s5pc110: fb: possible memory leak (un-free'd malloc)
[kernel/u-boot.git] / drivers / video / s5p-fb.c
index 8e28034..3e90e21 100644 (file)
 #include <asm/io.h>
 #include <asm/arch/cpu.h>
 #include <lcd.h>
+#include <malloc.h>
 
 #include "s5p-fb.h"
-#include "opening_wvga_32.h"
-//#include "logo_rgb24_wvga_portrait.h"
-//#include "opening_logo_rgb24_143_44.h"
-
-#define PANEL_WIDTH            480
-#define PANEL_HEIGHT           800
-#define S5P_LCD_BPP            32
+#include "logo.h"
+/*
+#include "logo_rgb24_wvga_portrait.h"
+#include "opening_logo_rgb24_143_44.h"
+*/
 
 extern void tl2796_panel_power_on(void);
 extern void tl2796_panel_enable(void);
@@ -51,6 +50,9 @@ void *lcd_console_address;
 short console_col;
 short console_row;
 
+static unsigned int panel_width, panel_height;
+
+#ifdef USE_LCD_TEST
 static unsigned short makepixel565(char r, char g, char b)
 {
     return (unsigned short)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
@@ -70,7 +72,7 @@ static void read_image16(char* pImg, int x1pos, int y1pos, int x2pos,
 
        for(i = y1pos; i < y2pos; i++) {
                for(j = x1pos; j < x2pos; j++) {
-                       offset_s = i * PANEL_WIDTH + j;
+                       offset_s = i * panel_width + j;
                        *(pDst + offset_s) = pixel;
                }
        }
@@ -83,55 +85,24 @@ static void read_image32(char* pImg, int x1pos, int y1pos, int x2pos,
        unsigned int offset_s;
        int i, j;
 
-       for(i = y1pos; i < y2pos; i++) {
-               for(j = x1pos; j < x2pos; j++) {
-                       offset_s = i * PANEL_WIDTH + j;
+       for (i = y1pos; i < y2pos; i++) {
+               for (j = x1pos; j < x2pos; j++) {
+                       offset_s = i * panel_width + j;
                        *(pDst+offset_s) = pixel;
                }
        }
 }
+#endif
 
 /* LCD Panel data */
-vidinfo_t panel_info = {
-               .vl_col         = PANEL_WIDTH,
-               .vl_row         = PANEL_HEIGHT,
-               .vl_width       = PANEL_WIDTH,
-               .vl_height      = PANEL_HEIGHT,
-               .vl_clkp        = CONFIG_SYS_HIGH,
-               .vl_hsp         = CONFIG_SYS_LOW,
-               .vl_vsp         = CONFIG_SYS_LOW,
-               .vl_dp          = CONFIG_SYS_HIGH,
-               .vl_bpix        = S5P_LCD_BPP,
-               .vl_lbw         = 0,
-               .vl_splt        = 0,
-               .vl_clor        = 1,
-               .vl_tft         = 1,
-
-               /* S6E63M0 LCD Panel */
-               .vl_hpw         = 2,
-               .vl_blw         = 16,
-               .vl_elw         = 16,
-
-               .vl_vpw         = 2,
-               .vl_bfw         = 3,
-               .vl_efw         = 28,
-               /* tl2796 panel.
-               .vl_hpw         = 4,
-               .vl_blw         = 8,
-               .vl_elw         = 8,
-
-               .vl_vpw         = 4,
-               .vl_bfw         = 8,
-               .vl_efw         = 8,
-               */
-};
+vidinfo_t panel_info;
 
 static void s5pc_lcd_init_mem(void *lcdbase, vidinfo_t *vid)
 {
        unsigned long palette_size, palette_mem_size;
        unsigned int fb_size;
 
-       fb_size = vid->vl_row * vid->vl_col * (vid->vl_bpix / 8);
+       fb_size = vid->vl_row * vid->vl_col * (vid->vl_bpix >> 3);
 
        lcd_base = lcdbase;
 
@@ -144,76 +115,173 @@ static void s5pc_lcd_init_mem(void *lcdbase, vidinfo_t *vid)
                        fb_size, (unsigned int)lcd_base, (int)palette_size, (int)palette_mem_size);
 }
 
-static void s5pc_gpio_setup(void)
-{
-       if (cpu_is_s5pc100())
-               s5pc_c100_gpio_setup();
-       else
-               s5pc_c110_gpio_setup();
-}
-
 static void s5pc_lcd_init(vidinfo_t *vid)
 {
        s5pc_fimd_lcd_init(vid);
 }
 
-static void lcd_test(void)
+#ifdef USE_LCD_TEST
+static void lcd_test(unsigned int width, unsigned int height)
 {
+       unsigned int height_level = height / 3;
+
        /* red */
-       read_image32((char *)lcd_base, 0, 0, 480, 200,
+       read_image32((char *)lcd_base, 0, 0, width, height_level,
                        makepixel8888(0, 255, 0, 0));
        /* green */
-       read_image32((char *)lcd_base, 0, 200, 480, 400,
-                       makepixel8888(0, 0, 255, 0));
+       read_image32((char *)lcd_base, 0, height_level, width,
+               height_level * 2, makepixel8888(0, 0, 255, 0));
        /* blue */
-       read_image32((char *)lcd_base, 0, 400, 480, 600,
+       read_image32((char *)lcd_base, 0, height_level * 2, width, height,
                        makepixel8888(0, 0, 0, 255));
-       /* write */
-       read_image32((char *)lcd_base, 0, 600, 480, 800,
-                       makepixel8888(0, 255, 255, 255));
+}
+#endif
+
+int conv_rgb565_to_rgb888(unsigned short rgb565, unsigned int sw)
+{
+       char red, green, blue;
+       unsigned int threshold = 150;
+
+       red = (rgb565 & 0xF800) >> 11;
+       green = (rgb565 & 0x7E0) >> 5;
+       blue = (rgb565 & 0x1F);
+
+       red = red << 3;
+       green = green << 2;
+       blue = blue << 3;
+
+       /* correct error pixels of samsung logo. */
+       if (sw) {
+               if (red > threshold)
+                       red = 255;
+               if (green > threshold)
+                       green = 255;
+               if (blue > threshold)
+                       blue = 255;
+       }
+
+       return (red << 16 | green << 8 | blue);
 }
 
 void draw_bitmap(void *lcdbase, int x, int y, int w, int h, unsigned long *bmp)
 {
-       int i, j, k = 0;
+       int i, j;
+       short k = 0;
        unsigned long *fb = (unsigned  long*)lcdbase;
 
        for (j = y; j < (y + h); j++) {
                for (i = x; i < (x + w); i++)
-                       *(fb + (j * PANEL_WIDTH) + i) = *(bmp + k++);
+                       *(fb + (j * panel_width) + i) = *(bmp + k++);
        }
 }
 
-static void draw_samsung_logo(void* lcdbase)
+void _draw_samsung_logo(void *lcdbase, int x, int y, int w, int h, unsigned short *bmp)
 {
-       int x, y;
+       int i, j, error_range = 40;
+       short k = 0;
+       unsigned int pixel;
+       unsigned long *fb = (unsigned  long*)lcdbase;
 
-       x = (PANEL_WIDTH - 138) / 2;
-       y = (PANEL_HEIGHT - 28) / 2 - 5;
+       for (j = y; j < (y + h); j++) {
+               for (i = x; i < (x + w); i++) {
+                       pixel = (*(bmp + k++));
+
+                       /* 40 lines under samsung logo image are error range. */
+                       if (j > h + y - error_range)
+                               *(fb + (j * panel_width) + i) =
+                                       conv_rgb565_to_rgb888(pixel, 1);
+                       else
+                               *(fb + (j * panel_width) + i) =
+                                       conv_rgb565_to_rgb888(pixel, 0);
+               }
+       }
+}
 
-       draw_bitmap(lcdbase, x, y, 138, 28, (unsigned long *)opening_32);
+static void draw_samsung_logo(void* lcdbase)
+{
+       int x, y;
+       unsigned int in_len, width, height;
+       unsigned long out_len;
+       void *dst = NULL;
+       width = 298;
+       height = 78;
+       x = ((panel_width - width) >> 1);
+       y = ((panel_height - height) >> 1) - 5;
+
+       in_len = width * height * 4;
+       dst = malloc(in_len);
+       if (dst == NULL) {
+               printf("Error: malloc in gunzip failed!\n");
+               return;
+       }
+       if (gunzip(dst, in_len, (uchar *)logo, &out_len) != 0) {
+               free(dst);
+               return;
+       }
+       if (out_len == CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)
+               printf("Image could be truncated"
+                               " (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n");
+       _draw_samsung_logo(lcdbase, x, y, width, height, (unsigned short *) dst);
+       free(dst);
 }
 
-static void lcd_panel_on(void)
+static void lcd_panel_on(vidinfo_t *vid)
 {
-       lcd_panel_init();
-       lcd_panel_power_on();
+       udelay(vid->init_delay);
+
+       if (vid->cfg_gpio)
+               vid->cfg_gpio();
+
+       if (vid->lcd_power_on)
+               vid->lcd_power_on(1);
+
+       udelay(vid->power_on_delay);
+
+       if (vid->reset_lcd)
+               vid->reset_lcd();
+
+       udelay(vid->reset_delay);
+
+       if (vid->backlight_on)
+               vid->backlight_on(1);
+
+
+       if (vid->cfg_ldo)
+               vid->cfg_ldo();
+
+
+       if (vid->enable_ldo)
+               vid->enable_ldo(1);
 
-       lcd_panel_enable();
 }
 
+/* extern void init_onenand_ext2(void); */
+extern void init_panel_info(vidinfo_t *vid);
+extern int s5p_no_lcd_support(void);
+
 void lcd_ctrl_init(void *lcdbase)
 {
        char *option;
 
+       if (s5p_no_lcd_support())
+               return;
+
        s5pc_lcd_init_mem(lcdbase, &panel_info);
 
+       /* initialize parameters which is specific to panel. */
+       init_panel_info(&panel_info);
+
+       panel_width = panel_info.vl_width;
+       panel_height = panel_info.vl_height;
+
        option = getenv("lcd");
 
        /*
        if (strcmp(option, "test") == 0) {
                memset(lcdbase, 0, PANEL_WIDTH*PANEL_HEIGHT*S5P_LCD_BPP >> 3);
-               lcd_test();
+#ifdef USE_LCD_TEST
+               lcd_test(panel_width, panel_height);
+#endif
        } else if (strcmp(option, "image") == 0)
                memcpy(lcdbase, LOGO_RGB24, PANEL_WIDTH*PANEL_HEIGHT*S5P_LCD_BPP >> 3);
        else {
@@ -222,11 +290,9 @@ void lcd_ctrl_init(void *lcdbase)
        }
        */
 
-       memset(lcdbase, 0, PANEL_WIDTH*PANEL_HEIGHT*S5P_LCD_BPP >> 3);
+       memset(lcdbase, 0, panel_width * panel_height * (32 >> 3));
        draw_samsung_logo(lcdbase);
 
-       s5pc_gpio_setup();
-
        s5pc_lcd_init(&panel_info);
 
        /* font test */
@@ -236,6 +302,8 @@ void lcd_ctrl_init(void *lcdbase)
        fb_printf("Test\n");
        exit_font();
        */
+
+       /* init_onenand_ext2(); */
 }
 
 
@@ -246,7 +314,7 @@ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blud)
 
 void lcd_enable(void)
 {
-       lcd_panel_on();
+       lcd_panel_on(&panel_info);
 }
 
 ulong calc_fbsize(void)
@@ -258,6 +326,4 @@ void s5pc1xxfb_test(void *lcdbase)
 {
        lcd_ctrl_init(lcdbase);
        lcd_enable();
-
-       //memcpy(lcdbase, LOGO_RGB24, PANEL_WIDTH*PANEL_HEIGHT*S5P_LCD_BPP >> 3);
 }