mfd: move drivers/i2c/chips/menelaus.c to drivers/mfd
[linux-2.6-block.git] / drivers / video / cg3.c
CommitLineData
1da177e4
LT
1/* cg3.c: CGTHREE frame buffer driver
2 *
50312ce9 3 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
1da177e4
LT
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)
7 *
8 * Driver layout based loosely on tgafb.c, see that file for credits.
9 */
10
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>
18#include <linux/fb.h>
19#include <linux/mm.h>
6cd5a86b 20#include <linux/of_device.h>
1da177e4
LT
21
22#include <asm/io.h>
1da177e4
LT
23#include <asm/fbio.h>
24
25#include "sbuslib.h"
26
27/*
28 * Local functions.
29 */
30
31static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
32 unsigned, struct fb_info *);
33static int cg3_blank(int, struct fb_info *);
34
216d526c 35static int cg3_mmap(struct fb_info *, struct vm_area_struct *);
67a6680d 36static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long);
1da177e4
LT
37
38/*
39 * Frame buffer operations
40 */
41
42static struct fb_ops cg3_ops = {
43 .owner = THIS_MODULE,
44 .fb_setcolreg = cg3_setcolreg,
45 .fb_blank = cg3_blank,
46 .fb_fillrect = cfb_fillrect,
47 .fb_copyarea = cfb_copyarea,
48 .fb_imageblit = cfb_imageblit,
49 .fb_mmap = cg3_mmap,
50 .fb_ioctl = cg3_ioctl,
9ffb83bc
CH
51#ifdef CONFIG_COMPAT
52 .fb_compat_ioctl = sbusfb_compat_ioctl,
53#endif
1da177e4
LT
54};
55
56
57/* Control Register Constants */
58#define CG3_CR_ENABLE_INTS 0x80
59#define CG3_CR_ENABLE_VIDEO 0x40
60#define CG3_CR_ENABLE_TIMING 0x20
61#define CG3_CR_ENABLE_CURCMP 0x10
62#define CG3_CR_XTAL_MASK 0x0c
63#define CG3_CR_DIVISOR_MASK 0x03
64
65/* Status Register Constants */
66#define CG3_SR_PENDING_INT 0x80
67#define CG3_SR_RES_MASK 0x70
68#define CG3_SR_1152_900_76_A 0x40
69#define CG3_SR_1152_900_76_B 0x60
70#define CG3_SR_ID_MASK 0x0f
71#define CG3_SR_ID_COLOR 0x01
72#define CG3_SR_ID_MONO 0x02
73#define CG3_SR_ID_MONO_ECL 0x03
74
75enum cg3_type {
76 CG3_AT_66HZ = 0,
77 CG3_AT_76HZ,
78 CG3_RDI
79};
80
81struct bt_regs {
50312ce9
DM
82 u32 addr;
83 u32 color_map;
84 u32 control;
85 u32 cursor;
1da177e4
LT
86};
87
88struct cg3_regs {
89 struct bt_regs cmap;
50312ce9
DM
90 u8 control;
91 u8 status;
92 u8 cursor_start;
93 u8 cursor_end;
94 u8 h_blank_start;
95 u8 h_blank_end;
96 u8 h_sync_start;
97 u8 h_sync_end;
98 u8 comp_sync_end;
99 u8 v_blank_start_high;
100 u8 v_blank_start_low;
101 u8 v_blank_end;
102 u8 v_sync_start;
103 u8 v_sync_end;
104 u8 xfer_holdoff_start;
105 u8 xfer_holdoff_end;
1da177e4
LT
106};
107
108/* Offset of interesting structures in the OBIO space */
109#define CG3_REGS_OFFSET 0x400000UL
110#define CG3_RAM_OFFSET 0x800000UL
111
112struct cg3_par {
113 spinlock_t lock;
114 struct cg3_regs __iomem *regs;
115 u32 sw_cmap[((256 * 3) + 3) / 4];
116
117 u32 flags;
118#define CG3_FLAG_BLANKED 0x00000001
119#define CG3_FLAG_RDI 0x00000002
120
121 unsigned long physbase;
50312ce9 122 unsigned long which_io;
1da177e4 123 unsigned long fbsize;
1da177e4
LT
124};
125
126/**
127 * cg3_setcolreg - Optional function. Sets a color register.
128 * @regno: boolean, 0 copy local, 1 get_user() function
129 * @red: frame buffer colormap structure
130 * @green: The green value which can be up to 16 bits wide
131 * @blue: The blue value which can be up to 16 bits wide.
132 * @transp: If supported the alpha value which can be up to 16 bits wide.
133 * @info: frame buffer info structure
134 *
135 * The cg3 palette is loaded with 4 color values at each time
136 * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
137 * We keep a sw copy of the hw cmap to assist us in this esoteric
138 * loading procedure.
139 */
140static int cg3_setcolreg(unsigned regno,
141 unsigned red, unsigned green, unsigned blue,
142 unsigned transp, struct fb_info *info)
143{
144 struct cg3_par *par = (struct cg3_par *) info->par;
145 struct bt_regs __iomem *bt = &par->regs->cmap;
146 unsigned long flags;
147 u32 *p32;
148 u8 *p8;
149 int count;
150
151 if (regno >= 256)
152 return 1;
153
154 red >>= 8;
155 green >>= 8;
156 blue >>= 8;
157
158 spin_lock_irqsave(&par->lock, flags);
159
160 p8 = (u8 *)par->sw_cmap + (regno * 3);
161 p8[0] = red;
162 p8[1] = green;
163 p8[2] = blue;
164
165#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
166#define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
167
168 count = 3;
169 p32 = &par->sw_cmap[D4M3(regno)];
170 sbus_writel(D4M4(regno), &bt->addr);
171 while (count--)
172 sbus_writel(*p32++, &bt->color_map);
173
174#undef D4M3
175#undef D4M4
176
177 spin_unlock_irqrestore(&par->lock, flags);
178
179 return 0;
180}
181
182/**
183 * cg3_blank - Optional function. Blanks the display.
184 * @blank_mode: the blank mode we want.
185 * @info: frame buffer structure that represents a single frame buffer
186 */
a7177514 187static int cg3_blank(int blank, struct fb_info *info)
1da177e4
LT
188{
189 struct cg3_par *par = (struct cg3_par *) info->par;
190 struct cg3_regs __iomem *regs = par->regs;
191 unsigned long flags;
192 u8 val;
193
194 spin_lock_irqsave(&par->lock, flags);
195
196 switch (blank) {
197 case FB_BLANK_UNBLANK: /* Unblanking */
198 val = sbus_readb(&regs->control);
199 val |= CG3_CR_ENABLE_VIDEO;
200 sbus_writeb(val, &regs->control);
201 par->flags &= ~CG3_FLAG_BLANKED;
202 break;
203
204 case FB_BLANK_NORMAL: /* Normal blanking */
205 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
206 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
207 case FB_BLANK_POWERDOWN: /* Poweroff */
208 val = sbus_readb(&regs->control);
209 val &= ~CG3_CR_ENABLE_VIDEO;
210 sbus_writeb(val, &regs->control);
211 par->flags |= CG3_FLAG_BLANKED;
212 break;
213 }
214
215 spin_unlock_irqrestore(&par->lock, flags);
216
217 return 0;
218}
219
220static struct sbus_mmap_map cg3_mmap_map[] = {
221 {
222 .voff = CG3_MMAP_OFFSET,
223 .poff = CG3_RAM_OFFSET,
224 .size = SBUS_MMAP_FBSIZE(1)
225 },
226 { .size = 0 }
227};
228
216d526c 229static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
1da177e4
LT
230{
231 struct cg3_par *par = (struct cg3_par *)info->par;
232
233 return sbusfb_mmap_helper(cg3_mmap_map,
234 par->physbase, par->fbsize,
50312ce9 235 par->which_io,
1da177e4
LT
236 vma);
237}
238
67a6680d 239static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
1da177e4
LT
240{
241 struct cg3_par *par = (struct cg3_par *) info->par;
242
243 return sbusfb_ioctl_helper(cmd, arg, info,
244 FBTYPE_SUN3COLOR, 8, par->fbsize);
245}
246
247/*
248 * Initialisation
249 */
250
a7177514
RR
251static void __devinit cg3_init_fix(struct fb_info *info, int linebytes,
252 struct device_node *dp)
1da177e4 253{
50312ce9 254 strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
1da177e4
LT
255
256 info->fix.type = FB_TYPE_PACKED_PIXELS;
257 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
258
259 info->fix.line_length = linebytes;
260
261 info->fix.accel = FB_ACCEL_SUN_CGTHREE;
262}
263
a7177514
RR
264static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
265 struct device_node *dp)
1da177e4 266{
ccf0dec6 267 const char *params;
1da177e4
LT
268 char *p;
269 int ww, hh;
270
50312ce9
DM
271 params = of_get_property(dp, "params", NULL);
272 if (params) {
273 ww = simple_strtoul(params, &p, 10);
1da177e4
LT
274 if (ww && *p == 'x') {
275 hh = simple_strtoul(p + 1, &p, 10);
276 if (hh && *p == '-') {
277 if (var->xres != ww ||
278 var->yres != hh) {
279 var->xres = var->xres_virtual = ww;
280 var->yres = var->yres_virtual = hh;
281 }
282 }
283 }
284 }
285}
286
a7177514 287static u8 cg3regvals_66hz[] __devinitdata = { /* 1152 x 900, 66 Hz */
1da177e4
LT
288 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
289 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
290 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
291 0x10, 0x20, 0
292};
293
a7177514 294static u8 cg3regvals_76hz[] __devinitdata = { /* 1152 x 900, 76 Hz */
1da177e4
LT
295 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
296 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
297 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
298 0x10, 0x24, 0
299};
300
a7177514 301static u8 cg3regvals_rdi[] __devinitdata = { /* 640 x 480, cgRDI */
1da177e4
LT
302 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
303 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
304 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
305 0x10, 0x22, 0
306};
307
a7177514 308static u8 *cg3_regvals[] __devinitdata = {
1da177e4
LT
309 cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
310};
311
a7177514 312static u_char cg3_dacvals[] __devinitdata = {
1da177e4
LT
313 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
314};
315
6c8f5b90 316static int __devinit cg3_do_default_mode(struct cg3_par *par)
1da177e4
LT
317{
318 enum cg3_type type;
319 u8 *p;
320
321 if (par->flags & CG3_FLAG_RDI)
322 type = CG3_RDI;
323 else {
324 u8 status = sbus_readb(&par->regs->status), mon;
325 if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
326 mon = status & CG3_SR_RES_MASK;
327 if (mon == CG3_SR_1152_900_76_A ||
328 mon == CG3_SR_1152_900_76_B)
329 type = CG3_AT_76HZ;
330 else
331 type = CG3_AT_66HZ;
332 } else {
6c8f5b90
DM
333 printk(KERN_ERR "cgthree: can't handle SR %02x\n",
334 status);
335 return -EINVAL;
1da177e4
LT
336 }
337 }
338
339 for (p = cg3_regvals[type]; *p; p += 2) {
340 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
341 sbus_writeb(p[1], regp);
342 }
343 for (p = cg3_dacvals; *p; p += 2) {
50312ce9 344 u8 __iomem *regp;
1da177e4 345
50312ce9 346 regp = (u8 __iomem *)&par->regs->cmap.addr;
1da177e4 347 sbus_writeb(p[0], regp);
50312ce9 348 regp = (u8 __iomem *)&par->regs->cmap.control;
1da177e4
LT
349 sbus_writeb(p[1], regp);
350 }
6c8f5b90 351 return 0;
1da177e4
LT
352}
353
c7f439b9
DM
354static int __devinit cg3_probe(struct of_device *op,
355 const struct of_device_id *match)
1da177e4 356{
50312ce9 357 struct device_node *dp = op->node;
c7f439b9
DM
358 struct fb_info *info;
359 struct cg3_par *par;
50312ce9 360 int linebytes, err;
1da177e4 361
c7f439b9 362 info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev);
1da177e4 363
c7f439b9
DM
364 err = -ENOMEM;
365 if (!info)
366 goto out_err;
367 par = info->par;
1da177e4 368
c7f439b9 369 spin_lock_init(&par->lock);
1da177e4 370
c7f439b9
DM
371 par->physbase = op->resource[0].start;
372 par->which_io = op->resource[0].flags & IORESOURCE_BITS;
373
6cd5a86b 374 sbusfb_fill_var(&info->var, dp, 8);
c7f439b9
DM
375 info->var.red.length = 8;
376 info->var.green.length = 8;
377 info->var.blue.length = 8;
50312ce9 378 if (!strcmp(dp->name, "cgRDI"))
c7f439b9
DM
379 par->flags |= CG3_FLAG_RDI;
380 if (par->flags & CG3_FLAG_RDI)
381 cg3_rdi_maybe_fixup_var(&info->var, dp);
1da177e4 382
50312ce9 383 linebytes = of_getintprop_default(dp, "linebytes",
c7f439b9
DM
384 info->var.xres);
385 par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
1da177e4 386
c7f439b9
DM
387 par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
388 sizeof(struct cg3_regs), "cg3 regs");
389 if (!par->regs)
390 goto out_release_fb;
1da177e4 391
c7f439b9
DM
392 info->flags = FBINFO_DEFAULT;
393 info->fbops = &cg3_ops;
394 info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
395 par->fbsize, "cg3 ram");
396 if (!info->screen_base)
397 goto out_unmap_regs;
1da177e4 398
59f7137a 399 cg3_blank(FB_BLANK_UNBLANK, info);
1da177e4 400
6c8f5b90
DM
401 if (!of_find_property(dp, "width", NULL)) {
402 err = cg3_do_default_mode(par);
403 if (err)
404 goto out_unmap_screen;
405 }
c7f439b9
DM
406
407 if (fb_alloc_cmap(&info->cmap, 256, 0))
408 goto out_unmap_screen;
409
410 fb_set_cmap(&info->cmap, info);
1da177e4 411
c7f439b9
DM
412 cg3_init_fix(info, linebytes, dp);
413
414 err = register_framebuffer(info);
415 if (err < 0)
416 goto out_dealloc_cmap;
417
418 dev_set_drvdata(&op->dev, info);
50312ce9 419
194f1a68 420 printk(KERN_INFO "%s: cg3 at %lx:%lx\n",
c7f439b9 421 dp->full_name, par->which_io, par->physbase);
1da177e4 422
50312ce9 423 return 0;
1da177e4 424
c7f439b9
DM
425out_dealloc_cmap:
426 fb_dealloc_cmap(&info->cmap);
427
428out_unmap_screen:
429 of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
430
431out_unmap_regs:
432 of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
433
434out_release_fb:
435 framebuffer_release(info);
1da177e4 436
c7f439b9
DM
437out_err:
438 return err;
50312ce9 439}
1da177e4 440
e3a411a3 441static int __devexit cg3_remove(struct of_device *op)
50312ce9 442{
c7f439b9
DM
443 struct fb_info *info = dev_get_drvdata(&op->dev);
444 struct cg3_par *par = info->par;
50312ce9 445
c7f439b9
DM
446 unregister_framebuffer(info);
447 fb_dealloc_cmap(&info->cmap);
50312ce9 448
c7f439b9
DM
449 of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
450 of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
50312ce9 451
c7f439b9 452 framebuffer_release(info);
50312ce9 453
e3a411a3 454 dev_set_drvdata(&op->dev, NULL);
1da177e4
LT
455
456 return 0;
457}
458
fd098316 459static const struct of_device_id cg3_match[] = {
50312ce9
DM
460 {
461 .name = "cgthree",
462 },
463 {
464 .name = "cgRDI",
465 },
466 {},
467};
468MODULE_DEVICE_TABLE(of, cg3_match);
1da177e4 469
50312ce9
DM
470static struct of_platform_driver cg3_driver = {
471 .name = "cg3",
472 .match_table = cg3_match,
473 .probe = cg3_probe,
474 .remove = __devexit_p(cg3_remove),
475};
1da177e4 476
50312ce9
DM
477static int __init cg3_init(void)
478{
479 if (fb_get_options("cg3fb", NULL))
480 return -ENODEV;
481
482 return of_register_driver(&cg3_driver, &of_bus_type);
1da177e4
LT
483}
484
50312ce9 485static void __exit cg3_exit(void)
1da177e4 486{
50312ce9 487 of_unregister_driver(&cg3_driver);
1da177e4
LT
488}
489
490module_init(cg3_init);
1da177e4 491module_exit(cg3_exit);
1da177e4
LT
492
493MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
50312ce9
DM
494MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
495MODULE_VERSION("2.0");
1da177e4 496MODULE_LICENSE("GPL");