uboot/board/bf527-ezkit/video.c
<<
>>
Prefs
   1/*
   2 * video.c - run splash screen on lcd
   3 *
   4 * Copyright (c) 2007-2008 Analog Devices Inc.
   5 *
   6 * Licensed under the GPL-2 or later.
   7 */
   8
   9#include <stdarg.h>
  10#include <common.h>
  11#include <config.h>
  12#include <malloc.h>
  13#include <asm/blackfin.h>
  14#include <asm/portmux.h>
  15#include <asm/mach-common/bits/dma.h>
  16#include <spi.h>
  17#include <linux/types.h>
  18#include <stdio_dev.h>
  19
  20#include <lzma/LzmaTypes.h>
  21#include <lzma/LzmaDec.h>
  22#include <lzma/LzmaTools.h>
  23
  24#include <asm/mach-common/bits/ppi.h>
  25#include <asm/mach-common/bits/timer.h>
  26
  27#define LCD_X_RES               320     /* Horizontal Resolution */
  28#define LCD_Y_RES               240     /* Vertical Resolution */
  29#define DMA_BUS_SIZE            16
  30
  31#include EASYLOGO_HEADER
  32
  33#ifdef CONFIG_BF527_EZKIT_REV_2_1 /* lq035q1 */
  34
  35/* Interface 16/18-bit TFT over an 8-bit wide PPI using a
  36 * small Programmable Logic Device (CPLD)
  37 * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
  38 */
  39
  40#ifdef CONFIG_LQ035Q1_USE_RGB565_8_BIT_PPI
  41#define LCD_BPP         16      /* Bit Per Pixel */
  42#define CLOCKS_PPIX     2       /* Clocks per pixel */
  43#define CPLD_DELAY      3       /* RGB565 pipeline delay */
  44#endif
  45
  46#ifdef CONFIG_LQ035Q1_USE_RGB888_8_BIT_PPI
  47#define LCD_BPP         24      /* Bit Per Pixel */
  48#define CLOCKS_PPIX     3       /* Clocks per pixel */
  49#define CPLD_DELAY      5       /* RGB888 pipeline delay */
  50#endif
  51
  52/*
  53 * HS and VS timing parameters (all in number of PPI clk ticks)
  54 */
  55
  56#define H_ACTPIX        (LCD_X_RES * CLOCKS_PPIX)       /* active horizontal pixel */
  57#define H_PERIOD        (336 * CLOCKS_PPIX)             /* HS period */
  58#define H_PULSE         (2 * CLOCKS_PPIX)               /* HS pulse width */
  59#define H_START         (7 * CLOCKS_PPIX + CPLD_DELAY)  /* first valid pixel */
  60
  61#define U_LINE          4                               /* Blanking Lines */
  62
  63#define V_LINES         (LCD_Y_RES + U_LINE)            /* total vertical lines */
  64#define V_PULSE         (2 * CLOCKS_PPIX)               /* VS pulse width (1-5 H_PERIODs) */
  65#define V_PERIOD        (H_PERIOD * V_LINES)            /* VS period */
  66
  67#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8))
  68
  69/*
  70 * LCD Modes
  71 */
  72#define LQ035_RL        (0 << 8)        /* Right -> Left Scan */
  73#define LQ035_LR        (1 << 8)        /* Left -> Right Scan */
  74#define LQ035_TB        (1 << 9)        /* Top -> Botton Scan */
  75#define LQ035_BT        (0 << 9)        /* Botton -> Top Scan */
  76#define LQ035_BGR       (1 << 11)       /* Use BGR format */
  77#define LQ035_RGB       (0 << 11)       /* Use RGB format */
  78#define LQ035_NORM      (1 << 13)       /* Reversal */
  79#define LQ035_REV       (0 << 13)       /* Reversal */
  80
  81#define LQ035_INDEX                     0x74
  82#define LQ035_DATA                      0x76
  83
  84#define LQ035_DRIVER_OUTPUT_CTL         0x1
  85#define LQ035_SHUT_CTL                  0x11
  86
  87#define LQ035_DRIVER_OUTPUT_MASK        (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV)
  88#define LQ035_DRIVER_OUTPUT_DEFAULT     (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK)
  89
  90#define LQ035_SHUT                      (1 << 0)        /* Shutdown */
  91#define LQ035_ON                        (0 << 0)        /* Shutdown */
  92
  93#ifndef CONFIG_LQ035Q1_LCD_MODE
  94#define CONFIG_LQ035Q1_LCD_MODE         (LQ035_NORM | LQ035_RL | LQ035_TB | LQ035_BGR)
  95#endif
  96
  97#else /* t350mcqb */
  98
  99#define LCD_BPP         24      /* Bit Per Pixel */
 100#define CLOCKS_PPIX     3       /* Clocks per pixel */
 101
 102/* HS and VS timing parameters (all in number of PPI clk ticks) */
 103#define H_ACTPIX        (LCD_X_RES * CLOCKS_PPIX)       /* active horizontal pixel */
 104#define H_PERIOD        (408 * CLOCKS_PPIX)             /* HS period */
 105#define H_PULSE         90                              /* HS pulse width */
 106#define H_START         204                             /* first valid pixel */
 107
 108#define U_LINE          1                               /* Blanking Lines */
 109
 110#define V_LINES         (LCD_Y_RES + U_LINE)            /* total vertical lines */
 111#define V_PULSE         (3 * H_PERIOD)                  /* VS pulse width (1-5 H_PERIODs) */
 112#define V_PERIOD        (H_PERIOD * V_LINES)            /* VS period */
 113
 114#define ACTIVE_VIDEO_MEM_OFFSET (U_LINE * H_ACTPIX)
 115#endif
 116
 117#define LCD_PIXEL_SIZE          (LCD_BPP / 8)
 118#define DMA_SIZE16              2
 119
 120#define PPI_TX_MODE             0x2
 121#define PPI_XFER_TYPE_11        0xC
 122#define PPI_PORT_CFG_01         0x10
 123#define PPI_PACK_EN             0x80
 124#define PPI_POLS_1              0x8000
 125
 126#ifdef CONFIG_BF527_EZKIT_REV_2_1
 127static struct spi_slave *slave;
 128static int lq035q1_control(unsigned char reg, unsigned short value)
 129{
 130        int ret;
 131        u8 regs[3] = {LQ035_INDEX, 0, 0};
 132        u8 data[3] = {LQ035_DATA, 0, 0};
 133        u8 dummy[3];
 134
 135        regs[2] = reg;
 136        data[1] = value >> 8;
 137        data[2] = value & 0xFF;
 138
 139        if (!slave) {
 140                /* FIXME: Verify the max SCK rate */
 141                slave = spi_setup_slave(CONFIG_LQ035Q1_SPI_BUS,
 142                                CONFIG_LQ035Q1_SPI_CS, 20000000,
 143                                SPI_MODE_3);
 144                if (!slave)
 145                        return -1;
 146        }
 147
 148        if (spi_claim_bus(slave))
 149                return -1;
 150
 151        ret = spi_xfer(slave, 24, regs, dummy, SPI_XFER_BEGIN | SPI_XFER_END);
 152        ret |= spi_xfer(slave, 24, data, dummy, SPI_XFER_BEGIN | SPI_XFER_END);
 153
 154        spi_release_bus(slave);
 155
 156        return ret;
 157}
 158#endif
 159
 160/* enable and disable PPI functions */
 161void EnablePPI(void)
 162{
 163        bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN);
 164}
 165
 166void DisablePPI(void)
 167{
 168        bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN);
 169}
 170
 171void Init_Ports(void)
 172{
 173        const unsigned short pins[] = {
 174                P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, P_PPI0_D4,
 175                P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, P_PPI0_FS2, 0,
 176        };
 177        peripheral_request_list(pins, "lcd");
 178}
 179
 180void Init_PPI(void)
 181{
 182
 183        bfin_write_PPI_DELAY(H_START);
 184        bfin_write_PPI_COUNT(H_ACTPIX - 1);
 185        bfin_write_PPI_FRAME(V_LINES);
 186
 187        /* PPI control, to be replaced with definitions */
 188        bfin_write_PPI_CONTROL(
 189                        PPI_TX_MODE             |       /* output mode , PORT_DIR */
 190                        PPI_XFER_TYPE_11        |       /* sync mode XFR_TYPE */
 191                        PPI_PORT_CFG_01         |       /* two frame sync PORT_CFG */
 192                        PPI_PACK_EN             |       /* packing enabled PACK_EN */
 193                        PPI_POLS_1                      /* faling edge syncs POLS */
 194        );
 195}
 196
 197void Init_DMA(void *dst)
 198{
 199        bfin_write_DMA0_START_ADDR(dst);
 200
 201        /* X count */
 202        bfin_write_DMA0_X_COUNT(H_ACTPIX / 2);
 203        bfin_write_DMA0_X_MODIFY(DMA_BUS_SIZE / 8);
 204
 205        /* Y count */
 206        bfin_write_DMA0_Y_COUNT(V_LINES);
 207        bfin_write_DMA0_Y_MODIFY(DMA_BUS_SIZE / 8);
 208
 209        /* DMA Config */
 210        bfin_write_DMA0_CONFIG(
 211                WDSIZE_16       |       /* 16 bit DMA */
 212                DMA2D           |       /* 2D DMA */
 213                FLOW_AUTO               /* autobuffer mode */
 214        );
 215}
 216
 217void EnableDMA(void)
 218{
 219        bfin_write_DMA0_CONFIG(bfin_read_DMA0_CONFIG() | DMAEN);
 220}
 221
 222void DisableDMA(void)
 223{
 224        bfin_write_DMA0_CONFIG(bfin_read_DMA0_CONFIG() & ~DMAEN);
 225}
 226
 227/* Init TIMER0 as Frame Sync 1 generator */
 228void InitTIMER0(void)
 229{
 230        bfin_write_TIMER_DISABLE(TIMDIS0);                      /* disable Timer */
 231        SSYNC();
 232        bfin_write_TIMER_STATUS(TIMIL0 | TOVF_ERR0 | TRUN0);    /* clear status */
 233        SSYNC();
 234
 235        bfin_write_TIMER0_PERIOD(H_PERIOD);
 236        SSYNC();
 237        bfin_write_TIMER0_WIDTH(H_PULSE);
 238        SSYNC();
 239
 240        bfin_write_TIMER0_CONFIG(
 241                                PWM_OUT |
 242                                PERIOD_CNT   |
 243                                TIN_SEL      |
 244                                CLK_SEL      |
 245                                EMU_RUN
 246        );
 247        SSYNC();
 248}
 249
 250void EnableTIMER0(void)
 251{
 252        bfin_write_TIMER_ENABLE(TIMEN0);
 253        SSYNC();
 254}
 255
 256void DisableTIMER0(void)
 257{
 258        bfin_write_TIMER_DISABLE(TIMDIS0);
 259        SSYNC();
 260}
 261
 262
 263void InitTIMER1(void)
 264{
 265        bfin_write_TIMER_DISABLE(TIMDIS1);                      /* disable Timer */
 266        SSYNC();
 267        bfin_write_TIMER_STATUS(TIMIL1 | TOVF_ERR1 | TRUN1);    /* clear status */
 268        SSYNC();
 269
 270        bfin_write_TIMER1_PERIOD(V_PERIOD);
 271        SSYNC();
 272        bfin_write_TIMER1_WIDTH(V_PULSE);
 273        SSYNC();
 274
 275        bfin_write_TIMER1_CONFIG(
 276                                PWM_OUT |
 277                                PERIOD_CNT   |
 278                                TIN_SEL      |
 279                                CLK_SEL      |
 280                                EMU_RUN
 281        );
 282        SSYNC();
 283}
 284
 285void EnableTIMER1(void)
 286{
 287        bfin_write_TIMER_ENABLE(TIMEN1);
 288        SSYNC();
 289}
 290
 291void DisableTIMER1(void)
 292{
 293        bfin_write_TIMER_DISABLE(TIMDIS1);
 294        SSYNC();
 295}
 296
 297void EnableTIMER12(void)
 298{
 299        bfin_write_TIMER_ENABLE(TIMEN1 | TIMEN0);
 300        SSYNC();
 301}
 302
 303int video_init(void *dst)
 304{
 305
 306#ifdef CONFIG_BF527_EZKIT_REV_2_1
 307        lq035q1_control(LQ035_SHUT_CTL, LQ035_ON);
 308        lq035q1_control(LQ035_DRIVER_OUTPUT_CTL, (CONFIG_LQ035Q1_LCD_MODE &
 309                LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT);
 310#endif
 311        Init_Ports();
 312        Init_DMA(dst);
 313        EnableDMA();
 314        InitTIMER0();
 315        InitTIMER1();
 316        Init_PPI();
 317        EnablePPI();
 318
 319#ifdef CONFIG_BF527_EZKIT_REV_2_1
 320        EnableTIMER12();
 321#else
 322        /* Frame sync 2 (VS) needs to start at least one PPI clk earlier */
 323        EnableTIMER1();
 324        /* Add Some Delay ... */
 325        SSYNC();
 326        SSYNC();
 327        SSYNC();
 328        SSYNC();
 329
 330        /* now start frame sync 1 */
 331        EnableTIMER0();
 332#endif
 333
 334        return 0;
 335}
 336
 337static void dma_bitblit(void *dst, fastimage_t *logo, int x, int y)
 338{
 339        if (dcache_status())
 340                blackfin_dcache_flush_range(logo->data, logo->data + logo->size);
 341
 342        bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
 343
 344        /* Setup destination start address */
 345        bfin_write_MDMA_D0_START_ADDR(dst + ((x & -2) * LCD_PIXEL_SIZE)
 346                                        + (y * LCD_X_RES * LCD_PIXEL_SIZE));
 347        /* Setup destination xcount */
 348        bfin_write_MDMA_D0_X_COUNT(logo->width * LCD_PIXEL_SIZE / DMA_SIZE16);
 349        /* Setup destination xmodify */
 350        bfin_write_MDMA_D0_X_MODIFY(DMA_SIZE16);
 351
 352        /* Setup destination ycount */
 353        bfin_write_MDMA_D0_Y_COUNT(logo->height);
 354        /* Setup destination ymodify */
 355        bfin_write_MDMA_D0_Y_MODIFY((LCD_X_RES - logo->width) * LCD_PIXEL_SIZE + DMA_SIZE16);
 356
 357
 358        /* Setup Source start address */
 359        bfin_write_MDMA_S0_START_ADDR(logo->data);
 360        /* Setup Source xcount */
 361        bfin_write_MDMA_S0_X_COUNT(logo->width * LCD_PIXEL_SIZE / DMA_SIZE16);
 362        /* Setup Source xmodify */
 363        bfin_write_MDMA_S0_X_MODIFY(DMA_SIZE16);
 364
 365        /* Setup Source ycount */
 366        bfin_write_MDMA_S0_Y_COUNT(logo->height);
 367        /* Setup Source ymodify */
 368        bfin_write_MDMA_S0_Y_MODIFY(DMA_SIZE16);
 369
 370
 371        /* Enable source DMA */
 372        bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16 | DMA2D);
 373        SSYNC();
 374        bfin_write_MDMA_D0_CONFIG(WNR | DMAEN  | WDSIZE_16 | DMA2D);
 375
 376        while (bfin_read_MDMA_D0_IRQ_STATUS() & DMA_RUN);
 377
 378        bfin_write_MDMA_S0_IRQ_STATUS(bfin_read_MDMA_S0_IRQ_STATUS() | DMA_DONE | DMA_ERR);
 379        bfin_write_MDMA_D0_IRQ_STATUS(bfin_read_MDMA_D0_IRQ_STATUS() | DMA_DONE | DMA_ERR);
 380
 381}
 382
 383void video_stop(void)
 384{
 385        DisablePPI();
 386        DisableDMA();
 387        DisableTIMER0();
 388        DisableTIMER1();
 389#ifdef CONFIG_BF527_EZKIT_REV_2_1
 390        lq035q1_control(LQ035_SHUT_CTL, LQ035_SHUT);
 391#endif
 392}
 393
 394int drv_video_init(void)
 395{
 396        int error, devices = 1;
 397        struct stdio_dev videodev;
 398
 399        u8 *dst;
 400        u32 fbmem_size = LCD_X_RES * LCD_Y_RES * LCD_PIXEL_SIZE + ACTIVE_VIDEO_MEM_OFFSET;
 401
 402        dst = malloc(fbmem_size);
 403
 404        if (dst == NULL) {
 405                printf("Failed to alloc FB memory\n");
 406                return -1;
 407        }
 408
 409#ifdef EASYLOGO_ENABLE_GZIP
 410        unsigned char *data = EASYLOGO_DECOMP_BUFFER;
 411        unsigned long src_len = EASYLOGO_ENABLE_GZIP;
 412        error = gunzip(data, bfin_logo.size, bfin_logo.data, &src_len);
 413        bfin_logo.data = data;
 414#elif defined(EASYLOGO_ENABLE_LZMA)
 415        unsigned char *data = EASYLOGO_DECOMP_BUFFER;
 416        SizeT lzma_len = bfin_logo.size;
 417        error = lzmaBuffToBuffDecompress(data, &lzma_len,
 418                bfin_logo.data, EASYLOGO_ENABLE_LZMA);
 419        bfin_logo.data = data;
 420#else
 421        error = 0;
 422#endif
 423
 424        if (error) {
 425                puts("Failed to decompress logo\n");
 426                free(dst);
 427                return -1;
 428        }
 429
 430        memset(dst + ACTIVE_VIDEO_MEM_OFFSET, bfin_logo.data[0], fbmem_size - ACTIVE_VIDEO_MEM_OFFSET);
 431
 432        dma_bitblit(dst + ACTIVE_VIDEO_MEM_OFFSET, &bfin_logo,
 433                        (LCD_X_RES - bfin_logo.width) / 2,
 434                        (LCD_Y_RES - bfin_logo.height) / 2);
 435
 436        video_init(dst);                /* Video initialization */
 437
 438        memset(&videodev, 0, sizeof(videodev));
 439
 440        strcpy(videodev.name, "video");
 441
 442        error = stdio_register(&videodev);
 443
 444        return (error == 0) ? devices : error;
 445}
 446