video: fsl_dcu_fb: add additional modes for DCU
[oweals/u-boot.git] / drivers / video / fsl_dcu_fb.c
index d4cd38277669cf7495022ca51b87806c83e06093..01e4a409b6759d8ceecfa8ee5b1aa369f5d84856 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <asm/io.h>
 #include <common.h>
+#include <fdt_support.h>
 #include <fsl_dcu_fb.h>
 #include <linux/fb.h>
 #include <malloc.h>
@@ -40,7 +41,7 @@
 #define DCU_VSYN_PARA_BP(x)            ((x) << 22)
 #define DCU_VSYN_PARA_PW(x)            ((x) << 11)
 #define DCU_VSYN_PARA_FP(x)            (x)
-#define DCU_SYN_POL_INV_PXCK_FALL      (0 << 6)
+#define DCU_SYN_POL_INV_PXCK_FALL      (1 << 6)
 #define DCU_SYN_POL_NEG_REMAIN         (0 << 5)
 #define DCU_SYN_POL_INV_VS_LOW         (1 << 1)
 #define DCU_SYN_POL_INV_HS_LOW         (1)
@@ -79,6 +80,8 @@
 #define BPP_24_RGB888                  5
 #define BPP_32_ARGB8888                        6
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /*
  * This setting is used for the TWR_LCD_RGB card
  */
