uboot/board/freescale/p1022ds/diu.c
<<
>>
Prefs
   1/*
   2 * Copyright 2010-2011 Freescale Semiconductor, Inc.
   3 * Authors: Timur Tabi <timur@freescale.com>
   4 *
   5 * FSL DIU Framebuffer driver
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11#include <command.h>
  12#include <linux/ctype.h>
  13#include <asm/io.h>
  14#include <stdio_dev.h>
  15#include <video_fb.h>
  16#include "../common/ngpixis.h"
  17#include <fsl_diu_fb.h>
  18
  19/* The CTL register is called 'csr' in the ngpixis_t structure */
  20#define PX_CTL_ALTACC           0x80
  21
  22#define PX_BRDCFG0_ELBC_SPI_MASK        0xc0
  23#define PX_BRDCFG0_ELBC_SPI_ELBC        0x00
  24#define PX_BRDCFG0_ELBC_SPI_NULL        0xc0
  25#define PX_BRDCFG0_ELBC_DIU             0x02
  26
  27#define PX_BRDCFG1_DVIEN        0x80
  28#define PX_BRDCFG1_DFPEN        0x40
  29#define PX_BRDCFG1_BACKLIGHT    0x20
  30
  31#define PMUXCR_ELBCDIU_MASK     0xc0000000
  32#define PMUXCR_ELBCDIU_NOR16    0x80000000
  33#define PMUXCR_ELBCDIU_DIU      0x40000000
  34
  35/*
  36 * DIU Area Descriptor
  37 *
  38 * Note that we need to byte-swap the value before it's written to the AD
  39 * register.  So even though the registers don't look like they're in the same
  40 * bit positions as they are on the MPC8610, the same value is written to the
  41 * AD register on the MPC8610 and on the P1022.
  42 */
  43#define AD_BYTE_F               0x10000000
  44#define AD_ALPHA_C_SHIFT        25
  45#define AD_BLUE_C_SHIFT         23
  46#define AD_GREEN_C_SHIFT        21
  47#define AD_RED_C_SHIFT          19
  48#define AD_PIXEL_S_SHIFT        16
  49#define AD_COMP_3_SHIFT         12
  50#define AD_COMP_2_SHIFT         8
  51#define AD_COMP_1_SHIFT         4
  52#define AD_COMP_0_SHIFT         0
  53
  54/*
  55 * Variables used by the DIU/LBC switching code.  It's safe to makes these
  56 * global, because the DIU requires DDR, so we'll only run this code after
  57 * relocation.
  58 */
  59static u8 px_brdcfg0;
  60static u32 pmuxcr;
  61static void *lbc_lcs0_ba;
  62static void *lbc_lcs1_ba;
  63static u32 old_br0, old_or0, old_br1, old_or1;
  64static u32 new_br0, new_or0, new_br1, new_or1;
  65
  66void diu_set_pixel_clock(unsigned int pixclock)
  67{
  68        ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
  69        unsigned long speed_ccb, temp;
  70        u32 pixval;
  71
  72        speed_ccb = get_bus_freq(0);
  73        temp = 1000000000 / pixclock;
  74        temp *= 1000;
  75        pixval = speed_ccb / temp;
  76        debug("DIU pixval = %u\n", pixval);
  77
  78        /* Modify PXCLK in GUTS CLKDVDR */
  79        temp = in_be32(&gur->clkdvdr) & 0x2000FFFF;
  80        out_be32(&gur->clkdvdr, temp);                  /* turn off clock */
  81        out_be32(&gur->clkdvdr, temp | 0x80000000 | ((pixval & 0x1F) << 16));
  82}
  83
  84int platform_diu_init(unsigned int xres, unsigned int yres, const char *port)
  85{
  86        ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
  87        const char *name;
  88        u32 pixel_format;
  89        u8 temp;
  90        phys_addr_t phys0, phys1; /* BR0/BR1 physical addresses */
  91
  92        /*
  93         * Indirect mode requires both BR0 and BR1 to be set to "GPCM",
  94         * otherwise writes to these addresses won't actually appear on the
  95         * local bus, and so the PIXIS won't see them.
  96         *
  97         * In FCM mode, writes go to the NAND controller, which does not pass
  98         * them to the localbus directly.  So we force BR0 and BR1 into GPCM
  99         * mode, since we don't care about what's behind the localbus any
 100         * more.  However, we save those registers first, so that we can
 101         * restore them when necessary.
 102         */
 103        new_br0 = old_br0 = get_lbc_br(0);
 104        new_br1 = old_br1 = get_lbc_br(1);
 105        new_or0 = old_or0 = get_lbc_or(0);
 106        new_or1 = old_or1 = get_lbc_or(1);
 107
 108        /*
 109         * Use the existing BRx/ORx values if it's already GPCM. Otherwise,
 110         * force the values to simple 32KB GPCM windows with the most
 111         * conservative timing.
 112         */
 113        if ((old_br0 & BR_MSEL) != BR_MS_GPCM) {
 114                new_br0 = (get_lbc_br(0) & BR_BA) | BR_V;
 115                new_or0 = OR_AM_32KB | 0xFF7;
 116                set_lbc_br(0, new_br0);
 117                set_lbc_or(0, new_or0);
 118        }
 119        if ((old_br1 & BR_MSEL) != BR_MS_GPCM) {
 120                new_br1 = (get_lbc_br(1) & BR_BA) | BR_V;
 121                new_or1 = OR_AM_32KB | 0xFF7;
 122                set_lbc_br(1, new_br1);
 123                set_lbc_or(1, new_or1);
 124        }
 125
 126        /*
 127         * Determine the physical addresses for Chip Selects 0 and 1.  The
 128         * BR0/BR1 registers contain the truncated physical addresses for the
 129         * chip selects, mapped via the localbus LAW.  Since the BRx registers
 130         * only contain the lower 32 bits of the address, we have to determine
 131         * the upper 4 bits some other way.  The proper way is to scan the LAW
 132         * table looking for a matching localbus address. Instead, we cheat.
 133         * We know that the upper bits are 0 for 32-bit addressing, or 0xF for
 134         * 36-bit addressing.
 135         */
 136#ifdef CONFIG_PHYS_64BIT
 137        phys0 = 0xf00000000ULL | (old_br0 & old_or0 & BR_BA);
 138        phys1 = 0xf00000000ULL | (old_br1 & old_or1 & BR_BA);
 139#else
 140        phys0 = old_br0 & old_or0 & BR_BA;
 141        phys1 = old_br1 & old_or1 & BR_BA;
 142#endif
 143
 144         /* Save the LBC LCS0 and LCS1 addresses for the DIU mux functions */
 145        lbc_lcs0_ba = map_physmem(phys0, 1, 0);
 146        lbc_lcs1_ba = map_physmem(phys1, 1, 0);
 147
 148        pixel_format = cpu_to_le32(AD_BYTE_F | (3 << AD_ALPHA_C_SHIFT) |
 149                (0 << AD_BLUE_C_SHIFT) | (1 << AD_GREEN_C_SHIFT) |
 150                (2 << AD_RED_C_SHIFT) | (8 << AD_COMP_3_SHIFT) |
 151                (8 << AD_COMP_2_SHIFT) | (8 << AD_COMP_1_SHIFT) |
 152                (8 << AD_COMP_0_SHIFT) | (3 << AD_PIXEL_S_SHIFT));
 153
 154        temp = in_8(&pixis->brdcfg1);
 155
 156        if (strncmp(port, "lvds", 4) == 0) {
 157                /* Single link LVDS */
 158                temp &= ~PX_BRDCFG1_DVIEN;
 159                /*
 160                 * LVDS also needs backlight enabled, otherwise the display
 161                 * will be blank.
 162                 */
 163                temp |= (PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT);
 164                name = "Single-Link LVDS";
 165        } else {        /* DVI */
 166                /* Enable the DVI port, disable the DFP and the backlight */
 167                temp &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT);
 168                temp |= PX_BRDCFG1_DVIEN;
 169                name = "DVI";
 170        }
 171
 172        printf("DIU:   Switching to %s monitor @ %ux%u\n", name, xres, yres);
 173        out_8(&pixis->brdcfg1, temp);
 174
 175        /*
 176         * Enable PIXIS indirect access mode.  This is a hack that allows us to
 177         * access PIXIS registers even when the LBC pins have been muxed to the
 178         * DIU.
 179         */
 180        setbits_8(&pixis->csr, PX_CTL_ALTACC);
 181
 182        /*
 183         * Route the LAD pins to the DIU.  This will disable access to the eLBC,
 184         * which means we won't be able to read/write any NOR flash addresses!
 185         */
 186        out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0));
 187        px_brdcfg0 = in_8(lbc_lcs1_ba);
 188        out_8(lbc_lcs1_ba, px_brdcfg0 | PX_BRDCFG0_ELBC_DIU);
 189        in_8(lbc_lcs1_ba);
 190
 191        /* Set PMUXCR to switch the muxed pins from the LBC to the DIU */
 192        clrsetbits_be32(&gur->pmuxcr, PMUXCR_ELBCDIU_MASK, PMUXCR_ELBCDIU_DIU);
 193        pmuxcr = in_be32(&gur->pmuxcr);
 194
 195        return fsl_diu_init(xres, yres, pixel_format, 0);
 196}
 197
 198/*
 199 * set_mux_to_lbc - disable the DIU so that we can read/write to elbc
 200 *
 201 * On the Freescale P1022, the DIU video signal and the LBC address/data lines
 202 * share the same pins, which means that when the DIU is active (e.g. the
 203 * console is on the DVI display), NOR flash cannot be accessed.  So we use the
 204 * weak accessor feature of the CFI flash code to temporarily switch the pin
 205 * mux from DIU to LBC whenever we want to read or write flash.  This has a
 206 * significant performance penalty, but it's the only way to make it work.
 207 *
 208 * There are two muxes: one on the chip, and one on the board. The chip mux
 209 * controls whether the pins are used for the DIU or the LBC, and it is
 210 * set via PMUXCR.  The board mux controls whether those signals go to
 211 * the video connector or the NOR flash chips, and it is set via the ngPIXIS.
 212 */
 213static int set_mux_to_lbc(void)
 214{
 215        ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
 216
 217        /* Switch the muxes only if they're currently set to DIU mode */
 218        if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
 219            PMUXCR_ELBCDIU_NOR16) {
 220                /*
 221                 * In DIU mode, the PIXIS can only be accessed indirectly
 222                 * since we can't read/write the LBC directly.
 223                 */
 224                /* Set the board mux to LBC.  This will disable the display. */
 225                out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0));
 226                out_8(lbc_lcs1_ba, px_brdcfg0);
 227                in_8(lbc_lcs1_ba);
 228
 229                /* Disable indirect PIXIS mode */
 230                out_8(lbc_lcs0_ba, offsetof(ngpixis_t, csr));
 231                clrbits_8(lbc_lcs1_ba, PX_CTL_ALTACC);
 232
 233                /* Set the chip mux to LBC mode, so that writes go to flash. */
 234                out_be32(&gur->pmuxcr, (pmuxcr & ~PMUXCR_ELBCDIU_MASK) |
 235                         PMUXCR_ELBCDIU_NOR16);
 236                in_be32(&gur->pmuxcr);
 237
 238                /* Restore the BR0 and BR1 settings */
 239                set_lbc_br(0, old_br0);
 240                set_lbc_or(0, old_or0);
 241                set_lbc_br(1, old_br1);
 242                set_lbc_or(1, old_or1);
 243
 244                return 1;
 245        }
 246
 247        return 0;
 248}
 249
 250/*
 251 * set_mux_to_diu - re-enable the DIU muxing
 252 *
 253 * This function restores the chip and board muxing to point to the DIU.
 254 */
 255static void set_mux_to_diu(void)
 256{
 257        ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
 258
 259        /* Set BR0 and BR1 to GPCM mode */
 260        set_lbc_br(0, new_br0);
 261        set_lbc_or(0, new_or0);
 262        set_lbc_br(1, new_br1);
 263        set_lbc_or(1, new_or1);
 264
 265        /* Enable indirect PIXIS mode */
 266        setbits_8(&pixis->csr, PX_CTL_ALTACC);
 267
 268        /* Set the board mux to DIU.  This will enable the display. */
 269        out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0));
 270        out_8(lbc_lcs1_ba, px_brdcfg0 | PX_BRDCFG0_ELBC_DIU);
 271        in_8(lbc_lcs1_ba);
 272
 273        /* Set the chip mux to DIU mode. */
 274        out_be32(&gur->pmuxcr, pmuxcr);
 275        in_be32(&gur->pmuxcr);
 276}
 277
 278/*
 279 * pixis_read - board-specific function to read from the PIXIS
 280 *
 281 * This function overrides the generic pixis_read() function, so that it can
 282 * use PIXIS indirect mode if necessary.
 283 */
 284u8 pixis_read(unsigned int reg)
 285{
 286        ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
 287
 288        /* Use indirect mode if the mux is currently set to DIU mode */
 289        if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
 290            PMUXCR_ELBCDIU_NOR16) {
 291                out_8(lbc_lcs0_ba, reg);
 292                return in_8(lbc_lcs1_ba);
 293        } else {
 294                void *p = (void *)PIXIS_BASE;
 295
 296                return in_8(p + reg);
 297        }
 298}
 299
 300/*
 301 * pixis_write - board-specific function to write to the PIXIS
 302 *
 303 * This function overrides the generic pixis_write() function, so that it can
 304 * use PIXIS indirect mode if necessary.
 305 */
 306void pixis_write(unsigned int reg, u8 value)
 307{
 308        ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
 309
 310        /* Use indirect mode if the mux is currently set to DIU mode */
 311        if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) !=
 312            PMUXCR_ELBCDIU_NOR16) {
 313                out_8(lbc_lcs0_ba, reg);
 314                out_8(lbc_lcs1_ba, value);
 315                /* Do a read-back to ensure the write completed */
 316                in_8(lbc_lcs1_ba);
 317        } else {
 318                void *p = (void *)PIXIS_BASE;
 319
 320                out_8(p + reg, value);
 321        }
 322}
 323
 324void pixis_bank_reset(void)
 325{
 326        /*
 327         * For some reason, a PIXIS bank reset does not work if the PIXIS is
 328         * in indirect mode, so switch to direct mode first.
 329         */
 330        set_mux_to_lbc();
 331
 332        out_8(&pixis->vctl, 0);
 333        out_8(&pixis->vctl, 1);
 334
 335        while (1);
 336}
 337
 338#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
 339
 340void flash_write8(u8 value, void *addr)
 341{
 342        int sw = set_mux_to_lbc();
 343
 344        __raw_writeb(value, addr);
 345        if (sw) {
 346                /*
 347                 * To ensure the post-write is completed to eLBC, software must
 348                 * perform a dummy read from one valid address from eLBC space
 349                 * before changing the eLBC_DIU from NOR mode to DIU mode.
 350                 * set_mux_to_diu() includes a sync that will ensure the
 351                 * __raw_readb() completes before it switches the mux.
 352                 */
 353                __raw_readb(addr);
 354                set_mux_to_diu();
 355        }
 356}
 357
 358void flash_write16(u16 value, void *addr)
 359{
 360        int sw = set_mux_to_lbc();
 361
 362        __raw_writew(value, addr);
 363        if (sw) {
 364                /*
 365                 * To ensure the post-write is completed to eLBC, software must
 366                 * perform a dummy read from one valid address from eLBC space
 367                 * before changing the eLBC_DIU from NOR mode to DIU mode.
 368                 * set_mux_to_diu() includes a sync that will ensure the
 369                 * __raw_readb() completes before it switches the mux.
 370                 */
 371                __raw_readb(addr);
 372                set_mux_to_diu();
 373        }
 374}
 375
 376void flash_write32(u32 value, void *addr)
 377{
 378        int sw = set_mux_to_lbc();
 379
 380        __raw_writel(value, addr);
 381        if (sw) {
 382                /*
 383                 * To ensure the post-write is completed to eLBC, software must
 384                 * perform a dummy read from one valid address from eLBC space
 385                 * before changing the eLBC_DIU from NOR mode to DIU mode.
 386                 * set_mux_to_diu() includes a sync that will ensure the
 387                 * __raw_readb() completes before it switches the mux.
 388                 */
 389                __raw_readb(addr);
 390                set_mux_to_diu();
 391        }
 392}
 393
 394void flash_write64(u64 value, void *addr)
 395{
 396        int sw = set_mux_to_lbc();
 397        uint32_t *p = addr;
 398
 399        /*
 400         * There is no __raw_writeq(), so do the write manually.  We don't trust
 401         * the compiler, so we use inline assembly.
 402         */
 403        __asm__ __volatile__(
 404                "stw%U0%X0 %2,%0;\n"
 405                "stw%U1%X1 %3,%1;\n"
 406                : "=m" (*p), "=m" (*(p + 1))
 407                : "r" ((uint32_t) (value >> 32)), "r" ((uint32_t) (value)));
 408
 409        if (sw) {
 410                /*
 411                 * To ensure the post-write is completed to eLBC, software must
 412                 * perform a dummy read from one valid address from eLBC space
 413                 * before changing the eLBC_DIU from NOR mode to DIU mode.  We
 414                 * read addr+4 because we just wrote to addr+4, so that's how we
 415                 * maintain execution order.  set_mux_to_diu() includes a sync
 416                 * that will ensure the __raw_readb() completes before it
 417                 * switches the mux.
 418                 */
 419                __raw_readb(addr + 4);
 420                set_mux_to_diu();
 421        }
 422}
 423
 424u8 flash_read8(void *addr)
 425{
 426        u8 ret;
 427
 428        int sw = set_mux_to_lbc();
 429
 430        ret = __raw_readb(addr);
 431        if (sw)
 432                set_mux_to_diu();
 433
 434        return ret;
 435}
 436
 437u16 flash_read16(void *addr)
 438{
 439        u16 ret;
 440
 441        int sw = set_mux_to_lbc();
 442
 443        ret = __raw_readw(addr);
 444        if (sw)
 445                set_mux_to_diu();
 446
 447        return ret;
 448}
 449
 450u32 flash_read32(void *addr)
 451{
 452        u32 ret;
 453
 454        int sw = set_mux_to_lbc();
 455
 456        ret = __raw_readl(addr);
 457        if (sw)
 458                set_mux_to_diu();
 459
 460        return ret;
 461}
 462
 463u64 flash_read64(void *addr)
 464{
 465        u64 ret;
 466
 467        int sw = set_mux_to_lbc();
 468
 469        /* There is no __raw_readq(), so do the read manually */
 470        ret = *(volatile u64 *)addr;
 471        if (sw)
 472                set_mux_to_diu();
 473
 474        return ret;
 475}
 476
 477#endif
 478