uboot/drivers/video/fsl_dcu_fb.c
<<
>>
Prefs
   1/*
   2 * Copyright 2014 Freescale Semiconductor, Inc.
   3 *
   4 * FSL DCU Framebuffer driver
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <asm/io.h>
  10#include <common.h>
  11#include <fdt_support.h>
  12#include <fsl_dcu_fb.h>
  13#include <linux/fb.h>
  14#include <malloc.h>
  15#include <video_fb.h>
  16#include "videomodes.h"
  17
  18/* Convert the X,Y resolution pair into a single number */
  19#define RESOLUTION(x, y) (((u32)(x) << 16) | (y))
  20
  21#ifdef CONFIG_SYS_FSL_DCU_LE
  22#define dcu_read32      in_le32
  23#define dcu_write32     out_le32
  24#elif defined(CONFIG_SYS_FSL_DCU_BE)
  25#define dcu_read32      in_be32
  26#define dcu_write32     out_be32
  27#endif
  28
  29#define DCU_MODE_BLEND_ITER(x)          ((x) << 20)
  30#define DCU_MODE_RASTER_EN              (1 << 14)
  31#define DCU_MODE_NORMAL                 1
  32#define DCU_MODE_COLORBAR               3
  33#define DCU_BGND_R(x)                   ((x) << 16)
  34#define DCU_BGND_G(x)                   ((x) << 8)
  35#define DCU_BGND_B(x)                   (x)
  36#define DCU_DISP_SIZE_DELTA_Y(x)        ((x) << 16)
  37#define DCU_DISP_SIZE_DELTA_X(x)        (x)
  38#define DCU_HSYN_PARA_BP(x)             ((x) << 22)
  39#define DCU_HSYN_PARA_PW(x)             ((x) << 11)
  40#define DCU_HSYN_PARA_FP(x)             (x)
  41#define DCU_VSYN_PARA_BP(x)             ((x) << 22)
  42#define DCU_VSYN_PARA_PW(x)             ((x) << 11)
  43#define DCU_VSYN_PARA_FP(x)             (x)
  44#define DCU_SYN_POL_INV_PXCK_FALL       (1 << 6)
  45#define DCU_SYN_POL_NEG_REMAIN          (0 << 5)
  46#define DCU_SYN_POL_INV_VS_LOW          (1 << 1)
  47#define DCU_SYN_POL_INV_HS_LOW          (1)
  48#define DCU_THRESHOLD_LS_BF_VS(x)       ((x) << 16)
  49#define DCU_THRESHOLD_OUT_BUF_HIGH(x)   ((x) << 8)
  50#define DCU_THRESHOLD_OUT_BUF_LOW(x)    (x)
  51#define DCU_UPDATE_MODE_MODE            (1 << 31)
  52#define DCU_UPDATE_MODE_READREG         (1 << 30)
  53
  54#define DCU_CTRLDESCLN_1_HEIGHT(x)      ((x) << 16)
  55#define DCU_CTRLDESCLN_1_WIDTH(x)       (x)
  56#define DCU_CTRLDESCLN_2_POSY(x)        ((x) << 16)
  57#define DCU_CTRLDESCLN_2_POSX(x)        (x)
  58#define DCU_CTRLDESCLN_4_EN             (1 << 31)
  59#define DCU_CTRLDESCLN_4_TILE_EN        (1 << 30)
  60#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT  (1 << 29)
  61#define DCU_CTRLDESCLN_4_SAFETY_EN      (1 << 28)
  62#define DCU_CTRLDESCLN_4_TRANS(x)       ((x) << 20)
  63#define DCU_CTRLDESCLN_4_BPP(x)         ((x) << 16)
  64#define DCU_CTRLDESCLN_4_RLE_EN         (1 << 15)
  65#define DCU_CTRLDESCLN_4_LUOFFS(x)      ((x) << 4)
  66#define DCU_CTRLDESCLN_4_BB_ON          (1 << 2)
  67#define DCU_CTRLDESCLN_4_AB(x)          (x)
  68#define DCU_CTRLDESCLN_5_CKMAX_R(x)     ((x) << 16)
  69#define DCU_CTRLDESCLN_5_CKMAX_G(x)     ((x) << 8)
  70#define DCU_CTRLDESCLN_5_CKMAX_B(x)     (x)
  71#define DCU_CTRLDESCLN_6_CKMIN_R(x)     ((x) << 16)
  72#define DCU_CTRLDESCLN_6_CKMIN_G(x)     ((x) << 8)
  73#define DCU_CTRLDESCLN_6_CKMIN_B(x)     (x)
  74#define DCU_CTRLDESCLN_7_TILE_VER(x)    ((x) << 16)
  75#define DCU_CTRLDESCLN_7_TILE_HOR(x)    (x)
  76#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)   (x)
  77#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)   (x)
  78
  79#define BPP_16_RGB565                   4
  80#define BPP_24_RGB888                   5
  81#define BPP_32_ARGB8888                 6
  82
  83DECLARE_GLOBAL_DATA_PTR;
  84
  85/*
  86 * This setting is used for the TWR_LCD_RGB card
  87 */
  88static struct fb_videomode fsl_dcu_mode_480_272 = {
  89        .name           = "480x272-60",
  90        .refresh        = 60,
  91        .xres           = 480,
  92        .yres           = 272,
  93        .pixclock       = 91996,
  94        .left_margin    = 2,
  95        .right_margin   = 2,
  96        .upper_margin   = 1,
  97        .lower_margin   = 1,
  98        .hsync_len      = 41,
  99        .vsync_len      = 2,
 100        .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 101        .vmode          = FB_VMODE_NONINTERLACED
 102};
 103
 104/*
 105 * This setting is used for Siliconimage SiI9022A HDMI
 106 */
 107static struct fb_videomode fsl_dcu_cea_mode_640_480 = {
 108        .name           = "640x480-60",
 109        .refresh        = 60,
 110        .xres           = 640,
 111        .yres           = 480,
 112        .pixclock       = 39722,
 113        .left_margin    = 48,
 114        .right_margin   = 16,
 115        .upper_margin   = 33,
 116        .lower_margin   = 10,
 117        .hsync_len      = 96,
 118        .vsync_len      = 2,
 119        .sync           = 0,
 120        .vmode          = FB_VMODE_NONINTERLACED,
 121};
 122
 123static struct fb_videomode fsl_dcu_mode_640_480 = {
 124        .name           = "640x480-60",
 125        .refresh        = 60,
 126        .xres           = 640,
 127        .yres           = 480,
 128        .pixclock       = 25175,
 129        .left_margin    = 40,
 130        .right_margin   = 24,
 131        .upper_margin   = 32,
 132        .lower_margin   = 11,
 133        .hsync_len      = 96,
 134        .vsync_len      = 2,
 135        .sync           = 0,
 136        .vmode          = FB_VMODE_NONINTERLACED,
 137};
 138
 139static struct fb_videomode fsl_dcu_mode_800_480 = {
 140        .name           = "800x480-60",
 141        .refresh        = 60,
 142        .xres           = 800,
 143        .yres           = 480,
 144        .pixclock       = 33260,
 145        .left_margin    = 216,
 146        .right_margin   = 40,
 147        .upper_margin   = 35,
 148        .lower_margin   = 10,
 149        .hsync_len      = 128,
 150        .vsync_len      = 2,
 151        .sync           = 0,
 152        .vmode          = FB_VMODE_NONINTERLACED,
 153};
 154
 155static struct fb_videomode fsl_dcu_mode_1024_600 = {
 156        .name           = "1024x600-60",
 157        .refresh        = 60,
 158        .xres           = 1024,
 159        .yres           = 600,
 160        .pixclock       = 48000,
 161        .left_margin    = 104,
 162        .right_margin   = 43,
 163        .upper_margin   = 24,
 164        .lower_margin   = 20,
 165        .hsync_len      = 5,
 166        .vsync_len      = 5,
 167        .sync           = 0,
 168        .vmode          = FB_VMODE_NONINTERLACED,
 169};
 170
 171/*
 172 * DCU register map
 173 */
 174struct dcu_reg {
 175        u32 desc_cursor[4];
 176        u32 mode;
 177        u32 bgnd;
 178        u32 disp_size;
 179        u32 hsyn_para;
 180        u32 vsyn_para;
 181        u32 synpol;
 182        u32 threshold;
 183        u32 int_status;
 184        u32 int_mask;
 185        u32 colbar[8];
 186        u32 div_ratio;
 187        u32 sign_calc[2];
 188        u32 crc_val;
 189        u8 res_064[0x6c-0x64];
 190        u32 parr_err_status1;
 191        u8 res_070[0x7c-0x70];
 192        u32 parr_err_status3;
 193        u32 mparr_err_status1;
 194        u8 res_084[0x90-0x84];
 195        u32 mparr_err_status3;
 196        u32 threshold_inp_buf[2];
 197        u8 res_09c[0xa0-0x9c];
 198        u32 luma_comp;
 199        u32 chroma_red;
 200        u32 chroma_green;
 201        u32 chroma_blue;
 202        u32 crc_pos;
 203        u32 lyr_intpol_en;
 204        u32 lyr_luma_comp;
 205        u32 lyr_chrm_red;
 206        u32 lyr_chrm_grn;
 207        u32 lyr_chrm_blue;
 208        u8 res_0c4[0xcc-0xc8];
 209        u32 update_mode;
 210        u32 underrun;
 211        u8 res_0d4[0x100-0xd4];
 212        u32 gpr;
 213        u32 slr_l[2];
 214        u32 slr_disp_size;
 215        u32 slr_hvsync_para;
 216        u32 slr_pol;
 217        u32 slr_l_transp[2];
 218        u8 res_120[0x200-0x120];
 219        u32 ctrldescl[DCU_LAYER_MAX_NUM][16];
 220};
 221
 222static struct fb_info info;
 223
 224static void reset_total_layers(void)
 225{
 226        struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR;
 227        int i;
 228
 229        for (i = 0; i < DCU_LAYER_MAX_NUM; i++) {
 230                dcu_write32(&regs->ctrldescl[i][0], 0);
 231                dcu_write32(&regs->ctrldescl[i][1], 0);
 232                dcu_write32(&regs->ctrldescl[i][2], 0);
 233                dcu_write32(&regs->ctrldescl[i][3], 0);
 234                dcu_write32(&regs->ctrldescl[i][4], 0);
 235                dcu_write32(&regs->ctrldescl[i][5], 0);
 236                dcu_write32(&regs->ctrldescl[i][6], 0);
 237                dcu_write32(&regs->ctrldescl[i][7], 0);
 238                dcu_write32(&regs->ctrldescl[i][8], 0);
 239                dcu_write32(&regs->ctrldescl[i][9], 0);
 240                dcu_write32(&regs->ctrldescl[i][10], 0);
 241        }
 242}
 243
 244static int layer_ctrldesc_init(int index, u32 pixel_format)
 245{
 246        struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR;
 247        unsigned int bpp = BPP_24_RGB888;
 248
 249        dcu_write32(&regs->ctrldescl[index][0],
 250                    DCU_CTRLDESCLN_1_HEIGHT(info.var.yres) |
 251                    DCU_CTRLDESCLN_1_WIDTH(info.var.xres));
 252
 253        dcu_write32(&regs->ctrldescl[index][1],
 254                    DCU_CTRLDESCLN_2_POSY(0) |
 255                    DCU_CTRLDESCLN_2_POSX(0));
 256
 257        dcu_write32(&regs->ctrldescl[index][2], (unsigned int)info.screen_base);
 258
 259        switch (pixel_format) {
 260        case 16:
 261                bpp = BPP_16_RGB565;
 262                break;
 263        case 24:
 264                bpp = BPP_24_RGB888;
 265                break;
 266        case 32:
 267                bpp = BPP_32_ARGB8888;
 268                break;
 269        default:
 270                printf("unsupported color depth: %u\n", pixel_format);
 271        }
 272
 273        dcu_write32(&regs->ctrldescl[index][3],
 274                    DCU_CTRLDESCLN_4_EN |
 275                    DCU_CTRLDESCLN_4_TRANS(0xff) |
 276                    DCU_CTRLDESCLN_4_BPP(bpp) |
 277                    DCU_CTRLDESCLN_4_AB(0));
 278
 279        dcu_write32(&regs->ctrldescl[index][4],
 280                    DCU_CTRLDESCLN_5_CKMAX_R(0xff) |
 281                    DCU_CTRLDESCLN_5_CKMAX_G(0xff) |
 282                    DCU_CTRLDESCLN_5_CKMAX_B(0xff));
 283        dcu_write32(&regs->ctrldescl[index][5],
 284                    DCU_CTRLDESCLN_6_CKMIN_R(0) |
 285                    DCU_CTRLDESCLN_6_CKMIN_G(0) |
 286                    DCU_CTRLDESCLN_6_CKMIN_B(0));
 287
 288        dcu_write32(&regs->ctrldescl[index][6],
 289                    DCU_CTRLDESCLN_7_TILE_VER(0) |
 290                    DCU_CTRLDESCLN_7_TILE_HOR(0));
 291
 292        dcu_write32(&regs->ctrldescl[index][7], DCU_CTRLDESCLN_8_FG_FCOLOR(0));
 293        dcu_write32(&regs->ctrldescl[index][8], DCU_CTRLDESCLN_9_BG_BCOLOR(0));
 294
 295        return 0;
 296}
 297
 298int fsl_dcu_init(unsigned int xres, unsigned int yres,
 299                 unsigned int pixel_format)
 300{
 301        struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR;
 302        unsigned int div, mode;
 303
 304        info.screen_size =
 305                info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
 306
 307        if (info.screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) {
 308                info.screen_size = 0;
 309                return -ENOMEM;
 310        }
 311
 312        /* Reserve framebuffer at the end of memory */
 313        gd->fb_base = gd->bd->bi_dram[0].start +
 314                        gd->bd->bi_dram[0].size - info.screen_size;
 315        info.screen_base = (char *)gd->fb_base;
 316
 317        memset(info.screen_base, 0, info.screen_size);
 318
 319        reset_total_layers();
 320
 321        dcu_write32(&regs->disp_size,
 322                    DCU_DISP_SIZE_DELTA_Y(info.var.yres) |
 323                    DCU_DISP_SIZE_DELTA_X(info.var.xres / 16));
 324
 325        dcu_write32(&regs->hsyn_para,
 326                    DCU_HSYN_PARA_BP(info.var.left_margin) |
 327                    DCU_HSYN_PARA_PW(info.var.hsync_len) |
 328                    DCU_HSYN_PARA_FP(info.var.right_margin));
 329
 330        dcu_write32(&regs->vsyn_para,
 331                    DCU_VSYN_PARA_BP(info.var.upper_margin) |
 332                    DCU_VSYN_PARA_PW(info.var.vsync_len) |
 333                    DCU_VSYN_PARA_FP(info.var.lower_margin));
 334
 335        dcu_write32(&regs->synpol,
 336                    DCU_SYN_POL_INV_PXCK_FALL |
 337                    DCU_SYN_POL_NEG_REMAIN |
 338                    DCU_SYN_POL_INV_VS_LOW |
 339                    DCU_SYN_POL_INV_HS_LOW);
 340
 341        dcu_write32(&regs->bgnd,
 342                    DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0));
 343
 344        dcu_write32(&regs->mode,
 345                    DCU_MODE_BLEND_ITER(2) |
 346                    DCU_MODE_RASTER_EN);
 347
 348        dcu_write32(&regs->threshold,
 349                    DCU_THRESHOLD_LS_BF_VS(0x3) |
 350                    DCU_THRESHOLD_OUT_BUF_HIGH(0x78) |
 351                    DCU_THRESHOLD_OUT_BUF_LOW(0));
 352
 353        mode = dcu_read32(&regs->mode);
 354        dcu_write32(&regs->mode, mode | DCU_MODE_NORMAL);
 355
 356        layer_ctrldesc_init(0, pixel_format);
 357
 358        div = dcu_set_pixel_clock(info.var.pixclock);
 359        dcu_write32(&regs->div_ratio, (div - 1));
 360
 361        dcu_write32(&regs->update_mode, DCU_UPDATE_MODE_READREG);
 362
 363        return 0;
 364}
 365
 366ulong board_get_usable_ram_top(ulong total_size)
 367{
 368        return gd->ram_top - CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB;
 369}
 370
 371void *video_hw_init(void)
 372{
 373        static GraphicDevice ctfb;
 374        const char *options;
 375        unsigned int depth = 0, freq = 0;
 376        struct fb_videomode *fsl_dcu_mode_db = &fsl_dcu_mode_480_272;
 377
 378        if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq,
 379                                  &options))
 380                return NULL;
 381
 382        /* Find the monitor port, which is a required option */
 383        if (!options)
 384                return NULL;
 385        if (strncmp(options, "monitor=", 8) != 0)
 386                return NULL;
 387
 388        switch (RESOLUTION(ctfb.winSizeX, ctfb.winSizeY)) {
 389        case RESOLUTION(480, 272):
 390                fsl_dcu_mode_db = &fsl_dcu_mode_480_272;
 391                break;
 392        case RESOLUTION(640, 480):
 393                if (!strncmp(options, "monitor=hdmi", 12))
 394                        fsl_dcu_mode_db = &fsl_dcu_cea_mode_640_480;
 395                else
 396                        fsl_dcu_mode_db = &fsl_dcu_mode_640_480;
 397                break;
 398        case RESOLUTION(800, 480):
 399                fsl_dcu_mode_db = &fsl_dcu_mode_800_480;
 400                break;
 401        case RESOLUTION(1024, 600):
 402                fsl_dcu_mode_db = &fsl_dcu_mode_1024_600;
 403                break;
 404        default:
 405                printf("unsupported resolution %ux%u\n",
 406                       ctfb.winSizeX, ctfb.winSizeY);
 407        }
 408
 409        info.var.xres = fsl_dcu_mode_db->xres;
 410        info.var.yres = fsl_dcu_mode_db->yres;
 411        info.var.bits_per_pixel = 32;
 412        info.var.pixclock = fsl_dcu_mode_db->pixclock;
 413        info.var.left_margin = fsl_dcu_mode_db->left_margin;
 414        info.var.right_margin = fsl_dcu_mode_db->right_margin;
 415        info.var.upper_margin = fsl_dcu_mode_db->upper_margin;
 416        info.var.lower_margin = fsl_dcu_mode_db->lower_margin;
 417        info.var.hsync_len = fsl_dcu_mode_db->hsync_len;
 418        info.var.vsync_len = fsl_dcu_mode_db->vsync_len;
 419        info.var.sync = fsl_dcu_mode_db->sync;
 420        info.var.vmode = fsl_dcu_mode_db->vmode;
 421        info.fix.line_length = info.var.xres * info.var.bits_per_pixel / 8;
 422
 423        if (platform_dcu_init(ctfb.winSizeX, ctfb.winSizeY,
 424                              options + 8, fsl_dcu_mode_db) < 0)
 425                return NULL;
 426
 427        ctfb.frameAdrs = (unsigned int)info.screen_base;
 428        ctfb.plnSizeX = ctfb.winSizeX;
 429        ctfb.plnSizeY = ctfb.winSizeY;
 430
 431        ctfb.gdfBytesPP = 4;
 432        ctfb.gdfIndex = GDF_32BIT_X888RGB;
 433
 434        ctfb.memSize = info.screen_size;
 435
 436        return &ctfb;
 437}
 438
 439#if defined(CONFIG_OF_BOARD_SETUP)
 440int fsl_dcu_fixedfb_setup(void *blob)
 441{
 442        u64 start, size;
 443        int ret;
 444
 445        start = gd->bd->bi_dram[0].start;
 446        size = gd->bd->bi_dram[0].size - info.screen_size;
 447
 448        /*
 449         * Align size on section size (1 MiB).
 450         */
 451        size &= 0xfff00000;
 452        ret = fdt_fixup_memory_banks(blob, &start, &size, 1);
 453        if (ret) {
 454                eprintf("Cannot setup fb: Error reserving memory\n");
 455                return ret;
 456        }
 457
 458        return 0;
 459}
 460#endif
 461