]> git.neil.brown.name Git - history.git/commitdiff
[ARM] Update clps711x fbcon driver.
authorRussell King <rmk@flint.arm.linux.org.uk>
Sun, 13 Oct 2002 18:49:33 +0000 (19:49 +0100)
committerRussell King <rmk@flint.arm.linux.org.uk>
Sun, 13 Oct 2002 18:49:33 +0000 (19:49 +0100)
drivers/video/clps711xfb.c

index d00c96dccb1ea5cc6722fd61e7802d200e52cec6..14a67d332255ee301baecb5c9940dba6f2c49a4d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/delay.h>
 
 #include <video/fbcon.h>
 
@@ -37,7 +38,7 @@
 
 struct fb_info *cfb;
 
-#define CMAP_SIZE      16
+#define CMAP_MAX_SIZE  16
 
 /* The /proc entry for the backlight. */
 static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL;
@@ -47,6 +48,13 @@ static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
 static int clps7111fb_proc_backlight_write(struct file *file, 
                const char *buffer, unsigned long count, void *data);
 
+/*
+ * LCD AC Prescale.  This comes from the LCD panel manufacturers specifications.
+ * This determines how many clocks + 1 of CL1 before the M signal toggles.
+ * The number of lines on the display must not be divisible by this number.
+ */
+static unsigned int lcd_ac_prescale = 13;
+
 /*
  *    Set a single color register. Return != 0 for invalid regno.
  */
@@ -56,7 +64,7 @@ clps7111fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 {
        unsigned int level, mask, shift, pal;
 
-       if (regno >= CMAP_SIZE)
+       if (regno >= (1 << info->var.bits_per_pixel))
                return 1;
 
        /* gray = 0.30*R + 0.58*G + 0.11*B */
@@ -104,6 +112,8 @@ clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 
        if (var->bits_per_pixel > 4) 
                return -EINVAL;
+
+       return 0;
 }
 
 /*
@@ -112,32 +122,46 @@ clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 static int 
 clps7111fb_set_par(struct fb_info *info)
 {
-       unsigned int lcdcon, syscon;
+       unsigned int lcdcon, syscon, pixclock;
 
-       switch (var->bits_per_pixel) {
+       switch (info->var.bits_per_pixel) {
        case 1:
-               info->fix.visual        = FB_VISUAL_MONO01;
+               info->fix.visual = FB_VISUAL_MONO01;
                break;
        case 2:
-               info->fix.visual        = FB_VISUAL_PSEUDOCOLOR;
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
                break;
        case 4:
-               info->fix.visual        = FB_VISUAL_PSEUDOCOLOR;
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
                break;
        }
 
        info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8;
 
-       /*
-        * LCDCON must only be changed while the LCD is disabled
-        */
        lcdcon = (info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel) / 128 - 1;
        lcdcon |= ((info->var.xres_virtual / 16) - 1) << 13;
-       lcdcon |= 2 << 19;
-       lcdcon |= 13 << 25;
-       lcdcon |= LCDCON_GSEN;
-       lcdcon |= LCDCON_GSMD;
+       lcdcon |= lcd_ac_prescale << 25;
+
+       /*
+        * Calculate pixel prescale value from the pixclock.  This is:
+        *  36.864MHz / pixclock_mhz - 1.
+        * However, pixclock is in picoseconds, so this ends up being:
+        *  36864000 * pixclock_ps / 10^12 - 1
+        * and this will overflow the 32-bit math.  We perform this as
+        * (9 * 4096000 == 36864000):
+        *  pixclock_ps * 9 * (4096000 / 10^12) - 1
+        */
+       pixclock = 9 * info->var.pixclock / 244140 - 1;
+       lcdcon |= pixclock << 19;
+
+       if (info->var.bits_per_pixel == 4)
+               lcdcon |= LCDCON_GSMD;
+       if (info->var.bits_per_pixel >= 2)
+               lcdcon |= LCDCON_GSEN;
 
+       /*
+        * LCDCON must only be changed while the LCD is disabled
+        */
        syscon = clps_readl(SYSCON1);
        clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1);
        clps_writel(lcdcon, LCDCON);
