Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cg3.c
Go to the documentation of this file.
1 /* cg3.c: CGTHREE frame buffer driver
2  *
3  * Copyright (C) 2003, 2006 David S. Miller ([email protected])
4  * Copyright (C) 1996,1998 Jakub Jelinek ([email protected])
5  * Copyright (C) 1996 Miguel de Icaza ([email protected])
6  * Copyright (C) 1997 Eddie C. Dost ([email protected])
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/delay.h>
16 #include <linux/init.h>
17 #include <linux/fb.h>
18 #include <linux/mm.h>
19 #include <linux/of_device.h>
20 
21 #include <asm/io.h>
22 #include <asm/fbio.h>
23 
24 #include "sbuslib.h"
25 
26 /*
27  * Local functions.
28  */
29 
30 static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
31  unsigned, struct fb_info *);
32 static int cg3_blank(int, struct fb_info *);
33 
34 static int cg3_mmap(struct fb_info *, struct vm_area_struct *);
35 static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long);
36 
37 /*
38  * Frame buffer operations
39  */
40 
41 static 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,
50 #ifdef CONFIG_COMPAT
51  .fb_compat_ioctl = sbusfb_compat_ioctl,
52 #endif
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 
74 enum cg3_type {
78 };
79 
80 struct bt_regs {
81  u32 addr;
82  u32 color_map;
83  u32 control;
84  u32 cursor;
85 };
86 
87 struct cg3_regs {
88  struct bt_regs cmap;
105 };
106 
107 /* Offset of interesting structures in the OBIO space */
108 #define CG3_REGS_OFFSET 0x400000UL
109 #define CG3_RAM_OFFSET 0x800000UL
110 
111 struct cg3_par {
114  u32 sw_cmap[((256 * 3) + 3) / 4];
115 
117 #define CG3_FLAG_BLANKED 0x00000001
118 #define CG3_FLAG_RDI 0x00000002
119 
120  unsigned long which_io;
121 };
122 
137 static 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 
184 static int cg3_blank(int blank, struct fb_info *info)
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);
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);
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 
217 static 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 
226 static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
227 {
228  struct cg3_par *par = (struct cg3_par *)info->par;
229 
230  return sbusfb_mmap_helper(cg3_mmap_map,
231  info->fix.smem_start, info->fix.smem_len,
232  par->which_io,
233  vma);
234 }
235 
236 static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
237 {
238  return sbusfb_ioctl_helper(cmd, arg, info,
239  FBTYPE_SUN3COLOR, 8, info->fix.smem_len);
240 }
241 
242 /*
243  * Initialisation
244  */
245 
246 static void __devinit cg3_init_fix(struct fb_info *info, int linebytes,
247  struct device_node *dp)
248 {
249  strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
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 
259 static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
260  struct device_node *dp)
261 {
262  const char *params;
263  char *p;
264  int ww, hh;
265 
266  params = of_get_property(dp, "params", NULL);
267  if (params) {
268  ww = simple_strtoul(params, &p, 10);
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 
282 static u8 cg3regvals_66hz[] __devinitdata = { /* 1152 x 900, 66 Hz */
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 
289 static u8 cg3regvals_76hz[] __devinitdata = { /* 1152 x 900, 76 Hz */
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 
296 static u8 cg3regvals_rdi[] __devinitdata = { /* 640 x 480, cgRDI */
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 
303 static u8 *cg3_regvals[] __devinitdata = {
304  cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
305 };
306 
307 static u_char cg3_dacvals[] __devinitdata = {
308  4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
309 };
310 
311 static int __devinit cg3_do_default_mode(struct cg3_par *par)
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 {
328  printk(KERN_ERR "cgthree: can't handle SR %02x\n",
329  status);
330  return -EINVAL;
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) {
339  u8 __iomem *regp;
340 
341  regp = (u8 __iomem *)&par->regs->cmap.addr;
342  sbus_writeb(p[0], regp);
343  regp = (u8 __iomem *)&par->regs->cmap.control;
344  sbus_writeb(p[1], regp);
345  }
346  return 0;
347 }
348 
349 static int __devinit cg3_probe(struct platform_device *op)
350 {
351  struct device_node *dp = op->dev.of_node;
352  struct fb_info *info;
353  struct cg3_par *par;
354  int linebytes, err;
355 
356  info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev);
357 
358  err = -ENOMEM;
359  if (!info)
360  goto out_err;
361  par = info->par;
362 
363  spin_lock_init(&par->lock);
364 
365  info->fix.smem_start = op->resource[0].start;
366  par->which_io = op->resource[0].flags & IORESOURCE_BITS;
367 
368  sbusfb_fill_var(&info->var, dp, 8);
369  info->var.red.length = 8;
370  info->var.green.length = 8;
371  info->var.blue.length = 8;
372  if (!strcmp(dp->name, "cgRDI"))
373  par->flags |= CG3_FLAG_RDI;
374  if (par->flags & CG3_FLAG_RDI)
375  cg3_rdi_maybe_fixup_var(&info->var, dp);
376 
377  linebytes = of_getintprop_default(dp, "linebytes",
378  info->var.xres);
379  info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
380 
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;
385 
386  info->flags = FBINFO_DEFAULT;
387  info->fbops = &cg3_ops;
389  info->fix.smem_len, "cg3 ram");
390  if (!info->screen_base)
391  goto out_unmap_regs;
392 
393  cg3_blank(FB_BLANK_UNBLANK, info);
394 
395  if (!of_find_property(dp, "width", NULL)) {
396  err = cg3_do_default_mode(par);
397  if (err)
398  goto out_unmap_screen;
399  }
400 
401  err = fb_alloc_cmap(&info->cmap, 256, 0);
402  if (err)
403  goto out_unmap_screen;
404 
405  fb_set_cmap(&info->cmap, info);
406 
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);
414 
415  printk(KERN_INFO "%s: cg3 at %lx:%lx\n",
416  dp->full_name, par->which_io, info->fix.smem_start);
417 
418  return 0;
419 
420 out_dealloc_cmap:
421  fb_dealloc_cmap(&info->cmap);
422 
423 out_unmap_screen:
424  of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
425 
426 out_unmap_regs:
427  of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
428 
429 out_release_fb:
430  framebuffer_release(info);
431 
432 out_err:
433  return err;
434 }
435 
436 static int __devexit cg3_remove(struct platform_device *op)
437 {
438  struct fb_info *info = dev_get_drvdata(&op->dev);
439  struct cg3_par *par = info->par;
440 
442  fb_dealloc_cmap(&info->cmap);
443 
444  of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
445  of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
446 
447  framebuffer_release(info);
448 
449  dev_set_drvdata(&op->dev, NULL);
450 
451  return 0;
452 }
453 
454 static const struct of_device_id cg3_match[] = {
455  {
456  .name = "cgthree",
457  },
458  {
459  .name = "cgRDI",
460  },
461  {},
462 };
463 MODULE_DEVICE_TABLE(of, cg3_match);
464 
465 static struct platform_driver cg3_driver = {
466  .driver = {
467  .name = "cg3",
468  .owner = THIS_MODULE,
469  .of_match_table = cg3_match,
470  },
471  .probe = cg3_probe,
472  .remove = __devexit_p(cg3_remove),
473 };
474 
475 static int __init cg3_init(void)
476 {
477  if (fb_get_options("cg3fb", NULL))
478  return -ENODEV;
479 
480  return platform_driver_register(&cg3_driver);
481 }
482 
483 static void __exit cg3_exit(void)
484 {
485  platform_driver_unregister(&cg3_driver);
486 }
487 
488 module_init(cg3_init);
489 module_exit(cg3_exit);
490 
491 MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
492 MODULE_AUTHOR("David S. Miller <[email protected]>");
493 MODULE_VERSION("2.0");
494 MODULE_LICENSE("GPL");