make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / video / rpxfb.c
1 /*
2  * drivers/video/rpxfb.c
3  *
4  * RPX LCD frame buffer driver for PowerPC MPC823 family.
5  *
6  * Maintained by: Paul Mundt <pmundt@mvista.com>
7  *
8  * Copyright (C) 2000, 2001 MontaVista Software, Inc.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 2 of the License, or (at your
13  * option) any later version.
14  */
15
16 #include <linux/config.h>
17 #include <linux/errno.h>
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/sched.h>
21 #include <linux/string.h>
22 #include <linux/module.h>
23 #include <linux/bootmem.h>
24 #include <asm/io.h>
25 #include <asm/irq.h>
26 #include <asm/8xx_immap.h>
27 #include <asm/mpc8xx.h>
28
29 #include <linux/fb.h>
30 #include <video/fbcon.h>
31 #include <video/fbcon-mfb.h>
32 #include <video/fbcon-cfb4.h>
33 #include <video/fbcon-cfb8.h>
34
35 #ifdef CONFIG_PM
36   #include <linux/pm.h>
37 #endif
38
39 /* LCD Controller Configuration Register. */
40 #define LCCR_BNUM       ((uint)0xfffe0000)
41 #define LCCR_EIEN       ((uint)0x00010000)
42 #define LCCR_IEN        ((uint)0x00008000)
43 #define LCCR_IRQL       ((uint)0x00007000)
44 #define LCCR_CLKP       ((uint)0x00000800)
45 #define LCCR_OEP        ((uint)0x00000400)
46 #define LCCR_HSP        ((uint)0x00000200)
47 #define LCCR_VSP        ((uint)0x00000100)
48 #define LCCR_DP         ((uint)0x00000080)
49 #define LCCR_BPIX       ((uint)0x00000060)
50 #define LCCR_LBW        ((uint)0x00000010)
51 #define LCCR_SPLT       ((uint)0x00000008)
52 #define LCCR_CLOR       ((uint)0x00000004)
53 #define LCCR_TFT        ((uint)0x00000002)
54 #define LCCR_PON        ((uint)0x00000001)
55
56 /* Define the bit shifts to load values into the register. */
57 #define LCDBIT(BIT, VAL)        ((VAL) << (31 - BIT))
58
59 #define LCCR_BNUM_BIT   ((uint)14)
60 #define LCCR_EIEN_BIT   ((uint)15)
61 #define LCCR_IEN_BIT    ((uint)16)
62 #define LCCR_IROL_BIT   ((uint)19)
63 #define LCCR_CLKP_BIT   ((uint)20)
64 #define LCCR_OEP_BIT    ((uint)21)
65 #define LCCR_HSP_BIT    ((uint)22)
66 #define LCCR_VSP_BIT    ((uint)23)
67 #define LCCR_DP_BIT     ((uint)24)
68 #define LCCR_BPIX_BIT   ((uint)26)
69 #define LCCR_LBW_BIT    ((uint)27)
70 #define LCCR_SPLT_BIT   ((uint)28)
71 #define LCCR_CLOR_BIT   ((uint)29)
72 #define LCCR_TFT_BIT    ((uint)30)
73 #define LCCR_PON_BIT    ((uint)31)
74
75 /* LCD Horizontal control register. */
76 #define LCHCR_BO        ((uint)0x01000000)
77 #define LCHCR_AT        ((uint)0x00e00000)
78 #define LCHCR_HPC       ((uint)0x001ffc00)
79 #define LCHCR_WBL       ((uint)0x000003ff)
80
81 #define LCHCR_AT_BIT    ((uint)10)
82 #define LCHCR_HPC_BIT   ((uint)21)
83 #define LCHCR_WBL_BIT   ((uint)31)
84
85 /* LCD Vertical control register. */
86 #define LCVCR_VPW       ((uint)0xf0000000)
87 #define LCVCR_LCD_AC    ((uint)0x01e00000)
88 #define LCVCR_VPC       ((uint)0x001ff800)
89 #define LCVCR_WBF       ((uint)0x000003ff)
90
91 #define LCVCR_VPW_BIT   ((uint)3)
92 #define LCVCR_LCD_AC_BIT ((uint)10)
93 #define LCVCR_VPC_BIT   ((uint)20)
94
95 /* Comm processor */
96 extern cpm8xx_t *cpmp;
97
98 #ifdef CONFIG_FB_RPX_DEBUG
99   #define rpxfb_debug(x...) printk(KERN_DEBUG "fb:" __FUNCTION__ ": " ##x)
100 #else
101   #define rpxfb_debug(x...)
102 #endif /* CONFIG_FB_RPX_DEBUG */
103
104 /*
105  * Information about displays we are using.  This is for configuring
106  * the LCD controller and memory allocation.  Someone has to know what
107  * is connected, as we can't autodetect anything.
108  */
109 #define CFG_HIGH        0       /* Pins are active high */
110 #define CFG_LOW         1       /* Pins are active low */
111
112 typedef struct vidinfo {
113     ushort      vl_col;         /* Number of columns (i.e. 640) */
114     ushort      vl_row;         /* Number of rows (i.e. 480) */
115     ushort      vl_width;       /* Width of display area in millimeters */
116     ushort      vl_height;      /* Height of display area in millimeters */
117     
118     /* LCD configuration register. */
119     u_char      vl_clkp;        /* Clock polarity */
120     u_char      vl_oep;         /* Output Enable polarity */
121     u_char      vl_hsp;         /* Horizontal Sync polarity */
122     u_char      vl_vsp;         /* Vertical Sync polarity */
123     u_char      vl_dp;          /* Data polarity */
124     u_char      vl_bpix;        /* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8 */
125     u_char      vl_lbw;         /* LCD Bus width, 0 = 4, 1 = 8 */
126     u_char      vl_splt;        /* Split display, 0 = dual, 1 = single */
127     u_char      vl_clor;        /* Color, 0 = mono, 1 = color */
128     u_char      vl_tft;         /* 0 = passive, 1 = TFT */
129
130     /* Horizontal control register. Timing from data sheet. */
131     ushort      vl_wbl;         /* Wait between lines */
132     
133     /* Vertical control register. */
134     u_char      vl_vpw;         /* Vertical sync pulse width */
135     u_char      vl_lcdac;       /* LCD AC timing */
136     u_char      vl_wbf;         /* Wait between frames */
137 } vidinfo_t;
138
139 #if defined(CONFIG_FB_RPX_LCD_NEC)
140 /*
141  * NEC NL6648AC33-18. Active, color, single scan.
142  * Over time, we could either configure exactly one of these at build
143  * time, or create an array of supported devices and find a way to
144  * tell this driver what we have (EEPROM perhaps?).
145  */
146 static vidinfo_t panel_info = {
147     640, 480, 132, 99, CFG_HIGH, CFG_HIGH, CFG_LOW, CFG_LOW, CFG_HIGH,
148     3, 0, 0, 1, 1, 144, 2, 0, 33
149 };
150 #elif defined(CONFIG_FB_RPX_LCD_SHARP)
151 /*
152  * Sharp 320x240. Active, color, single scan.  It isn't 16x9, and I am
153  * not sure what it is.......
154  */
155 static vidinfo_t panel_info = {
156     320, 240, 0, 0, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_HIGH, CFG_HIGH,
157     3, 0, 0, 1, 1, 15, 4, 0, 3
158 };
159 #else
160 #error "LCD type not defined"
161 #endif
162
163 #define NBITS(bit_code)         (1 << (bit_code))
164 #define NCOLORS(bit_code)       (1 << NBITS(bit_code))
165
166 static struct fb_info fb_info;
167 static struct display display;
168 static int currcon = 0;
169 static int inverse = 0;
170
171 #ifdef CONFIG_PM
172 /* Power management device */
173 static struct pm_dev *pm_dev;
174 #endif
175
176 /* Frame buffer memory information */
177 static unsigned long lcd_fb_base;
178 static unsigned long lcd_fb_size;
179 static unsigned long lcd_fb_line_length;
180
181 /* Desired mode */
182 static const char *mode_option __initdata = NULL;
183
184 /* 
185  * TODO: Add a modedb so the above actually works, instead of
186  * relying on hard coded values in the panel_info. This way
187  * we can add modes for our device (such as the Sharp and NEC
188  * LCDs) and just specify which one to load via the unique name
189  * identifier.
190  */
191
192 static int rpxfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
193                            unsigned *blue, unsigned *transp, struct fb_info *info)
194 {
195     volatile cpm8xx_t   *cp = cpmp;
196
197     *red = (cp->lcd_cmap[regno * 2] & 0x0f) << 12;
198     *green = (cp->lcd_cmap[(regno * 2) + 1] & 0xf0) << 8;
199     *blue = (cp->lcd_cmap[(regno * 2) + 1] & 0x0f) << 12;
200
201     return 0;
202 }
203
204 static int rpxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
205                            unsigned blue, unsigned transp, struct fb_info *info)
206 {
207     volatile cpm8xx_t   *cp = cpmp;
208
209     cp->lcd_cmap[regno * 2] = (red & 0xf000) >> 12;
210     cp->lcd_cmap[(regno * 2) + 1] =
211         ((green & 0xf000) >> 8) | ((blue & 0xf000) >> 12);
212
213     return 0;
214 }
215
216
217 static void rpxfb_install_cmap(int con, struct fb_info *info)
218 {
219     struct fb_cmap *cmap;
220
221     /* Make sure we're installing to the current console */
222     if (con != currcon)
223         return;
224
225     if (fb_display[con].cmap.len != 0)
226         cmap = &fb_display[con].cmap;
227     else
228         cmap = fb_default_cmap(NCOLORS(panel_info.vl_bpix));
229
230     fb_set_cmap(cmap, 1, rpxfb_setcolreg, info);
231 }
232
233 /* 
234  * To determine if these occur, just cat /proc/interrupts and look
235  * at the interrupt count.
236  */
237 static void rpxfb_interrupt(int irq, void * dev, struct pt_regs * regs)
238 {
239     volatile lcd8xx_t *lcdp = &(((immap_t *)IMAP_ADDR)->im_lcd);
240
241     lcdp->lcd_lcsr = 0xff;
242 }
243
244 static int rpxfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
245 {
246     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
247     strcpy(fix->id, "RPX FB");
248
249     fix->smem_start = virt_to_phys((void *)lcd_fb_base);
250     fix->smem_len = lcd_fb_size;
251     fix->line_length = lcd_fb_line_length;
252
253     fix->type = FB_TYPE_PACKED_PIXELS;
254
255     if (info->var.bits_per_pixel == 1) {
256         fix->visual = FB_VISUAL_MONO01;
257     } else {
258         fix->visual = FB_VISUAL_PSEUDOCOLOR;
259     }
260
261     return 0;
262 }
263
264 static int rpxfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
265 {
266     if (con == -1) {
267         memset(var, 0, sizeof(struct fb_var_screeninfo));
268
269         var->xres = var->xres_virtual = panel_info.vl_col;
270         var->yres = var->yres_virtual = panel_info.vl_row;
271
272         var->width = panel_info.vl_width;
273         var->height = panel_info.vl_height;
274
275         var->bits_per_pixel = NBITS(panel_info.vl_bpix);
276         var->grayscale = (panel_info.vl_clor == 0);
277         var->red.length = var->green.length = var->blue.length = 4;
278     } else {
279         *var = fb_display[con].var;
280     }
281
282     return 0;
283 }
284
285 static int rpxfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
286 {
287     if ((var->xres != panel_info.vl_col)
288         || (var->yres != panel_info.vl_row)
289         || (var->bits_per_pixel != NBITS(panel_info.vl_bpix))
290         || (var->grayscale && panel_info.vl_clor)
291         || ((var->grayscale == 0) && (panel_info.vl_clor == 0))) {
292         return -EINVAL;
293     }
294
295     rpxfb_get_var(var, con, info);
296
297     return 0;
298 }
299
300 static struct fb_ops rpxfb_ops = {
301     owner:              THIS_MODULE,
302     fb_get_fix:         rpxfb_get_fix,
303     fb_get_var:         rpxfb_get_var,
304     fb_set_var:         rpxfb_set_var,
305     fb_get_cmap:        fbgen_get_cmap,
306     fb_set_cmap:        fbgen_set_cmap,
307     fb_pan_display:     fbgen_pan_display,
308 };
309
310 static void rpxfb_enable(void)
311 {
312     volatile immap_t *immap = (immap_t *) IMAP_ADDR;
313     volatile lcd8xx_t *lcdp = &immap->im_lcd;
314
315     /* See if the LCD has already been enabled */
316     if (lcdp->lcd_lccr & LCCR_PON) {
317         rpxfb_debug("LCD already enabled\n");
318         return;
319     }
320
321     /* Enable the LCD panel */
322     immap->im_siu_conf.sc_sdcr |= (1 << (31 - 25));     /* LAM = 1 */
323     lcdp->lcd_lccr |= LCCR_PON;
324 }
325
326 static void rpxfb_disable(void)
327 {
328     volatile immap_t *immap = (immap_t *) IMAP_ADDR;
329     volatile lcd8xx_t *lcdp = &immap->im_lcd;
330
331     /* Disable the LCD panel */
332     lcdp->lcd_lccr &= ~LCCR_PON;
333     immap->im_siu_conf.sc_sdcr &= ~(1 << (31 - 25)); /* LAM = 0 */
334 }
335
336 static int rpxfb_switch(int con, struct fb_info *info)
337 {
338     /* Do we have to save the colormap ? */
339     if (fb_display[currcon].cmap.len != 0)
340         fb_get_cmap(&fb_display[currcon].cmap, 1, rpxfb_getcolreg, info);
341
342     currcon = con;
343
344     /* Install new colormap */
345     rpxfb_install_cmap(currcon, info);
346
347     return 0;
348 }
349
350 /*
351  * This is called very early in the system initialization to
352  * easily grab physically contiguous memory pages for the LCD
353  * controller.
354  */
355 void __init rpxfb_alloc_pages(void)
356 {
357     lcd_fb_line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
358     lcd_fb_size = lcd_fb_line_length * panel_info.vl_row;
359
360     /* Round up to nearest full page */
361     lcd_fb_size = (lcd_fb_size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
362
363     /* Allocate pages for the frame buffer. */
364     lcd_fb_base = (unsigned long)alloc_bootmem_pages(lcd_fb_size);
365
366     printk(KERN_INFO "rpxfb: allocated %d pages for frame buffer\n",
367            (int)(lcd_fb_size / PAGE_SIZE));
368 }
369
370 static void __init rpxfb_init_dev(void)
371 {
372     volatile cpm8xx_t *cp = cpmp;
373     volatile immap_t *immap = (immap_t *)IMAP_ADDR;
374     volatile lcd8xx_t *lcdp = &immap->im_lcd;
375     uint lccrtmp;
376
377     /* 
378      * Initialize the LCD control register according to the LCD
379      * parameters defined.  We do everything here but enable
380      * the controller.
381      */
382     lccrtmp = LCDBIT(LCCR_BNUM_BIT, 
383             (((panel_info.vl_row * panel_info.vl_col) * 8) / 128));
384
385     lccrtmp |= LCDBIT(LCCR_CLKP_BIT, panel_info.vl_clkp) |
386                     LCDBIT(LCCR_OEP_BIT, panel_info.vl_oep) |
387                     LCDBIT(LCCR_HSP_BIT, panel_info.vl_hsp) |
388                     LCDBIT(LCCR_VSP_BIT, panel_info.vl_vsp) |
389                     LCDBIT(LCCR_DP_BIT, panel_info.vl_dp) |
390                     LCDBIT(LCCR_BPIX_BIT, panel_info.vl_bpix) |
391                     LCDBIT(LCCR_LBW_BIT, panel_info.vl_lbw) |
392                     LCDBIT(LCCR_SPLT_BIT, panel_info.vl_splt) |
393                     LCDBIT(LCCR_CLOR_BIT, panel_info.vl_clor) |
394                     LCDBIT(LCCR_TFT_BIT, panel_info.vl_tft);
395     
396     lccrtmp |= ((SIU_LEVEL5/2) << 12);
397     lccrtmp |= LCCR_EIEN;
398     lcdp->lcd_lccr = lccrtmp;
399     lcdp->lcd_lcsr = 0xff;              /* Clear pending interrupts */
400
401     /* Initialize LCD controller bus priorities. */
402     immap->im_siu_conf.sc_sdcr &= ~0x0f;        /* RAID = LAID = 0 */
403
404     /* 
405      * set SHFT/CLOCK division factor 4
406      * This needs to be set based upon display type and processor
407      * speed.  The TFT displays run about 20 to 30 MHz.
408      * I was running 64 MHz processor speed.
409      * The value for this divider must be chosen so the result is
410      * an integer of the processor speed (i.e., divide by 3 with
411      * 64 MHz would be bad).
412      */
413     immap->im_clkrst.car_sccr &= ~0x1f;
414     immap->im_clkrst.car_sccr |= 8;
415
416     /* Enable LCD on port D. */
417     immap->im_ioport.iop_pdpar |= 0x1fff;
418     immap->im_ioport.iop_pddir |= 0x1fff;
419
420     /* Enable LCD_A/B/C on port B. */
421     cp->cp_pbpar |= 0x00005001;
422     cp->cp_pbdir |= 0x00005001;
423
424     /* 
425      * Load the physical address of the linear frame buffer
426      * into the LCD controller.
427      * BIG NOTE:  This has to be modified to load A and B depending
428      * upon the split mode of the LCD.
429      * Since we don't touch these pages, we don't care how the
430      * application assigns cache mode.
431      */
432     lcdp->lcd_lcfaa = lcdp->lcd_lcfba = __pa(lcd_fb_base);
433
434     /* 
435      * MORE HACKS...This must be updated according to 823 manual
436      * for different panels.
437      */
438     lcdp->lcd_lchcr = LCHCR_BO |
439             LCDBIT(LCHCR_AT_BIT, 4) |
440             LCDBIT(LCHCR_HPC_BIT, panel_info.vl_col) |
441             panel_info.vl_wbl;
442
443     lcdp->lcd_lcvcr = LCDBIT(LCVCR_VPW_BIT, panel_info.vl_vpw) |
444             LCDBIT(LCVCR_LCD_AC_BIT, panel_info.vl_lcdac) |
445             LCDBIT(LCVCR_VPC_BIT, panel_info.vl_row) |
446             panel_info.vl_wbf;
447
448     *((uint *)HIOX_CSR0_ADDR) &= ~(HIOX_CSR0_ENVDOCLK | HIOX_CSR0_VDORST_HL);
449
450     if (request_8xxirq(SIU_LEVEL5, rpxfb_interrupt, 0, "rpxfb", NULL) != 0) {
451         panic("fb: Couldn't allocate LCD IRQ!\n");
452     }
453 }
454
455 #ifdef CONFIG_PM
456 static int rpxfb_pm_request(struct pm_dev *dev, pm_request_t rqst, void *data)
457 {
458     rpxfb_debug("PM request: %d\n", (int)rqst);
459
460     switch (rqst) {
461         case PM_SUSPEND:
462             rpxfb_disable();
463             break;
464         case PM_RESUME:
465             rpxfb_enable();
466             break;
467     }
468
469     return 0;
470 }
471 #endif
472
473 int __init rpxfb_setup(char *options)
474 {
475     char *this_opt;
476
477     if (!options || !*options) {
478         rpxfb_debug("no options\n");
479         return 0;
480     }
481
482     fb_info.fontname[0] = '\0';
483
484     while ((this_opt = strsep(&options, ","))) {
485         if (!*this_opt)
486             continue;
487         if (!strncmp(this_opt, "inverse", 7)) {
488             inverse = 1;
489             fb_invert_cmaps();
490         } else if (!strncmp(this_opt, "font:", 5)) {
491             strcpy(fb_info.fontname, this_opt + 5);
492         } else {
493             mode_option = this_opt;
494         }
495     }
496     
497     return 0;
498 }
499
500 int __init rpxfb_init(void)
501 {
502     strcpy(fb_info.modename, "rpxfb");
503     fb_info.flags = FBINFO_FLAG_DEFAULT;
504     fb_info.fbops = &rpxfb_ops;
505     fb_info.disp = &display;
506     fb_info.switch_con = &rpxfb_switch;
507     fb_info.blank = &fbgen_blank;
508     fb_info.changevar = NULL;
509
510     rpxfb_get_var(&display.var, -1, &fb_info);
511     display.screen_base = (char *) lcd_fb_base;
512     display.line_length = lcd_fb_line_length;
513     display.type = FB_TYPE_PACKED_PIXELS;
514     display.inverse = inverse;
515
516     if (panel_info.vl_bpix == 1) {
517         display.visual = FB_VISUAL_MONO01;
518     } else {
519         display.visual = FB_VISUAL_PSEUDOCOLOR;
520         display.can_soft_blank = 1;
521     }
522
523     /* FIXME: This mess should be in a rpxfb_set_disp() */
524     switch (display.var.bits_per_pixel) {
525 #ifdef FBCON_HAS_MFB
526     case 1:
527         display.dispsw = &fbcon_mfb;
528         break;
529 #endif
530 #ifdef FBCON_HAS_CFB4
531     case 4:
532         display.dispsw = &fbcon_cfb4;
533         break;
534 #endif
535 #ifdef FBCON_HAS_CFB8
536     case 8:
537         display.dispsw = &fbcon_cfb8;
538         break;
539 #endif
540     default:
541         display.dispsw = &fbcon_dummy;
542         break;
543     }
544
545     rpxfb_init_dev();
546     rpxfb_install_cmap(0, &fb_info);
547     rpxfb_enable();
548
549     if (register_framebuffer(&fb_info) < 0) {
550         printk(KERN_ERR "rpxfb: Error registering frame buffer device\n");
551         return -EINVAL;
552     }
553
554     printk(KERN_INFO "fb%d: RPX LCD frame buffer device\n",
555            GET_FB_IDX(fb_info.node));
556
557 #ifdef CONFIG_PM
558     printk(KERN_INFO "rpxfb: Enabling power management\n");
559     pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, rpxfb_pm_request);
560 #endif
561
562     return 0;
563 }
564
565 static void __exit rpxfb_exit(void)
566 {
567 #ifdef CONFIG_PM
568     pm_unregister(pm_dev);
569 #endif
570     rpxfb_disable();
571     unregister_framebuffer(&fb_info);
572 }
573
574 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
575 MODULE_DESCRIPTION("RPX LCD frame buffer device driver");
576
577 #ifdef MODULE
578 module_init(rpxfb_init);
579 #endif
580 module_exit(rpxfb_exit);
581