Merge branch 'master' of http://git.denx.de/u-boot
[kernel/u-boot.git] / common / lcd.c
index c87de0b..4ed6b90 100644 (file)
@@ -35,6 +35,7 @@
 #include <stdarg.h>
 #include <linux/types.h>
 #include <stdio_dev.h>
+#include <malloc.h>
 #if defined(CONFIG_POST)
 #include <post.h>
 #endif
@@ -63,7 +64,7 @@
 /************************************************************************/
 #ifdef CONFIG_LCD_LOGO
 # include <bmp_logo.h>         /* Get logo data, width and height      */
-# if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET)
+# if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)
 #  error Default Color Map overlaps with Logo Color Map
 # endif
 #endif
@@ -79,25 +80,13 @@ static inline void lcd_putc_xy (ushort x, ushort y, uchar  c);
 static int lcd_init (void *lcdbase);
 
 static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]);
-extern void lcd_ctrl_init (void *lcdbase);
-extern void lcd_enable (void);
 static void *lcd_logo (void);
 
-
-#if (LCD_BPP == LCD_COLOR8) || (LCD_BPP == LCD_COLOR16)
-extern void lcd_setcolreg (ushort regno,
-                               ushort red, ushort green, ushort blue);
-#endif
-#if LCD_BPP == LCD_MONOCHROME
-extern void lcd_initcolregs (void);
-#endif
-
 static int lcd_getbgcolor (void);
 static void lcd_setfgcolor (int color);
 static void lcd_setbgcolor (int color);
 
 char lcd_is_enabled = 0;
