2 * drivers/video/rpxfb.c
4 * RPX LCD frame buffer driver for PowerPC MPC823 family.
6 * Maintained by: Paul Mundt <pmundt@mvista.com>
8 * Copyright (C) 2000, 2001 MontaVista Software, Inc.
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.
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>
26 #include <asm/8xx_immap.h>
27 #include <asm/mpc8xx.h>
30 #include <video/fbcon.h>
31 #include <video/fbcon-mfb.h>
32 #include <video/fbcon-cfb4.h>
33 #include <video/fbcon-cfb8.h>
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)
56 /* Define the bit shifts to load values into the register. */
57 #define LCDBIT(BIT, VAL) ((VAL) << (31 - BIT))
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)
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)
81 #define LCHCR_AT_BIT ((uint)10)
82 #define LCHCR_HPC_BIT ((uint)21)
83 #define LCHCR_WBL_BIT ((uint)31)
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)
91 #define LCVCR_VPW_BIT ((uint)3)
92 #define LCVCR_LCD_AC_BIT ((uint)10)
93 #define LCVCR_VPC_BIT ((uint)20)
96 extern cpm8xx_t *cpmp;
98 #ifdef CONFIG_FB_RPX_DEBUG
99 #define rpxfb_debug(x...) printk(KERN_DEBUG "fb:" __FUNCTION__ ": " ##x)
101 #define rpxfb_debug(x...)
102 #endif /* CONFIG_FB_RPX_DEBUG */
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.
109 #define CFG_HIGH 0 /* Pins are active high */
110 #define CFG_LOW 1 /* Pins are active low */
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 */
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 */
130 /* Horizontal control register. Timing from data sheet. */
131 ushort vl_wbl; /* Wait between lines */
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 */
139 #if defined(CONFIG_FB_RPX_LCD_NEC)
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?).
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
150 #elif defined(CONFIG_FB_RPX_LCD_SHARP)
152 * Sharp 320x240. Active, color, single scan. It isn't 16x9, and I am
153 * not sure what it is.......
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
160 #error "LCD type not defined"
163 #define NBITS(bit_code) (1 << (bit_code))
164 #define NCOLORS(bit_code) (1 << NBITS(bit_code))
166 static struct fb_info fb_info;
167 static struct display display;
168 static int currcon = 0;
169 static int inverse = 0;
172 /* Power management device */
173 static struct pm_dev *pm_dev;
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;
182 static const char *mode_option __initdata = NULL;
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
192 static int rpxfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
193 unsigned *blue, unsigned *transp, struct fb_info *info)
195 volatile cpm8xx_t *cp = cpmp;
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;
204 static int rpxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
205 unsigned blue, unsigned transp, struct fb_info *info)
207 volatile cpm8xx_t *cp = cpmp;
209 cp->lcd_cmap[regno * 2] = (red & 0xf000) >> 12;
210 cp->lcd_cmap[(regno * 2) + 1] =
211 ((green & 0xf000) >> 8) | ((blue & 0xf000) >> 12);
217 static void rpxfb_install_cmap(int con, struct fb_info *info)
219 struct fb_cmap *cmap;
221 /* Make sure we're installing to the current console */
225 if (fb_display[con].cmap.len != 0)
226 cmap = &fb_display[con].cmap;
228 cmap = fb_default_cmap(NCOLORS(panel_info.vl_bpix));
230 fb_set_cmap(cmap, 1, rpxfb_setcolreg, info);
234 * To determine if these occur, just cat /proc/interrupts and look
235 * at the interrupt count.
237 static void rpxfb_interrupt(int irq, void * dev, struct pt_regs * regs)
239 volatile lcd8xx_t *lcdp = &(((immap_t *)IMAP_ADDR)->im_lcd);
241 lcdp->lcd_lcsr = 0xff;
244 static int rpxfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
246 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
247 strcpy(fix->id, "RPX FB");
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;
253 fix->type = FB_TYPE_PACKED_PIXELS;
255 if (info->var.bits_per_pixel == 1) {
256 fix->visual = FB_VISUAL_MONO01;
258 fix->visual = FB_VISUAL_PSEUDOCOLOR;
264 static int rpxfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
267 memset(var, 0, sizeof(struct fb_var_screeninfo));
269 var->xres = var->xres_virtual = panel_info.vl_col;
270 var->yres = var->yres_virtual = panel_info.vl_row;
272 var->width = panel_info.vl_width;
273 var->height = panel_info.vl_height;
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;
279 *var = fb_display[con].var;
285 static int rpxfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
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))) {
295 rpxfb_get_var(var, con, info);
300 static struct fb_ops rpxfb_ops = {
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,
310 static void rpxfb_enable(void)
312 volatile immap_t *immap = (immap_t *) IMAP_ADDR;
313 volatile lcd8xx_t *lcdp = &immap->im_lcd;
315 /* See if the LCD has already been enabled */
316 if (lcdp->lcd_lccr & LCCR_PON) {
317 rpxfb_debug("LCD already enabled\n");
321 /* Enable the LCD panel */
322 immap->im_siu_conf.sc_sdcr |= (1 << (31 - 25)); /* LAM = 1 */
323 lcdp->lcd_lccr |= LCCR_PON;
326 static void rpxfb_disable(void)
328 volatile immap_t *immap = (immap_t *) IMAP_ADDR;
329 volatile lcd8xx_t *lcdp = &immap->im_lcd;
331 /* Disable the LCD panel */
332 lcdp->lcd_lccr &= ~LCCR_PON;
333 immap->im_siu_conf.sc_sdcr &= ~(1 << (31 - 25)); /* LAM = 0 */
336 static int rpxfb_switch(int con, struct fb_info *info)
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);
344 /* Install new colormap */
345 rpxfb_install_cmap(currcon, info);
351 * This is called very early in the system initialization to
352 * easily grab physically contiguous memory pages for the LCD
355 void __init rpxfb_alloc_pages(void)
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;
360 /* Round up to nearest full page */
361 lcd_fb_size = (lcd_fb_size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
363 /* Allocate pages for the frame buffer. */
364 lcd_fb_base = (unsigned long)alloc_bootmem_pages(lcd_fb_size);
366 printk(KERN_INFO "rpxfb: allocated %d pages for frame buffer\n",
367 (int)(lcd_fb_size / PAGE_SIZE));
370 static void __init rpxfb_init_dev(void)
372 volatile cpm8xx_t *cp = cpmp;
373 volatile immap_t *immap = (immap_t *)IMAP_ADDR;
374 volatile lcd8xx_t *lcdp = &immap->im_lcd;
378 * Initialize the LCD control register according to the LCD
379 * parameters defined. We do everything here but enable
382 lccrtmp = LCDBIT(LCCR_BNUM_BIT,
383 (((panel_info.vl_row * panel_info.vl_col) * 8) / 128));
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);
396 lccrtmp |= ((SIU_LEVEL5/2) << 12);
397 lccrtmp |= LCCR_EIEN;
398 lcdp->lcd_lccr = lccrtmp;
399 lcdp->lcd_lcsr = 0xff; /* Clear pending interrupts */
401 /* Initialize LCD controller bus priorities. */
402 immap->im_siu_conf.sc_sdcr &= ~0x0f; /* RAID = LAID = 0 */
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).
413 immap->im_clkrst.car_sccr &= ~0x1f;
414 immap->im_clkrst.car_sccr |= 8;
416 /* Enable LCD on port D. */
417 immap->im_ioport.iop_pdpar |= 0x1fff;
418 immap->im_ioport.iop_pddir |= 0x1fff;
420 /* Enable LCD_A/B/C on port B. */
421 cp->cp_pbpar |= 0x00005001;
422 cp->cp_pbdir |= 0x00005001;
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.
432 lcdp->lcd_lcfaa = lcdp->lcd_lcfba = __pa(lcd_fb_base);
435 * MORE HACKS...This must be updated according to 823 manual
436 * for different panels.
438 lcdp->lcd_lchcr = LCHCR_BO |
439 LCDBIT(LCHCR_AT_BIT, 4) |
440 LCDBIT(LCHCR_HPC_BIT, panel_info.vl_col) |
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) |
448 *((uint *)HIOX_CSR0_ADDR) &= ~(HIOX_CSR0_ENVDOCLK | HIOX_CSR0_VDORST_HL);
450 if (request_8xxirq(SIU_LEVEL5, rpxfb_interrupt, 0, "rpxfb", NULL) != 0) {
451 panic("fb: Couldn't allocate LCD IRQ!\n");
456 static int rpxfb_pm_request(struct pm_dev *dev, pm_request_t rqst, void *data)
458 rpxfb_debug("PM request: %d\n", (int)rqst);
473 int __init rpxfb_setup(char *options)
477 if (!options || !*options) {
478 rpxfb_debug("no options\n");
482 fb_info.fontname[0] = '\0';
484 while ((this_opt = strsep(&options, ","))) {
487 if (!strncmp(this_opt, "inverse", 7)) {
490 } else if (!strncmp(this_opt, "font:", 5)) {
491 strcpy(fb_info.fontname, this_opt + 5);
493 mode_option = this_opt;
500 int __init rpxfb_init(void)
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;
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;
516 if (panel_info.vl_bpix == 1) {
517 display.visual = FB_VISUAL_MONO01;
519 display.visual = FB_VISUAL_PSEUDOCOLOR;
520 display.can_soft_blank = 1;
523 /* FIXME: This mess should be in a rpxfb_set_disp() */
524 switch (display.var.bits_per_pixel) {
527 display.dispsw = &fbcon_mfb;
530 #ifdef FBCON_HAS_CFB4
532 display.dispsw = &fbcon_cfb4;
535 #ifdef FBCON_HAS_CFB8
537 display.dispsw = &fbcon_cfb8;
541 display.dispsw = &fbcon_dummy;
546 rpxfb_install_cmap(0, &fb_info);
549 if (register_framebuffer(&fb_info) < 0) {
550 printk(KERN_ERR "rpxfb: Error registering frame buffer device\n");
554 printk(KERN_INFO "fb%d: RPX LCD frame buffer device\n",
555 GET_FB_IDX(fb_info.node));
558 printk(KERN_INFO "rpxfb: Enabling power management\n");
559 pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, rpxfb_pm_request);
565 static void __exit rpxfb_exit(void)
568 pm_unregister(pm_dev);
571 unregister_framebuffer(&fb_info);
574 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
575 MODULE_DESCRIPTION("RPX LCD frame buffer device driver");
578 module_init(rpxfb_init);
580 module_exit(rpxfb_exit);