@@ -101,7 +104,7 @@ static struct fb_videomode fsl_dcu_mode_480_272 = {
 /*
  * This setting is used for Siliconimage SiI9022A HDMI
  */
-static struct fb_videomode fsl_dcu_mode_640_480 = {
+static struct fb_videomode fsl_dcu_cea_mode_640_480 = {
        .name           = "640x480-60",
        .refresh        = 60,
        .xres           = 640,
@@ -117,6 +120,54 @@ static struct fb_videomode fsl_dcu_mode_640_480 = {
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
+static struct fb_videomode fsl_dcu_mode_640_480 = {
+       .name           = "640x480-60",
+       .refresh        = 60,
+       .xres           = 640,
+       .yres           = 480,
+       .pixclock       = 25175,
+       .left_margin    = 40,
+       .right_margin   = 24,
+       .upper_margin   = 32,
+       .lower_margin   = 11,
+       .hsync_len      = 96,
+       .vsync_len      = 2,
+       .sync           = 0,
+       .vmode          = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_videomode fsl_dcu_mode_800_480 = {
+       .name           = "800x480-60",
+       .refresh        = 60,
+       .xres           = 800,
+       .yres           = 480,
+       .pixclock       = 33260,
+       .left_margin    = 216,
+       .right_margin   = 40,
+       .upper_margin   = 35,
+       .lower_margin   = 10,
+       .hsync_len      = 128,
+       .vsync_len      = 2,
+       .sync           = 0,
+       .vmode          = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_videomode fsl_dcu_mode_1024_600 = {
+       .name           = "1024x600-60",
+       .refresh        = 60,
+       .xres           = 1024,
+       .yres           = 600,
+       .pixclock       = 48000,
+       .left_margin    = 104,
+       .right_margin   = 43,
+       .upper_margin   = 24,
+       .lower_margin   = 20,
+       .hsync_len      = 5,
+       .vsync_len      = 5,
+       .sync           = 0,
+       .vmode          = FB_VMODE_NONINTERLACED,
+};
+
 /*
  * DCU register map
  */
@@ -188,8 +239,6 @@ static void reset_total_layers(void)
                dcu_write32(&regs->ctrldescl[i][9], 0);
                dcu_write32(&regs->ctrldescl[i][10], 0);
        }
-
-       dcu_write32(&regs->update_mode, DCU_UPDATE_MODE_READREG);
 }
 
 static int layer_ctrldesc_init(int index, u32 pixel_format)
@@ -243,8 +292,6 @@ static int layer_ctrldesc_init(int index, u32 pixel_format)
        dcu_write32(&regs->ctrldescl[index][7], DCU_CTRLDESCLN_8_FG_FCOLOR(0));
        dcu_write32(&regs->ctrldescl[index][8], DCU_CTRLDESCLN_9_BG_BCOLOR(0));
 
-       dcu_write32(&regs->update_mode, DCU_UPDATE_MODE_READREG);
-
        return 0;
 }
 
@@ -254,16 +301,22 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres,
        struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR;
        unsigned int div, mode;
 
-       /* Memory allocation for framebuffer */
        info.screen_size =
                info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
-       info.screen_base = (char *)memalign(ARCH_DMA_MINALIGN,
-                       roundup(info.screen_size, ARCH_DMA_MINALIGN));
+
+       if (info.screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) {
+               info.screen_size = 0;
+               return -ENOMEM;
+       }
+
+       /* Reserve framebuffer at the end of memory */
+       gd->fb_base = gd->bd->bi_dram[0].start +
+                       gd->bd->bi_dram[0].size - info.screen_size;
+       info.screen_base = (char *)gd->fb_base;
+
        memset(info.screen_base, 0, info.screen_size);
 
        reset_total_layers();
-       div = dcu_set_pixel_clock(info.var.pixclock);
-       dcu_write32(&regs->div_ratio, (div - 1));
 
        dcu_write32(&regs->disp_size,
                    DCU_DISP_SIZE_DELTA_Y(info.var.yres) |
@@ -289,7 +342,7 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres,
                    DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0));
 
        dcu_write32(&regs->mode,
-                   DCU_MODE_BLEND_ITER(DCU_LAYER_MAX_NUM) |
+                   DCU_MODE_BLEND_ITER(2) |
                    DCU_MODE_RASTER_EN);
 
        dcu_write32(&regs->threshold,
@@ -302,9 +355,19 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres,
 
        layer_ctrldesc_init(0, pixel_format);
 
+       div = dcu_set_pixel_clock(info.var.pixclock);
+       dcu_write32(&regs->div_ratio, (div - 1));
+
+       dcu_write32(&regs->update_mode, DCU_UPDATE_MODE_READREG);
+
        return 0;
 }
 
+ulong board_get_usable_ram_top(ulong total_size)
+{
+       return gd->ram_top - CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB;
+}
+
 void *video_hw_init(void)
 {
        static GraphicDevice ctfb;
@@ -327,7 +390,16 @@ void *video_hw_init(void)
                fsl_dcu_mode_db = &fsl_dcu_mode_480_272;
                break;
        case RESOLUTION(640, 480):
-               fsl_dcu_mode_db = &fsl_dcu_mode_640_480;
+               if (!strncmp(options, "monitor=hdmi", 12))
+                       fsl_dcu_mode_db = &fsl_dcu_cea_mode_640_480;
+               else
+                       fsl_dcu_mode_db = &fsl_dcu_mode_640_480;
+               break;
+       case RESOLUTION(800, 480):
+               fsl_dcu_mode_db = &fsl_dcu_mode_800_480;
+               break;
+       case RESOLUTION(1024, 600):
+               fsl_dcu_mode_db = &fsl_dcu_mode_1024_600;
                break;
        default:
                printf("unsupported resolution %ux%u\n",
@@ -363,3 +435,26 @@ void *video_hw_init(void)
 
        return &ctfb;
 }
+
+#if defined(CONFIG_OF_BOARD_SETUP)
+int fsl_dcu_fixedfb_setup(void *blob)
+{
+       u64 start, size;
+       int ret;
+
+       start = gd->bd->bi_dram[0].start;
+       size = gd->bd->bi_dram[0].size - info.screen_size;
+
+       /*
+        * Align size on section size (1 MiB).
+        */
+       size &= 0xfff00000;
+       ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
+       if (ret) {
+               eprintf("Cannot setup fb: Error reserving memory\n");
+               return ret;
+       }
+
+       return 0;
+}
+#endif