-extern vidinfo_t panel_info;
 
 #ifdef NOT_USED_SO_FAR
 static void lcd_getcolreg (ushort regno,
@@ -111,32 +100,11 @@ static int lcd_getfgcolor (void);
 
 static void console_scrollup (void)
 {
-#if 1
        /* Copy up rows ignoring the first one */
        memcpy (CONSOLE_ROW_FIRST, CONSOLE_ROW_SECOND, CONSOLE_SCROLL_SIZE);
 
        /* Clear the last one */
        memset (CONSOLE_ROW_LAST, COLOR_MASK(lcd_color_bg), CONSOLE_ROW_SIZE);
-#else
-       /*
-        * Poor attempt to optimize speed by moving "long"s.
-        * But the code is ugly, and not a bit faster :-(
-        */
-       ulong *t = (ulong *)CONSOLE_ROW_FIRST;
-       ulong *s = (ulong *)CONSOLE_ROW_SECOND;
-       ulong    l = CONSOLE_SCROLL_SIZE / sizeof(ulong);
-       uchar  c = lcd_color_bg & 0xFF;
-       ulong val= (c<<24) | (c<<16) | (c<<8) | c;
-
-       while (l--)
-               *t++ = *s++;
-
-       t = (ulong *)CONSOLE_ROW_LAST;
-       l = CONSOLE_ROW_SIZE / sizeof(ulong);
-
-       while (l-- > 0)
-               *t++ = val;
-#endif
 }
 
 /*----------------------------------------------------------------------*/
@@ -251,8 +219,12 @@ static void lcd_drawchars (ushort x, ushort y, uchar *str, int count)
 
        for (row=0;  row < VIDEO_FONT_HEIGHT;  ++row, dest += lcd_line_length)  {
                uchar *s = str;
-               uchar *d = dest;
                int i;
+#if LCD_BPP == LCD_COLOR16
+               ushort *d = (ushort *)dest;
+#else
+               uchar *d = dest;
+#endif
 
 #if LCD_BPP == LCD_MONOCHROME
                uchar rest = *d & -(1 << (8-off));
@@ -277,7 +249,7 @@ static void lcd_drawchars (ushort x, ushort y, uchar *str, int count)
                                bits <<= 1;
                        }
 #elif LCD_BPP == LCD_COLOR16
-                       for (c=0; c<16; ++c) {
+                       for (c=0; c<8; ++c) {
                                *d++ = (bits & 0x80) ?
                                                lcd_color_fg : lcd_color_bg;
                                bits <<= 1;
@@ -352,6 +324,16 @@ static void test_pattern (void)
 /************************************************************************/
 /* ** GENERIC Initialization Routines                                  */
 /************************************************************************/
+int drv_lcd_init_resume (void)
+{
+       lcd_base = (void *)(gd->fb_base);
+
+       lcd_line_length = (panel_info.vl_col * (panel_info.vl_bpix)) / 8;
+
+       lcd_init (lcd_base);            /* LCD initialization */
+
+       return 0;
+}
 
 int drv_lcd_init (void)
 {
@@ -360,7 +342,7 @@ int drv_lcd_init (void)
 
        lcd_base = (void *)(gd->fb_base);
 
-       lcd_line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+       lcd_line_length = (panel_info.vl_col * (panel_info.vl_bpix / 8));
 
        lcd_init (lcd_base);            /* LCD initialization */
 
@@ -467,10 +449,10 @@ static int lcd_init (void *lcdbase)
 ulong lcd_setmem (ulong addr)
 {
        ulong size;
-       int line_length = (panel_info.vl_col * NBITS (panel_info.vl_bpix)) / 8;
+       int line_length = (panel_info.vl_col * (panel_info.vl_bpix)) / 8;
 
        debug ("LCD panel info: %d x %d, %d bit/pix\n",
-               panel_info.vl_col, panel_info.vl_row, NBITS (panel_info.vl_bpix) );
+               panel_info.vl_col, panel_info.vl_row, (panel_info.vl_bpix) );
 
        size = line_length * panel_info.vl_row;
 
@@ -489,22 +471,14 @@ ulong lcd_setmem (ulong addr)
 
 static void lcd_setfgcolor (int color)
 {
-#ifdef CONFIG_ATMEL_LCD
        lcd_color_fg = color;
-#else
-       lcd_color_fg = color & 0x0F;
-#endif
 }
 
 /*----------------------------------------------------------------------*/
 
 static void lcd_setbgcolor (int color)
 {
-#ifdef CONFIG_ATMEL_LCD
        lcd_color_bg = color;
-#else
-       lcd_color_bg = color & 0x0F;
-#endif
 }
 
 /*----------------------------------------------------------------------*/
@@ -554,7 +528,7 @@ void bitmap_plot (int x, int y)
        bmap = &bmp_logo_bitmap[0];
        fb   = (uchar *)(lcd_base + y * lcd_line_length + x);
 
-       if (NBITS(panel_info.vl_bpix) < 12) {
+       if ((panel_info.vl_bpix) < 12) {
                /* Leave room for default color map */
 #if defined(CONFIG_PXA250)
                cmap = (ushort *)fbi->palette;
@@ -562,6 +536,13 @@ void bitmap_plot (int x, int y)
                cmap = (ushort *)&(cp->lcd_cmap[BMP_LOGO_OFFSET*sizeof(ushort)]);
 #elif defined(CONFIG_ATMEL_LCD)
                cmap = (uint *) (panel_info.mmio + ATMEL_LCDC_LUT(0));
+#else
+               /*
+                * default case: generic system with no cmap (most likely 16bpp)
+                * We set cmap to the source palette, so no change is done.
+                * This avoids even more ifdef in the next stanza
+                */
+               cmap = bmp_logo_palette;
 #endif
 
                WATCHDOG_RESET();
@@ -600,10 +581,15 @@ void bitmap_plot (int x, int y)
                }
        }
        else { /* true color mode */
+               u16 col16;
                fb16 = (ushort *)(lcd_base + y * lcd_line_length + x);
                for (i=0; i<BMP_LOGO_HEIGHT; ++i) {
                        for (j=0; j<BMP_LOGO_WIDTH; j++) {
-                               fb16[j] = bmp_logo_palette[(bmap[j])];
+                               col16 = bmp_logo_palette[(bmap[j]-16)];
+                               fb16[j] =
+                                       ((col16 & 0x000F) << 1) |
+                                       ((col16 & 0x00F0) << 3) |
+                                       ((col16 & 0x0F00) << 4);
                                }
                        bmap += BMP_LOGO_WIDTH;
                        fb16 += panel_info.vl_col;
@@ -624,6 +610,13 @@ void bitmap_plot (int x, int y)
 #ifdef CONFIG_SPLASH_SCREEN_ALIGN
 #define BMP_ALIGN_CENTER       0x7FFF
 #endif
+void lcd_display_clear(void)
+{
+       unsigned int *fb = lcd_base;
+       printf("Clean the display\n");
+
+       memset(fb, 0, panel_info.vl_row * panel_info.vl_col * panel_info.vl_bpix / 8);
+}
 
 int lcd_display_bitmap(ulong bmp_image, int x, int y)
 {
@@ -659,17 +652,17 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
        colors = 1 << bmp_bpix;
        compression = le32_to_cpu (bmp->header.compression);
 
-       bpix = NBITS(panel_info.vl_bpix);
+       bpix = (panel_info.vl_bpix);
 
-       if ((bpix != 1) && (bpix != 8) && (bpix != 16)) {
-               printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+       if ((bpix != 1) && (bpix != 8) && (bpix != 16) && (bpix != 32)) {
+               printf ("Error0: %d bit/pixel mode, but BMP has %d bit/pixel\n",
                        bpix, bmp_bpix);
                return 1;
        }
 
-       /* We support displaying 8bpp BMPs on 16bpp LCDs */
-       if (bpix != bmp_bpix && (bmp_bpix != 8 || bpix != 16)) {
-               printf ("Error: %d bit/pixel mode, but BMP has %d bit/pixel\n",
+       /* We support displaying 8bpp BMPs on 16bpp LCDs and 4bpp BMPs on 32bpp LCDs */
+       if (bpix != bmp_bpix && (bmp_bpix != 8 || bpix != 16) && !(bpix == 32 && bmp_bpix == 4) ) {
+               printf ("Error1: %d bit/pixel mode, but BMP has %d bit/pixel\n",
                        bpix,
                        le16_to_cpu(bmp->header.bit_count));
                return 1;
@@ -686,7 +679,8 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
 #elif defined(CONFIG_MPC823)
                cmap = (ushort *)&(cp->lcd_cmap[255*sizeof(ushort)]);
 #elif !defined(CONFIG_ATMEL_LCD)
-               cmap = panel_info.cmap;
+               /* cmap = panel_info.cmap; */
+               cmap = (ushort *) malloc(1024);
 #endif
 
                cmap_base = cmap;
@@ -759,6 +753,43 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
                (y + height - 1) * lcd_line_length + x);
 
        switch (bmp_bpix) {
+       case 4: /* Display 4b bmp at 32b lcd */
+               if (bpix == 32) {
+                       /* 1. Get the color map */
+                       unsigned int cmap_32[16];
+                       unsigned int effective_width;
+
+                       for (i=0; i<colors; ++i) {
+                               bmp_color_table_entry_t cte = bmp->color_table[i];
+                               cmap_32[i] = (cte.red << 0) | (cte.green << 8) |
+                                       (cte.blue << 16) | (cte.reserved << 24);
+                       }
+
+                       /* 2. Put'em on the screen */
+                       lcd_line_length = (panel_info.vl_col * (panel_info.vl_bpix / 8));
+                       fb = (uchar *) lcd_base;
+                       fb += lcd_line_length * (y + height) + x * 4;
+
+                       printf("Drawing the 32bit bmp.. @ 4b (%d,%d) of [%ldx%ld] in %d (%d color)\n",
+                                       x, y, width, height, lcd_line_length, colors);
+                       effective_width = (width % 2) ? (width + 1) : width;
+                       for (i = 0; i < height; ++i) {
+                               WATCHDOG_RESET();
+                               for (j = 0; j < width; j++) {
+                                       int color_v;
+                                       color_v = bmap[(j + i * effective_width) / 2];
+                                       if ((j + i * effective_width) % 2)
+                                               color_v = color_v & 0xf;
+                                       else
+                                               color_v = (color_v >> 4) & 0xf;
+
+                                       memcpy(fb, cmap_32 + color_v, 4);
+                                       fb += 4;
+                               }
+                               fb   -= (lcd_line_length + width * 4);
+                       }
+               }
+               break;
        case 1: /* pass through */
        case 8:
                if (bpix != 16)
@@ -806,6 +837,25 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
                }
                break;
 #endif /* CONFIG_BMP_16BPP */
+       case 32:
+               lcd_line_length = (panel_info.vl_col * (panel_info.vl_bpix / 8));
+               fb = (uchar *) lcd_base;
+               fb += lcd_line_length * (y + height) + x * 4;
+
+               printf("Drawing the 32bit bmp.. @ (%d,%d) of [%ldx%ld] in %d\n",
+                               x, y, width, height, lcd_line_length);
+               for (i = 0; i < height; ++i) {
+                       WATCHDOG_RESET();
+                       for (j = 0; j < width; j++) {
+                               *(fb++) = *(bmap++);
+                               *(fb++) = *(bmap++);
+                               *(fb++) = *(bmap++);
+                               *(fb++) = *(bmap++);
+                       }
+                       //bmap += (padded_line - width) * 4;
+                       fb   -= (lcd_line_length + width * 4);
+               }
+               break;
 
        default:
                break;
@@ -815,15 +865,12 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y)
 }
 #endif
 
-#ifdef CONFIG_VIDEO_BMP_GZIP
-extern bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp);
-#endif
-
 static void *lcd_logo (void)
 {
 #ifdef CONFIG_SPLASH_SCREEN
        char *s;
        ulong addr;
+       int allocated = 0;
        static int do_splash = 1;
 
        if (do_splash && (s = getenv("splashimage")) != NULL) {
@@ -854,12 +901,22 @@ static void *lcd_logo (void)
                if (!((bmp->header.signature[0]=='B') &&
                      (bmp->header.signature[1]=='M'))) {
                        addr = (ulong)gunzip_bmp(addr, &len);
+                       if (addr)
+                               allocated = 1;
                }
 #endif
 
                if (lcd_display_bitmap (addr, x, y) == 0) {
+#ifdef CONFIG_VIDEO_BMP_GZIP
+                       if (addr && allocated)
+                               free((void *)addr);
+#endif
                        return ((void *)lcd_base);
                }
+#ifdef CONFIG_VIDEO_BMP_GZIP
+               if (addr && allocated)
+                       free((void *)addr);
+#endif
        }
 #endif /* CONFIG_SPLASH_SCREEN */