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