0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/errno.h>
0014 #include <linux/string.h>
0015 #include <linux/delay.h>
0016 #include <linux/init.h>
0017 #include <linux/fb.h>
0018 #include <linux/mm.h>
0019 #include <linux/uaccess.h>
0020 #include <linux/of_device.h>
0021
0022 #include <asm/io.h>
0023 #include <asm/fbio.h>
0024
0025 #include "sbuslib.h"
0026
0027
0028
0029
0030
0031 static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned,
0032 unsigned, struct fb_info *);
0033
0034 static int cg14_mmap(struct fb_info *, struct vm_area_struct *);
0035 static int cg14_ioctl(struct fb_info *, unsigned int, unsigned long);
0036 static int cg14_pan_display(struct fb_var_screeninfo *, struct fb_info *);
0037
0038
0039
0040
0041
0042 static const struct fb_ops cg14_ops = {
0043 .owner = THIS_MODULE,
0044 .fb_setcolreg = cg14_setcolreg,
0045 .fb_pan_display = cg14_pan_display,
0046 .fb_fillrect = cfb_fillrect,
0047 .fb_copyarea = cfb_copyarea,
0048 .fb_imageblit = cfb_imageblit,
0049 .fb_mmap = cg14_mmap,
0050 .fb_ioctl = cg14_ioctl,
0051 #ifdef CONFIG_COMPAT
0052 .fb_compat_ioctl = sbusfb_compat_ioctl,
0053 #endif
0054 };
0055
0056 #define CG14_MCR_INTENABLE_SHIFT 7
0057 #define CG14_MCR_INTENABLE_MASK 0x80
0058 #define CG14_MCR_VIDENABLE_SHIFT 6
0059 #define CG14_MCR_VIDENABLE_MASK 0x40
0060 #define CG14_MCR_PIXMODE_SHIFT 4
0061 #define CG14_MCR_PIXMODE_MASK 0x30
0062 #define CG14_MCR_TMR_SHIFT 2
0063 #define CG14_MCR_TMR_MASK 0x0c
0064 #define CG14_MCR_TMENABLE_SHIFT 1
0065 #define CG14_MCR_TMENABLE_MASK 0x02
0066 #define CG14_MCR_RESET_SHIFT 0
0067 #define CG14_MCR_RESET_MASK 0x01
0068 #define CG14_REV_REVISION_SHIFT 4
0069 #define CG14_REV_REVISION_MASK 0xf0
0070 #define CG14_REV_IMPL_SHIFT 0
0071 #define CG14_REV_IMPL_MASK 0x0f
0072 #define CG14_VBR_FRAMEBASE_SHIFT 12
0073 #define CG14_VBR_FRAMEBASE_MASK 0x00fff000
0074 #define CG14_VMCR1_SETUP_SHIFT 0
0075 #define CG14_VMCR1_SETUP_MASK 0x000001ff
0076 #define CG14_VMCR1_VCONFIG_SHIFT 9
0077 #define CG14_VMCR1_VCONFIG_MASK 0x00000e00
0078 #define CG14_VMCR2_REFRESH_SHIFT 0
0079 #define CG14_VMCR2_REFRESH_MASK 0x00000001
0080 #define CG14_VMCR2_TESTROWCNT_SHIFT 1
0081 #define CG14_VMCR2_TESTROWCNT_MASK 0x00000002
0082 #define CG14_VMCR2_FBCONFIG_SHIFT 2
0083 #define CG14_VMCR2_FBCONFIG_MASK 0x0000000c
0084 #define CG14_VCR_REFRESHREQ_SHIFT 0
0085 #define CG14_VCR_REFRESHREQ_MASK 0x000003ff
0086 #define CG14_VCR1_REFRESHENA_SHIFT 10
0087 #define CG14_VCR1_REFRESHENA_MASK 0x00000400
0088 #define CG14_VCA_CAD_SHIFT 0
0089 #define CG14_VCA_CAD_MASK 0x000003ff
0090 #define CG14_VCA_VERS_SHIFT 10
0091 #define CG14_VCA_VERS_MASK 0x00000c00
0092 #define CG14_VCA_RAMSPEED_SHIFT 12
0093 #define CG14_VCA_RAMSPEED_MASK 0x00001000
0094 #define CG14_VCA_8MB_SHIFT 13
0095 #define CG14_VCA_8MB_MASK 0x00002000
0096
0097 #define CG14_MCR_PIXMODE_8 0
0098 #define CG14_MCR_PIXMODE_16 2
0099 #define CG14_MCR_PIXMODE_32 3
0100
0101 struct cg14_regs{
0102 u8 mcr;
0103 u8 ppr;
0104 u8 tms[2];
0105 u8 msr;
0106 u8 fsr;
0107 u8 rev;
0108 u8 ccr;
0109 u32 tmr;
0110 u8 mod;
0111 u8 acr;
0112 u8 xxx0[6];
0113 u16 hct;
0114 u16 vct;
0115 u16 hbs;
0116 u16 hbc;
0117 u16 hss;
0118 u16 hsc;
0119 u16 csc;
0120 u16 vbs;
0121 u16 vbc;
0122 u16 vss;
0123 u16 vsc;
0124 u16 xcs;
0125 u16 xcc;
0126 u16 fsa;
0127 u16 adr;
0128 u8 xxx1[0xce];
0129 u8 pcg[0x100];
0130 u32 vbr;
0131 u32 vmcr;
0132 u32 vcr;
0133 u32 vca;
0134 };
0135
0136 #define CG14_CCR_ENABLE 0x04
0137 #define CG14_CCR_SELECT 0x02
0138
0139 struct cg14_cursor {
0140 u32 cpl0[32];
0141 u32 cpl1[32];
0142 u8 ccr;
0143 u8 xxx0[3];
0144 u16 cursx;
0145 u16 cursy;
0146 u32 color0;
0147 u32 color1;
0148 u32 xxx1[0x1bc];
0149 u32 cpl0i[32];
0150 u32 cpl1i[32];
0151 };
0152
0153 struct cg14_dac {
0154 u8 addr;
0155 u8 xxx0[255];
0156 u8 glut;
0157 u8 xxx1[255];
0158 u8 select;
0159 u8 xxx2[255];
0160 u8 mode;
0161 };
0162
0163 struct cg14_xlut{
0164 u8 x_xlut [256];
0165 u8 x_xlutd [256];
0166 u8 xxx0[0x600];
0167 u8 x_xlut_inc [256];
0168 u8 x_xlutd_inc [256];
0169 };
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181 struct cg14_clut {
0182 u32 c_clut [256];
0183 u32 c_clutd [256];
0184 u32 c_clut_inc [256];
0185 u32 c_clutd_inc [256];
0186 };
0187
0188 #define CG14_MMAP_ENTRIES 16
0189
0190 struct cg14_par {
0191 spinlock_t lock;
0192 struct cg14_regs __iomem *regs;
0193 struct cg14_clut __iomem *clut;
0194 struct cg14_cursor __iomem *cursor;
0195
0196 u32 flags;
0197 #define CG14_FLAG_BLANKED 0x00000001
0198
0199 unsigned long iospace;
0200
0201 struct sbus_mmap_map mmap_map[CG14_MMAP_ENTRIES];
0202
0203 int mode;
0204 int ramsize;
0205 };
0206
0207 static void __cg14_reset(struct cg14_par *par)
0208 {
0209 struct cg14_regs __iomem *regs = par->regs;
0210 u8 val;
0211
0212 val = sbus_readb(®s->mcr);
0213 val &= ~(CG14_MCR_PIXMODE_MASK);
0214 sbus_writeb(val, ®s->mcr);
0215 }
0216
0217 static int cg14_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
0218 {
0219 struct cg14_par *par = (struct cg14_par *) info->par;
0220 unsigned long flags;
0221
0222
0223
0224
0225 spin_lock_irqsave(&par->lock, flags);
0226 __cg14_reset(par);
0227 spin_unlock_irqrestore(&par->lock, flags);
0228
0229 if (var->xoffset || var->yoffset || var->vmode)
0230 return -EINVAL;
0231 return 0;
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 static int cg14_setcolreg(unsigned regno,
0244 unsigned red, unsigned green, unsigned blue,
0245 unsigned transp, struct fb_info *info)
0246 {
0247 struct cg14_par *par = (struct cg14_par *) info->par;
0248 struct cg14_clut __iomem *clut = par->clut;
0249 unsigned long flags;
0250 u32 val;
0251
0252 if (regno >= 256)
0253 return 1;
0254
0255 red >>= 8;
0256 green >>= 8;
0257 blue >>= 8;
0258 val = (red | (green << 8) | (blue << 16));
0259
0260 spin_lock_irqsave(&par->lock, flags);
0261 sbus_writel(val, &clut->c_clut[regno]);
0262 spin_unlock_irqrestore(&par->lock, flags);
0263
0264 return 0;
0265 }
0266
0267 static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma)
0268 {
0269 struct cg14_par *par = (struct cg14_par *) info->par;
0270
0271 return sbusfb_mmap_helper(par->mmap_map,
0272 info->fix.smem_start, info->fix.smem_len,
0273 par->iospace, vma);
0274 }
0275
0276 static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
0277 {
0278 struct cg14_par *par = (struct cg14_par *) info->par;
0279 struct cg14_regs __iomem *regs = par->regs;
0280 struct mdi_cfginfo kmdi, __user *mdii;
0281 unsigned long flags;
0282 int cur_mode, mode, ret = 0;
0283
0284 switch (cmd) {
0285 case MDI_RESET:
0286 spin_lock_irqsave(&par->lock, flags);
0287 __cg14_reset(par);
0288 spin_unlock_irqrestore(&par->lock, flags);
0289 break;
0290
0291 case MDI_GET_CFGINFO:
0292 memset(&kmdi, 0, sizeof(kmdi));
0293
0294 spin_lock_irqsave(&par->lock, flags);
0295 kmdi.mdi_type = FBTYPE_MDICOLOR;
0296 kmdi.mdi_height = info->var.yres;
0297 kmdi.mdi_width = info->var.xres;
0298 kmdi.mdi_mode = par->mode;
0299 kmdi.mdi_pixfreq = 72;
0300 kmdi.mdi_size = par->ramsize;
0301 spin_unlock_irqrestore(&par->lock, flags);
0302
0303 mdii = (struct mdi_cfginfo __user *) arg;
0304 if (copy_to_user(mdii, &kmdi, sizeof(kmdi)))
0305 ret = -EFAULT;
0306 break;
0307
0308 case MDI_SET_PIXELMODE:
0309 if (get_user(mode, (int __user *) arg)) {
0310 ret = -EFAULT;
0311 break;
0312 }
0313
0314 spin_lock_irqsave(&par->lock, flags);
0315 cur_mode = sbus_readb(®s->mcr);
0316 cur_mode &= ~CG14_MCR_PIXMODE_MASK;
0317 switch(mode) {
0318 case MDI_32_PIX:
0319 cur_mode |= (CG14_MCR_PIXMODE_32 <<
0320 CG14_MCR_PIXMODE_SHIFT);
0321 break;
0322
0323 case MDI_16_PIX:
0324 cur_mode |= (CG14_MCR_PIXMODE_16 <<
0325 CG14_MCR_PIXMODE_SHIFT);
0326 break;
0327
0328 case MDI_8_PIX:
0329 break;
0330
0331 default:
0332 ret = -ENOSYS;
0333 break;
0334 }
0335 if (!ret) {
0336 sbus_writeb(cur_mode, ®s->mcr);
0337 par->mode = mode;
0338 }
0339 spin_unlock_irqrestore(&par->lock, flags);
0340 break;
0341
0342 default:
0343 ret = sbusfb_ioctl_helper(cmd, arg, info,
0344 FBTYPE_MDICOLOR, 8,
0345 info->fix.smem_len);
0346 break;
0347 }
0348
0349 return ret;
0350 }
0351
0352
0353
0354
0355
0356 static void cg14_init_fix(struct fb_info *info, int linebytes,
0357 struct device_node *dp)
0358 {
0359 snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);
0360
0361 info->fix.type = FB_TYPE_PACKED_PIXELS;
0362 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
0363
0364 info->fix.line_length = linebytes;
0365
0366 info->fix.accel = FB_ACCEL_SUN_CG14;
0367 }
0368
0369 static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] = {
0370 {
0371 .voff = CG14_REGS,
0372 .poff = 0x80000000,
0373 .size = 0x1000
0374 },
0375 {
0376 .voff = CG14_XLUT,
0377 .poff = 0x80003000,
0378 .size = 0x1000
0379 },
0380 {
0381 .voff = CG14_CLUT1,
0382 .poff = 0x80004000,
0383 .size = 0x1000
0384 },
0385 {
0386 .voff = CG14_CLUT2,
0387 .poff = 0x80005000,
0388 .size = 0x1000
0389 },
0390 {
0391 .voff = CG14_CLUT3,
0392 .poff = 0x80006000,
0393 .size = 0x1000
0394 },
0395 {
0396 .voff = CG3_MMAP_OFFSET - 0x7000,
0397 .poff = 0x80000000,
0398 .size = 0x7000
0399 },
0400 {
0401 .voff = CG3_MMAP_OFFSET,
0402 .poff = 0x00000000,
0403 .size = SBUS_MMAP_FBSIZE(1)
0404 },
0405 {
0406 .voff = MDI_CURSOR_MAP,
0407 .poff = 0x80001000,
0408 .size = 0x1000
0409 },
0410 {
0411 .voff = MDI_CHUNKY_BGR_MAP,
0412 .poff = 0x01000000,
0413 .size = 0x400000
0414 },
0415 {
0416 .voff = MDI_PLANAR_X16_MAP,
0417 .poff = 0x02000000,
0418 .size = 0x200000
0419 },
0420 {
0421 .voff = MDI_PLANAR_C16_MAP,
0422 .poff = 0x02800000,
0423 .size = 0x200000
0424 },
0425 {
0426 .voff = MDI_PLANAR_X32_MAP,
0427 .poff = 0x03000000,
0428 .size = 0x100000
0429 },
0430 {
0431 .voff = MDI_PLANAR_B32_MAP,
0432 .poff = 0x03400000,
0433 .size = 0x100000
0434 },
0435 {
0436 .voff = MDI_PLANAR_G32_MAP,
0437 .poff = 0x03800000,
0438 .size = 0x100000
0439 },
0440 {
0441 .voff = MDI_PLANAR_R32_MAP,
0442 .poff = 0x03c00000,
0443 .size = 0x100000
0444 },
0445 { .size = 0 }
0446 };
0447
0448 static void cg14_unmap_regs(struct platform_device *op, struct fb_info *info,
0449 struct cg14_par *par)
0450 {
0451 if (par->regs)
0452 of_iounmap(&op->resource[0],
0453 par->regs, sizeof(struct cg14_regs));
0454 if (par->clut)
0455 of_iounmap(&op->resource[0],
0456 par->clut, sizeof(struct cg14_clut));
0457 if (par->cursor)
0458 of_iounmap(&op->resource[0],
0459 par->cursor, sizeof(struct cg14_cursor));
0460 if (info->screen_base)
0461 of_iounmap(&op->resource[1],
0462 info->screen_base, info->fix.smem_len);
0463 }
0464
0465 static int cg14_probe(struct platform_device *op)
0466 {
0467 struct device_node *dp = op->dev.of_node;
0468 struct fb_info *info;
0469 struct cg14_par *par;
0470 int is_8mb, linebytes, i, err;
0471
0472 info = framebuffer_alloc(sizeof(struct cg14_par), &op->dev);
0473
0474 err = -ENOMEM;
0475 if (!info)
0476 goto out_err;
0477 par = info->par;
0478
0479 spin_lock_init(&par->lock);
0480
0481 sbusfb_fill_var(&info->var, dp, 8);
0482 info->var.red.length = 8;
0483 info->var.green.length = 8;
0484 info->var.blue.length = 8;
0485
0486 linebytes = of_getintprop_default(dp, "linebytes",
0487 info->var.xres);
0488 info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
0489
0490 if (of_node_name_eq(dp->parent, "sbus") ||
0491 of_node_name_eq(dp->parent, "sbi")) {
0492 info->fix.smem_start = op->resource[0].start;
0493 par->iospace = op->resource[0].flags & IORESOURCE_BITS;
0494 } else {
0495 info->fix.smem_start = op->resource[1].start;
0496 par->iospace = op->resource[0].flags & IORESOURCE_BITS;
0497 }
0498
0499 par->regs = of_ioremap(&op->resource[0], 0,
0500 sizeof(struct cg14_regs), "cg14 regs");
0501 par->clut = of_ioremap(&op->resource[0], CG14_CLUT1,
0502 sizeof(struct cg14_clut), "cg14 clut");
0503 par->cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS,
0504 sizeof(struct cg14_cursor), "cg14 cursor");
0505
0506 info->screen_base = of_ioremap(&op->resource[1], 0,
0507 info->fix.smem_len, "cg14 ram");
0508
0509 if (!par->regs || !par->clut || !par->cursor || !info->screen_base)
0510 goto out_unmap_regs;
0511
0512 is_8mb = (resource_size(&op->resource[1]) == (8 * 1024 * 1024));
0513
0514 BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map));
0515
0516 memcpy(&par->mmap_map, &__cg14_mmap_map, sizeof(par->mmap_map));
0517
0518 for (i = 0; i < CG14_MMAP_ENTRIES; i++) {
0519 struct sbus_mmap_map *map = &par->mmap_map[i];
0520
0521 if (!map->size)
0522 break;
0523 if (map->poff & 0x80000000)
0524 map->poff = (map->poff & 0x7fffffff) +
0525 (op->resource[0].start -
0526 op->resource[1].start);
0527 if (is_8mb &&
0528 map->size >= 0x100000 &&
0529 map->size <= 0x400000)
0530 map->size *= 2;
0531 }
0532
0533 par->mode = MDI_8_PIX;
0534 par->ramsize = (is_8mb ? 0x800000 : 0x400000);
0535
0536 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
0537 info->fbops = &cg14_ops;
0538
0539 __cg14_reset(par);
0540
0541 if (fb_alloc_cmap(&info->cmap, 256, 0))
0542 goto out_unmap_regs;
0543
0544 fb_set_cmap(&info->cmap, info);
0545
0546 cg14_init_fix(info, linebytes, dp);
0547
0548 err = register_framebuffer(info);
0549 if (err < 0)
0550 goto out_dealloc_cmap;
0551
0552 dev_set_drvdata(&op->dev, info);
0553
0554 printk(KERN_INFO "%pOF: cgfourteen at %lx:%lx, %dMB\n",
0555 dp,
0556 par->iospace, info->fix.smem_start,
0557 par->ramsize >> 20);
0558
0559 return 0;
0560
0561 out_dealloc_cmap:
0562 fb_dealloc_cmap(&info->cmap);
0563
0564 out_unmap_regs:
0565 cg14_unmap_regs(op, info, par);
0566 framebuffer_release(info);
0567
0568 out_err:
0569 return err;
0570 }
0571
0572 static int cg14_remove(struct platform_device *op)
0573 {
0574 struct fb_info *info = dev_get_drvdata(&op->dev);
0575 struct cg14_par *par = info->par;
0576
0577 unregister_framebuffer(info);
0578 fb_dealloc_cmap(&info->cmap);
0579
0580 cg14_unmap_regs(op, info, par);
0581
0582 framebuffer_release(info);
0583
0584 return 0;
0585 }
0586
0587 static const struct of_device_id cg14_match[] = {
0588 {
0589 .name = "cgfourteen",
0590 },
0591 {},
0592 };
0593 MODULE_DEVICE_TABLE(of, cg14_match);
0594
0595 static struct platform_driver cg14_driver = {
0596 .driver = {
0597 .name = "cg14",
0598 .of_match_table = cg14_match,
0599 },
0600 .probe = cg14_probe,
0601 .remove = cg14_remove,
0602 };
0603
0604 static int __init cg14_init(void)
0605 {
0606 if (fb_get_options("cg14fb", NULL))
0607 return -ENODEV;
0608
0609 return platform_driver_register(&cg14_driver);
0610 }
0611
0612 static void __exit cg14_exit(void)
0613 {
0614 platform_driver_unregister(&cg14_driver);
0615 }
0616
0617 module_init(cg14_init);
0618 module_exit(cg14_exit);
0619
0620 MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets");
0621 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
0622 MODULE_VERSION("2.0");
0623 MODULE_LICENSE("GPL");