uboot/drivers/video/fsl_diu_fb.c
<<
>>
Prefs
   1/*
   2 * Copyright 2007, 2010-2011 Freescale Semiconductor, Inc.
   3 * Authors: York Sun <yorksun@freescale.com>
   4 *          Timur Tabi <timur@freescale.com>
   5 *
   6 * FSL DIU Framebuffer driver
   7 *
   8 * See file CREDITS for list of people who contributed to this
   9 * project.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License as
  13 * published by the Free Software Foundation; either version 2 of
  14 * the License, or (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24 * MA 02111-1307 USA
  25 */
  26
  27#include <common.h>
  28#include <malloc.h>
  29#include <asm/io.h>
  30
  31#include "videomodes.h"
  32#include <video_fb.h>
  33#include <fsl_diu_fb.h>
  34
  35struct fb_var_screeninfo {
  36        unsigned int xres;              /* visible resolution           */
  37        unsigned int yres;
  38
  39        unsigned int bits_per_pixel;    /* guess what                   */
  40
  41        /* Timing: All values in pixclocks, except pixclock (of course) */
  42        unsigned int pixclock;          /* pixel clock in ps (pico seconds) */
  43        unsigned int left_margin;       /* time from sync to picture    */
  44        unsigned int right_margin;      /* time from picture to sync    */
  45        unsigned int upper_margin;      /* time from sync to picture    */
  46        unsigned int lower_margin;
  47        unsigned int hsync_len;         /* length of horizontal sync    */
  48        unsigned int vsync_len;         /* length of vertical sync      */
  49        unsigned int sync;              /* see FB_SYNC_*                */
  50        unsigned int vmode;             /* see FB_VMODE_*               */
  51        unsigned int rotate;            /* angle we rotate counter clockwise */
  52};
  53
  54struct fb_info {
  55        struct fb_var_screeninfo var;   /* Current var */
  56        unsigned int smem_len;          /* Length of frame buffer mem */
  57        unsigned int type;              /* see FB_TYPE_*                */
  58        unsigned int line_length;       /* length of a line in bytes    */
  59
  60        void *screen_base;
  61        unsigned long screen_size;
  62};
  63
  64struct fb_videomode {
  65        const char *name;       /* optional */
  66        unsigned int refresh;           /* optional */
  67        unsigned int xres;
  68        unsigned int yres;
  69        unsigned int pixclock;
  70        unsigned int left_margin;
  71        unsigned int right_margin;
  72        unsigned int upper_margin;
  73        unsigned int lower_margin;
  74        unsigned int hsync_len;
  75        unsigned int vsync_len;
  76        unsigned int sync;
  77        unsigned int vmode;
  78        unsigned int flag;
  79};
  80
  81#define FB_SYNC_VERT_HIGH_ACT   2       /* vertical sync high active    */
  82#define FB_SYNC_COMP_HIGH_ACT   8       /* composite sync high active   */
  83#define FB_VMODE_NONINTERLACED  0       /* non interlaced */
  84
  85/* This setting is used for the ifm pdm360ng with PRIMEVIEW PM070WL3 */
  86static struct fb_videomode fsl_diu_mode_800 = {
  87        .name           = "800x600-60",
  88        .refresh        = 60,
  89        .xres           = 800,
  90        .yres           = 480,
  91        .pixclock       = 31250,
  92        .left_margin    = 86,
  93        .right_margin   = 42,
  94        .upper_margin   = 33,
  95        .lower_margin   = 10,
  96        .hsync_len      = 128,
  97        .vsync_len      = 2,
  98        .sync           = 0,
  99        .vmode          = FB_VMODE_NONINTERLACED
 100};
 101
 102/*
 103 * These parameters give default parameters
 104 * for video output 1024x768,
 105 * FIXME - change timing to proper amounts
 106 * hsync 31.5kHz, vsync 60Hz
 107 */
 108static struct fb_videomode fsl_diu_mode_1024 = {
 109        .name           = "1024x768-60",
 110        .refresh        = 60,
 111        .xres           = 1024,
 112        .yres           = 768,
 113        .pixclock       = 15385,
 114        .left_margin    = 160,
 115        .right_margin   = 24,
 116        .upper_margin   = 29,
 117        .lower_margin   = 3,
 118        .hsync_len      = 136,
 119        .vsync_len      = 6,
 120        .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 121        .vmode          = FB_VMODE_NONINTERLACED
 122};
 123
 124static struct fb_videomode fsl_diu_mode_1280 = {
 125        .name           = "1280x1024-60",
 126        .refresh        = 60,
 127        .xres           = 1280,
 128        .yres           = 1024,
 129        .pixclock       = 9375,
 130        .left_margin    = 38,
 131        .right_margin   = 128,
 132        .upper_margin   = 2,
 133        .lower_margin   = 7,
 134        .hsync_len      = 216,
 135        .vsync_len      = 37,
 136        .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 137        .vmode          = FB_VMODE_NONINTERLACED
 138};
 139
 140/*
 141 * These are the fields of area descriptor(in DDR memory) for every plane
 142 */
 143struct diu_ad {
 144        /* Word 0(32-bit) in DDR memory */
 145        __le32 pix_fmt; /* hard coding pixel format */
 146        /* Word 1(32-bit) in DDR memory */
 147        __le32 addr;
 148        /* Word 2(32-bit) in DDR memory */
 149        __le32 src_size_g_alpha;
 150        /* Word 3(32-bit) in DDR memory */
 151        __le32 aoi_size;
 152        /* Word 4(32-bit) in DDR memory */
 153        __le32 offset_xyi;
 154        /* Word 5(32-bit) in DDR memory */
 155        __le32 offset_xyd;
 156        /* Word 6(32-bit) in DDR memory */
 157        __le32 ckmax_r:8;
 158        __le32 ckmax_g:8;
 159        __le32 ckmax_b:8;
 160        __le32 res9:8;
 161        /* Word 7(32-bit) in DDR memory */
 162        __le32 ckmin_r:8;
 163        __le32 ckmin_g:8;
 164        __le32 ckmin_b:8;
 165        __le32 res10:8;
 166        /* Word 8(32-bit) in DDR memory */
 167        __le32 next_ad;
 168        /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
 169        __le32 res[3];
 170} __attribute__ ((packed));
 171
 172/*
 173 * DIU register map
 174 */
 175struct diu {
 176        __be32 desc[3];
 177        __be32 gamma;
 178        __be32 pallete;
 179        __be32 cursor;
 180        __be32 curs_pos;
 181        __be32 diu_mode;
 182        __be32 bgnd;
 183        __be32 bgnd_wb;
 184        __be32 disp_size;
 185        __be32 wb_size;
 186        __be32 wb_mem_addr;
 187        __be32 hsyn_para;
 188        __be32 vsyn_para;
 189        __be32 syn_pol;
 190        __be32 thresholds;
 191        __be32 int_status;
 192        __be32 int_mask;
 193        __be32 colorbar[8];
 194        __be32 filling;
 195        __be32 plut;
 196} __attribute__ ((packed));
 197
 198struct diu_addr {
 199        void *vaddr;            /* Virtual address */
 200        u32 paddr;              /* 32-bit physical address */
 201        unsigned int offset;    /* Alignment offset */
 202};
 203
 204static struct fb_info info;
 205
 206/*
 207 * Align to 64-bit(8-byte), 32-byte, etc.
 208 */
 209static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
 210{
 211        u32 offset, ssize;
 212        u32 mask;
 213
 214        ssize = size + bytes_align;
 215        buf->vaddr = malloc(ssize);
 216        if (!buf->vaddr)
 217                return -1;
 218
 219        memset(buf->vaddr, 0, ssize);
 220        mask = bytes_align - 1;
 221        offset = (u32)buf->vaddr & mask;
 222        if (offset) {
 223                buf->offset = bytes_align - offset;
 224                buf->vaddr += offset;
 225        } else
 226                buf->offset = 0;
 227
 228        buf->paddr = virt_to_phys(buf->vaddr);
 229        return 0;
 230}
 231
 232/*
 233 * Allocate a framebuffer and an Area Descriptor that points to it.  Both
 234 * are created in the same memory block.  The Area Descriptor is updated to
 235 * point to the framebuffer memory. Memory is aligned as needed.
 236 */
 237static struct diu_ad *allocate_fb(unsigned int xres, unsigned int yres,
 238                                  unsigned int depth, void **fb)
 239{
 240        unsigned long size = xres * yres * depth;
 241        struct diu_addr addr;
 242        struct diu_ad *ad;
 243        size_t ad_size = roundup(sizeof(struct diu_ad), 32);
 244
 245        /*
 246         * Allocate a memory block that holds the Area Descriptor and the
 247         * frame buffer right behind it.  To keep the code simple, everything
 248         * is aligned on a 32-byte address.
 249         */
 250        if (allocate_buf(&addr, ad_size + size, 32) < 0)
 251                return NULL;
 252
 253        ad = addr.vaddr;
 254        ad->addr = cpu_to_le32(addr.paddr + ad_size);
 255        ad->aoi_size = cpu_to_le32((yres << 16) | xres);
 256        ad->src_size_g_alpha = cpu_to_le32((yres << 12) | xres);
 257        ad->offset_xyi = 0;
 258        ad->offset_xyd = 0;
 259
 260        if (fb)
 261                *fb = addr.vaddr + ad_size;
 262
 263        return ad;
 264}
 265
 266int fsl_diu_init(int xres, u32 pixel_format, int gamma_fix)
 267{
 268        struct fb_videomode *fsl_diu_mode_db;
 269        struct diu_ad *ad;
 270        struct diu *hw = (struct diu *)CONFIG_SYS_DIU_ADDR;
 271        u8 *gamma_table_base;
 272        unsigned int i, j;
 273        struct diu_ad *dummy_ad;
 274        struct diu_addr gamma;
 275        struct diu_addr cursor;
 276
 277        switch (xres) {
 278        case 800:
 279                fsl_diu_mode_db = &fsl_diu_mode_800;
 280                break;
 281        case 1280:
 282                fsl_diu_mode_db = &fsl_diu_mode_1280;
 283                break;
 284        default:
 285                fsl_diu_mode_db = &fsl_diu_mode_1024;
 286        }
 287
 288        /* The AD struct for the dummy framebuffer and the FB itself */
 289        dummy_ad = allocate_fb(2, 4, 4, NULL);
 290        if (!dummy_ad) {
 291                printf("DIU:   Out of memory\n");
 292                return -1;
 293        }
 294        dummy_ad->pix_fmt = 0x88883316;
 295
 296        /* read mode info */
 297        info.var.xres = fsl_diu_mode_db->xres;
 298        info.var.yres = fsl_diu_mode_db->yres;
 299        info.var.bits_per_pixel = 32;
 300        info.var.pixclock = fsl_diu_mode_db->pixclock;
 301        info.var.left_margin = fsl_diu_mode_db->left_margin;
 302        info.var.right_margin = fsl_diu_mode_db->right_margin;
 303        info.var.upper_margin = fsl_diu_mode_db->upper_margin;
 304        info.var.lower_margin = fsl_diu_mode_db->lower_margin;
 305        info.var.hsync_len = fsl_diu_mode_db->hsync_len;
 306        info.var.vsync_len = fsl_diu_mode_db->vsync_len;
 307        info.var.sync = fsl_diu_mode_db->sync;
 308        info.var.vmode = fsl_diu_mode_db->vmode;
 309        info.line_length = info.var.xres * info.var.bits_per_pixel / 8;
 310
 311        /* Memory allocation for framebuffer */
 312        info.smem_len =
 313                info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
 314        ad = allocate_fb(info.var.xres, info.var.yres,
 315                         info.var.bits_per_pixel / 8, &info.screen_base);
 316        if (!ad) {
 317                printf("DIU:   Out of memory\n");
 318                return -1;
 319        }
 320
 321        ad->pix_fmt = pixel_format;
 322
 323        /* Disable chroma keying function */
 324        ad->ckmax_r = 0;
 325        ad->ckmax_g = 0;
 326        ad->ckmax_b = 0;
 327
 328        ad->ckmin_r = 255;
 329        ad->ckmin_g = 255;
 330        ad->ckmin_b = 255;
 331
 332        /* Initialize the gamma table */
 333        if (allocate_buf(&gamma, 256 * 3, 32) < 0) {
 334                printf("DIU:   Out of memory\n");
 335                return -1;
 336        }
 337        gamma_table_base = gamma.vaddr;
 338        for (i = 0; i <= 2; i++)
 339                for (j = 0; j < 256; j++)
 340                        *gamma_table_base++ = j;
 341
 342        if (gamma_fix == 1) {   /* fix the gamma */
 343                gamma_table_base = gamma.vaddr;
 344                for (i = 0; i < 256 * 3; i++) {
 345                        gamma_table_base[i] = (gamma_table_base[i] << 2)
 346                                | ((gamma_table_base[i] >> 6) & 0x03);
 347                }
 348        }
 349
 350        /* Initialize the cursor */
 351        if (allocate_buf(&cursor, 32 * 32 * 2, 32) < 0) {
 352                printf("DIU:   Can't alloc cursor data\n");
 353                return -1;
 354        }
 355
 356        /* Program DIU registers */
 357        out_be32(&hw->diu_mode, 0);     /* Temporarily disable the DIU */
 358
 359        out_be32(&hw->gamma, gamma.paddr);
 360        out_be32(&hw->cursor, cursor.paddr);
 361        out_be32(&hw->bgnd, 0x007F7F7F);
 362        out_be32(&hw->bgnd_wb, 0);
 363        out_be32(&hw->disp_size, info.var.yres << 16 | info.var.xres);
 364        out_be32(&hw->wb_size, 0);
 365        out_be32(&hw->wb_mem_addr, 0);
 366        out_be32(&hw->hsyn_para, info.var.left_margin << 22 |
 367                        info.var.hsync_len << 11 |
 368                        info.var.right_margin);
 369
 370        out_be32(&hw->vsyn_para, info.var.upper_margin << 22 |
 371                        info.var.vsync_len << 11 |
 372                        info.var.lower_margin);
 373
 374        out_be32(&hw->syn_pol, 0);
 375        out_be32(&hw->thresholds, 0x00037800);
 376        out_be32(&hw->int_status, 0);
 377        out_be32(&hw->int_mask, 0);
 378        out_be32(&hw->plut, 0x01F5F666);
 379        /* Pixel Clock configuration */
 380        diu_set_pixel_clock(info.var.pixclock);
 381
 382        /* Set the frame buffers */
 383        out_be32(&hw->desc[0], virt_to_phys(ad));
 384        out_be32(&hw->desc[1], virt_to_phys(dummy_ad));
 385        out_be32(&hw->desc[2], virt_to_phys(dummy_ad));
 386
 387        /* Enable the DIU, set display to all three planes */
 388        out_be32(&hw->diu_mode, 1);
 389
 390        return 0;
 391}
 392
 393void *video_hw_init(void)
 394{
 395        static GraphicDevice ctfb;
 396        const char *options;
 397        unsigned int depth = 0, freq = 0;
 398
 399        if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq,
 400                                  &options))
 401                return NULL;
 402
 403        /* Find the monitor port, which is a required option */
 404        if (!options)
 405                return NULL;
 406        if (strncmp(options, "monitor=", 8) != 0)
 407                return NULL;
 408
 409        if (platform_diu_init(ctfb.winSizeX, ctfb.winSizeY, options + 8) < 0)
 410                return NULL;
 411
 412        /* fill in Graphic device struct */
 413        sprintf(ctfb.modeIdent, "%ix%ix%i %ikHz %iHz",
 414                ctfb.winSizeX, ctfb.winSizeY, depth, 64, freq);
 415
 416        ctfb.frameAdrs = (unsigned int)info.screen_base;
 417        ctfb.plnSizeX = ctfb.winSizeX;
 418        ctfb.plnSizeY = ctfb.winSizeY;
 419
 420        ctfb.gdfBytesPP = 4;
 421        ctfb.gdfIndex = GDF_32BIT_X888RGB;
 422
 423        ctfb.isaBase = 0;
 424        ctfb.pciBase = 0;
 425        ctfb.memSize = info.screen_size;
 426
 427        /* Cursor Start Address */
 428        ctfb.dprBase = 0;
 429        ctfb.vprBase = 0;
 430        ctfb.cprBase = 0;
 431
 432        return &ctfb;
 433}
 434