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