@@ -149,8 +173,6 @@ static int clps7111fb_blank(int blank, struct fb_info *info)
 {
        if (blank) {
                if (machine_is_edb7211()) {
-                       int i;
-
                        /* Turn off the LCD backlight. */
                        clps_writeb(clps_readb(PDDR) & ~EDB_PD3_LCDBL, PDDR);
 
@@ -169,8 +191,6 @@ static int clps7111fb_blank(int blank, struct fb_info *info)
                }
        } else {
                if (machine_is_edb7211()) {
-                       int i;
-
                        /* Power up the LCD controller. */
                        clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN,
                                        SYSCON1);
@@ -256,6 +276,93 @@ clps7111fb_proc_backlight_write(struct file *file, const char *buffer,
        return count;
 }
 
+static void __init clps711x_guess_lcd_params(struct fb_info *info)
+{
+       unsigned int lcdcon, syscon, size;
+       unsigned long phys_base = PAGE_OFFSET;
+       void *virt_base = (void *)PAGE_OFFSET;
+
+       info->var.xres_virtual   = 640;
+       info->var.yres_virtual   = 240;
+       info->var.bits_per_pixel = 4;
+       info->var.activate       = FB_ACTIVATE_NOW;
+       info->var.height         = -1;
+       info->var.width          = -1;
+       info->var.pixclock       = 93006; /* 10.752MHz pixel clock */
+
+       /*
+        * If the LCD controller is already running, decode the values
+        * in LCDCON to xres/yres/bpp/pixclock/acprescale
+        */
+       syscon = clps_readl(SYSCON1);
+       if (syscon & SYSCON1_LCDEN) {
+               lcdcon = clps_readl(LCDCON);
+
+               /*
+                * Decode GSMD and GSEN bits to bits per pixel
+                */
+               switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) {
+               case LCDCON_GSMD | LCDCON_GSEN:
+                       info->var.bits_per_pixel = 4;
+                       break;
+
+               case LCDCON_GSEN:
+                       info->var.bits_per_pixel = 2;
+                       break;
+
+               default:
+                       info->var.bits_per_pixel = 1;
+                       break;
+               }
+
+               /*
+                * Decode xres/yres
+                */
+               info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16;
+               info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) /
+                                         (info->var.xres_virtual *
+                                          info->var.bits_per_pixel);
+
+               /*
+                * Calculate pixclock
+                */
+               info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9;
+
+               /*
+                * Grab AC prescale
+                */
+               lcd_ac_prescale = (lcdcon >> 25) & 0x1f;
+       }
+
+       info->var.xres = info->var.xres_virtual;
+       info->var.yres = info->var.yres_virtual;
+       info->var.grayscale = info->var.bits_per_pixel > 1;
+
+       size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8;
+
+       /*
+        * Might be worth checking to see if we can use the on-board
+        * RAM if size here...
+        * CLPS7110 - no on-board SRAM
+        * EP7212   - 38400 bytes
+        */
+       if (size < 38400) {
+               printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n");
+       }
+
+       if ((syscon & SYSCON1_LCDEN) == 0) {
+               /*
+                * The display isn't running.  Ensure that
+                * the display memory is empty.
+                */
+               memset(virt_base, 0, size);
+       }
+
+       info->screen_base    = virt_base;
+       info->fix.smem_start = phys_base;
+       info->fix.smem_len   = PAGE_ALIGN(size);
+       info->fix.type       = FB_TYPE_PACKED_PIXELS;
+}
 
 int __init clps711xfb_init(void)
 {
@@ -266,34 +373,19 @@ int __init clps711xfb_init(void)
                goto out;
 
        memset(cfb, 0, sizeof(*cfb) + sizeof(struct display));
-       memset((void *)PAGE_OFFSET, 0, 0x14000);
+       strcpy(cfb->fix.id, "clps711x");
 
        cfb->currcon            = -1;
-
-       strcpy(cfb->fix.id, "clps7111");
-       cfb->screen_base        = (void *)PAGE_OFFSET;
-       cfb->fix.smem_start     = PAGE_OFFSET;
-       cfb->fix.smem_len       = 0x14000;
-       cfb->fix.type   = FB_TYPE_PACKED_PIXELS;
-
-       cfb->var.xres    = 640;
-       cfb->var.xres_virtual = 640;
-       cfb->var.yres    = 240;
-       cfb->var.yres_virtual = 240;
-       cfb->var.bits_per_pixel = 4;
-       cfb->var.grayscale   = 1;
-       cfb->var.activate       = FB_ACTIVATE_NOW;
-       cfb->var.height = -1;
-       cfb->var.width  = -1;
-
        cfb->fbops              = &clps7111fb_ops;
-       cfb->changevar  = NULL;
-       cfb->switch_con = gen_switch;
-       cfb->updatevar  = gen_update_var;
+       cfb->changevar          = NULL;
+       cfb->switch_con         = gen_switch;
+       cfb->updatevar          = gen_update_var;
        cfb->flags              = FBINFO_FLAG_DEFAULT;
        cfb->disp               = (struct display *)(cfb + 1);
 
-       fb_alloc_cmap(&cfb->cmap, CMAP_SIZE, 0);
+       clps711x_guess_lcd_params(cfb);
+
+       fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0);
 
        /* Register the /proc entries. */
        clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444,
@@ -317,8 +409,6 @@ int __init clps711xfb_init(void)
        }
 
        if (machine_is_edb7211()) {
-               int i;
-
                /* Power up the LCD panel. */
                clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR);