1 /* cg3.c: CGTHREE frame buffer driver
3 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
4 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
8 * Driver layout based loosely on tgafb.c, see that file for credits.
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/errno.h>
14 #include <linux/string.h>
15 #include <linux/slab.h>
16 #include <linux/delay.h>
17 #include <linux/init.h>
22 #include <asm/oplib.h>
24 #include <asm/of_device.h>
33 static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
34 unsigned, struct fb_info *);
35 static int cg3_blank(int, struct fb_info *);
37 static int cg3_mmap(struct fb_info *, struct vm_area_struct *);
38 static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long);
41 * Frame buffer operations
44 static struct fb_ops cg3_ops = {
46 .fb_setcolreg = cg3_setcolreg,
47 .fb_blank = cg3_blank,
48 .fb_fillrect = cfb_fillrect,
49 .fb_copyarea = cfb_copyarea,
50 .fb_imageblit = cfb_imageblit,
52 .fb_ioctl = cg3_ioctl,
54 .fb_compat_ioctl = sbusfb_compat_ioctl,
59 /* Control Register Constants */
60 #define CG3_CR_ENABLE_INTS 0x80
61 #define CG3_CR_ENABLE_VIDEO 0x40
62 #define CG3_CR_ENABLE_TIMING 0x20
63 #define CG3_CR_ENABLE_CURCMP 0x10
64 #define CG3_CR_XTAL_MASK 0x0c
65 #define CG3_CR_DIVISOR_MASK 0x03
67 /* Status Register Constants */
68 #define CG3_SR_PENDING_INT 0x80
69 #define CG3_SR_RES_MASK 0x70
70 #define CG3_SR_1152_900_76_A 0x40
71 #define CG3_SR_1152_900_76_B 0x60
72 #define CG3_SR_ID_MASK 0x0f
73 #define CG3_SR_ID_COLOR 0x01
74 #define CG3_SR_ID_MONO 0x02
75 #define CG3_SR_ID_MONO_ECL 0x03
101 u8 v_blank_start_high;
102 u8 v_blank_start_low;
106 u8 xfer_holdoff_start;
110 /* Offset of interesting structures in the OBIO space */
111 #define CG3_REGS_OFFSET 0x400000UL
112 #define CG3_RAM_OFFSET 0x800000UL
116 struct cg3_regs __iomem *regs;
117 u32 sw_cmap[((256 * 3) + 3) / 4];
120 #define CG3_FLAG_BLANKED 0x00000001
121 #define CG3_FLAG_RDI 0x00000002
123 unsigned long physbase;
124 unsigned long which_io;
125 unsigned long fbsize;
129 * cg3_setcolreg - Optional function. Sets a color register.
130 * @regno: boolean, 0 copy local, 1 get_user() function
131 * @red: frame buffer colormap structure
132 * @green: The green value which can be up to 16 bits wide
133 * @blue: The blue value which can be up to 16 bits wide.
134 * @transp: If supported the alpha value which can be up to 16 bits wide.
135 * @info: frame buffer info structure
137 * The cg3 palette is loaded with 4 color values at each time
138 * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
139 * We keep a sw copy of the hw cmap to assist us in this esoteric
142 static int cg3_setcolreg(unsigned regno,
143 unsigned red, unsigned green, unsigned blue,
144 unsigned transp, struct fb_info *info)
146 struct cg3_par *par = (struct cg3_par *) info->par;
147 struct bt_regs __iomem *bt = &par->regs->cmap;
160 spin_lock_irqsave(&par->lock, flags);
162 p8 = (u8 *)par->sw_cmap + (regno * 3);
167 #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
168 #define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
171 p32 = &par->sw_cmap[D4M3(regno)];
172 sbus_writel(D4M4(regno), &bt->addr);
174 sbus_writel(*p32++, &bt->color_map);
179 spin_unlock_irqrestore(&par->lock, flags);
185 * cg3_blank - Optional function. Blanks the display.
186 * @blank_mode: the blank mode we want.
187 * @info: frame buffer structure that represents a single frame buffer
190 cg3_blank(int blank, struct fb_info *info)
192 struct cg3_par *par = (struct cg3_par *) info->par;
193 struct cg3_regs __iomem *regs = par->regs;
197 spin_lock_irqsave(&par->lock, flags);
200 case FB_BLANK_UNBLANK: /* Unblanking */
201 val = sbus_readb(®s->control);
202 val |= CG3_CR_ENABLE_VIDEO;
203 sbus_writeb(val, ®s->control);
204 par->flags &= ~CG3_FLAG_BLANKED;
207 case FB_BLANK_NORMAL: /* Normal blanking */
208 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
209 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
210 case FB_BLANK_POWERDOWN: /* Poweroff */
211 val = sbus_readb(®s->control);
212 val &= ~CG3_CR_ENABLE_VIDEO;
213 sbus_writeb(val, ®s->control);
214 par->flags |= CG3_FLAG_BLANKED;
218 spin_unlock_irqrestore(&par->lock, flags);
223 static struct sbus_mmap_map cg3_mmap_map[] = {
225 .voff = CG3_MMAP_OFFSET,
226 .poff = CG3_RAM_OFFSET,
227 .size = SBUS_MMAP_FBSIZE(1)
232 static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
234 struct cg3_par *par = (struct cg3_par *)info->par;
236 return sbusfb_mmap_helper(cg3_mmap_map,
237 par->physbase, par->fbsize,
242 static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
244 struct cg3_par *par = (struct cg3_par *) info->par;
246 return sbusfb_ioctl_helper(cmd, arg, info,
247 FBTYPE_SUN3COLOR, 8, par->fbsize);
255 cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
257 strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
259 info->fix.type = FB_TYPE_PACKED_PIXELS;
260 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
262 info->fix.line_length = linebytes;
264 info->fix.accel = FB_ACCEL_SUN_CGTHREE;
267 static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
268 struct device_node *dp)
274 params = of_get_property(dp, "params", NULL);
276 ww = simple_strtoul(params, &p, 10);
277 if (ww && *p == 'x') {
278 hh = simple_strtoul(p + 1, &p, 10);
279 if (hh && *p == '-') {
280 if (var->xres != ww ||
282 var->xres = var->xres_virtual = ww;
283 var->yres = var->yres_virtual = hh;
290 static u8 cg3regvals_66hz[] __initdata = { /* 1152 x 900, 66 Hz */
291 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
292 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
293 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
297 static u8 cg3regvals_76hz[] __initdata = { /* 1152 x 900, 76 Hz */
298 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
299 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
300 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
304 static u8 cg3regvals_rdi[] __initdata = { /* 640 x 480, cgRDI */
305 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
306 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
307 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
311 static u8 *cg3_regvals[] __initdata = {
312 cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
315 static u_char cg3_dacvals[] __initdata = {
316 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
319 static void cg3_do_default_mode(struct cg3_par *par)
324 if (par->flags & CG3_FLAG_RDI)
327 u8 status = sbus_readb(&par->regs->status), mon;
328 if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
329 mon = status & CG3_SR_RES_MASK;
330 if (mon == CG3_SR_1152_900_76_A ||
331 mon == CG3_SR_1152_900_76_B)
336 prom_printf("cgthree: can't handle SR %02x\n",
343 for (p = cg3_regvals[type]; *p; p += 2) {
344 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
345 sbus_writeb(p[1], regp);
347 for (p = cg3_dacvals; *p; p += 2) {
350 regp = (u8 __iomem *)&par->regs->cmap.addr;
351 sbus_writeb(p[0], regp);
352 regp = (u8 __iomem *)&par->regs->cmap.control;
353 sbus_writeb(p[1], regp);
362 static int __devinit cg3_init_one(struct of_device *op)
364 struct device_node *dp = op->node;
365 struct all_info *all;
368 all = kzalloc(sizeof(*all), GFP_KERNEL);
372 spin_lock_init(&all->par.lock);
374 all->par.physbase = op->resource[0].start;
375 all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
377 sbusfb_fill_var(&all->info.var, dp->node, 8);
378 all->info.var.red.length = 8;
379 all->info.var.green.length = 8;
380 all->info.var.blue.length = 8;
381 if (!strcmp(dp->name, "cgRDI"))
382 all->par.flags |= CG3_FLAG_RDI;
383 if (all->par.flags & CG3_FLAG_RDI)
384 cg3_rdi_maybe_fixup_var(&all->info.var, dp);
386 linebytes = of_getintprop_default(dp, "linebytes",
388 all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
390 all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
391 sizeof(struct cg3_regs), "cg3 regs");
393 all->info.flags = FBINFO_DEFAULT;
394 all->info.fbops = &cg3_ops;
395 all->info.screen_base =
396 of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
397 all->par.fbsize, "cg3 ram");
398 all->info.par = &all->par;
400 cg3_blank(0, &all->info);
402 if (!of_find_property(dp, "width", NULL))
403 cg3_do_default_mode(&all->par);
405 if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
406 of_iounmap(&op->resource[0],
407 all->par.regs, sizeof(struct cg3_regs));
408 of_iounmap(&op->resource[0],
409 all->info.screen_base, all->par.fbsize);
413 fb_set_cmap(&all->info.cmap, &all->info);
415 cg3_init_fix(&all->info, linebytes, dp);
417 err = register_framebuffer(&all->info);
419 fb_dealloc_cmap(&all->info.cmap);
420 of_iounmap(&op->resource[0],
421 all->par.regs, sizeof(struct cg3_regs));
422 of_iounmap(&op->resource[0],
423 all->info.screen_base, all->par.fbsize);
428 dev_set_drvdata(&op->dev, all);
430 printk("%s: cg3 at %lx:%lx\n",
431 dp->full_name, all->par.which_io, all->par.physbase);
436 static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id *match)
438 struct of_device *op = to_of_device(&dev->dev);
440 return cg3_init_one(op);
443 static int __devexit cg3_remove(struct of_device *op)
445 struct all_info *all = dev_get_drvdata(&op->dev);
447 unregister_framebuffer(&all->info);
448 fb_dealloc_cmap(&all->info.cmap);
450 of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs));
451 of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
455 dev_set_drvdata(&op->dev, NULL);
460 static struct of_device_id cg3_match[] = {
469 MODULE_DEVICE_TABLE(of, cg3_match);
471 static struct of_platform_driver cg3_driver = {
473 .match_table = cg3_match,
475 .remove = __devexit_p(cg3_remove),
478 static int __init cg3_init(void)
480 if (fb_get_options("cg3fb", NULL))
483 return of_register_driver(&cg3_driver, &of_bus_type);
486 static void __exit cg3_exit(void)
488 of_unregister_driver(&cg3_driver);
491 module_init(cg3_init);
492 module_exit(cg3_exit);
494 MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
495 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
496 MODULE_VERSION("2.0");
497 MODULE_LICENSE("GPL");