X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=board%2Ffreescale%2Fp1022ds%2Fdiu.c;h=6fd4d953b6e60f6456c971ae349227d9170b0df8;hb=f15ea6e1d67782a1626d4a4922b6c20e380085e5;hp=b37e0e269b1929f967d7a3421a52520ac45a9e3b;hpb=aa8d3fb8f4d383e7371f8f678ca3db1ca7d0ae32;p=oweals%2Fu-boot.git diff --git a/board/freescale/p1022ds/diu.c b/board/freescale/p1022ds/diu.c index b37e0e269b..6fd4d953b6 100644 --- a/board/freescale/p1022ds/diu.c +++ b/board/freescale/p1022ds/diu.c @@ -4,14 +4,12 @@ * * FSL DIU Framebuffer driver * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * SPDX-License-Identifier: GPL-2.0+ */ #include #include +#include #include #include #include @@ -62,6 +60,8 @@ static u8 px_brdcfg0; static u32 pmuxcr; static void *lbc_lcs0_ba; static void *lbc_lcs1_ba; +static u32 old_br0, old_or0, old_br1, old_or1; +static u32 new_br0, new_or0, new_br1, new_or1; void diu_set_pixel_clock(unsigned int pixclock) { @@ -73,7 +73,7 @@ void diu_set_pixel_clock(unsigned int pixclock) temp = 1000000000 / pixclock; temp *= 1000; pixval = speed_ccb / temp; - debug("DIU pixval = %lu\n", pixval); + debug("DIU pixval = %u\n", pixval); /* Modify PXCLK in GUTS CLKDVDR */ temp = in_be32(&gur->clkdvdr) & 0x2000FFFF; @@ -81,16 +81,69 @@ void diu_set_pixel_clock(unsigned int pixclock) out_be32(&gur->clkdvdr, temp | 0x80000000 | ((pixval & 0x1F) << 16)); } -int platform_diu_init(unsigned int *xres, unsigned int *yres) +int platform_diu_init(unsigned int xres, unsigned int yres, const char *port) { ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); - char *monitor_port; + const char *name; u32 pixel_format; u8 temp; + phys_addr_t phys0, phys1; /* BR0/BR1 physical addresses */ - /* Save the LBC LCS0 and LCS1 addresses for the DIU mux functions */ - lbc_lcs0_ba = (void *)(get_lbc_br(0) & get_lbc_or(0) & 0xFFFF8000); - lbc_lcs1_ba = (void *)(get_lbc_br(1) & get_lbc_or(1) & 0xFFFF8000); + /* + * Indirect mode requires both BR0 and BR1 to be set to "GPCM", + * otherwise writes to these addresses won't actually appear on the + * local bus, and so the PIXIS won't see them. + * + * In FCM mode, writes go to the NAND controller, which does not pass + * them to the localbus directly. So we force BR0 and BR1 into GPCM + * mode, since we don't care about what's behind the localbus any + * more. However, we save those registers first, so that we can + * restore them when necessary. + */ + new_br0 = old_br0 = get_lbc_br(0); + new_br1 = old_br1 = get_lbc_br(1); + new_or0 = old_or0 = get_lbc_or(0); + new_or1 = old_or1 = get_lbc_or(1); + + /* + * Use the existing BRx/ORx values if it's already GPCM. Otherwise, + * force the values to simple 32KB GPCM windows with the most + * conservative timing. + */ + if ((old_br0 & BR_MSEL) != BR_MS_GPCM) { + new_br0 = (get_lbc_br(0) & BR_BA) | BR_V; + new_or0 = OR_AM_32KB | 0xFF7; + set_lbc_br(0, new_br0); + set_lbc_or(0, new_or0); + } + if ((old_br1 & BR_MSEL) != BR_MS_GPCM) { + new_br1 = (get_lbc_br(1) & BR_BA) | BR_V; + new_or1 = OR_AM_32KB | 0xFF7; + set_lbc_br(1, new_br1); + set_lbc_or(1, new_or1); + } + + /* + * Determine the physical addresses for Chip Selects 0 and 1. The + * BR0/BR1 registers contain the truncated physical addresses for the + * chip selects, mapped via the localbus LAW. Since the BRx registers + * only contain the lower 32 bits of the address, we have to determine + * the upper 4 bits some other way. The proper way is to scan the LAW + * table looking for a matching localbus address. Instead, we cheat. + * We know that the upper bits are 0 for 32-bit addressing, or 0xF for + * 36-bit addressing. + */ +#ifdef CONFIG_PHYS_64BIT + phys0 = 0xf00000000ULL | (old_br0 & old_or0 & BR_BA); + phys1 = 0xf00000000ULL | (old_br1 & old_or1 & BR_BA); +#else + phys0 = old_br0 & old_or0 & BR_BA; + phys1 = old_br1 & old_or1 & BR_BA; +#endif + + /* Save the LBC LCS0 and LCS1 addresses for the DIU mux functions */ + lbc_lcs0_ba = map_physmem(phys0, 1, 0); + lbc_lcs1_ba = map_physmem(phys1, 1, 0); pixel_format = cpu_to_le32(AD_BYTE_F | (3 << AD_ALPHA_C_SHIFT) | (0 << AD_BLUE_C_SHIFT) | (1 << AD_GREEN_C_SHIFT) | @@ -100,21 +153,23 @@ int platform_diu_init(unsigned int *xres, unsigned int *yres) temp = in_8(&pixis->brdcfg1); - monitor_port = getenv("monitor"); - if (!strncmp(monitor_port, "1", 1)) { /* 1 - Single link LVDS */ - *xres = 1024; - *yres = 768; - /* Enable the DFP port, disable the DVI and the backlight */ - temp &= ~(PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT); - temp |= PX_BRDCFG1_DFPEN; + if (strncmp(port, "lvds", 4) == 0) { + /* Single link LVDS */ + temp &= ~PX_BRDCFG1_DVIEN; + /* + * LVDS also needs backlight enabled, otherwise the display + * will be blank. + */ + temp |= (PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); + name = "Single-Link LVDS"; } else { /* DVI */ - *xres = 1280; - *yres = 1024; /* Enable the DVI port, disable the DFP and the backlight */ temp &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); temp |= PX_BRDCFG1_DVIEN; + name = "DVI"; } + printf("DIU: Switching to %s monitor @ %ux%u\n", name, xres, yres); out_8(&pixis->brdcfg1, temp); /* @@ -131,12 +186,13 @@ int platform_diu_init(unsigned int *xres, unsigned int *yres) out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0)); px_brdcfg0 = in_8(lbc_lcs1_ba); out_8(lbc_lcs1_ba, px_brdcfg0 | PX_BRDCFG0_ELBC_DIU); + in_8(lbc_lcs1_ba); /* Set PMUXCR to switch the muxed pins from the LBC to the DIU */ clrsetbits_be32(&gur->pmuxcr, PMUXCR_ELBCDIU_MASK, PMUXCR_ELBCDIU_DIU); pmuxcr = in_be32(&gur->pmuxcr); - return fsl_diu_init(*xres, pixel_format, 0); + return fsl_diu_init(xres, yres, pixel_format, 0); } /* @@ -165,12 +221,10 @@ static int set_mux_to_lbc(void) * In DIU mode, the PIXIS can only be accessed indirectly * since we can't read/write the LBC directly. */ - /* Set the board mux to LBC. This will disable the display. */ out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0)); - px_brdcfg0 = in_8(lbc_lcs1_ba); - out_8(lbc_lcs1_ba, (px_brdcfg0 & ~(PX_BRDCFG0_ELBC_SPI_MASK - | PX_BRDCFG0_ELBC_DIU)) | PX_BRDCFG0_ELBC_SPI_ELBC); + out_8(lbc_lcs1_ba, px_brdcfg0); + in_8(lbc_lcs1_ba); /* Disable indirect PIXIS mode */ out_8(lbc_lcs0_ba, offsetof(ngpixis_t, csr)); @@ -181,6 +235,12 @@ static int set_mux_to_lbc(void) PMUXCR_ELBCDIU_NOR16); in_be32(&gur->pmuxcr); + /* Restore the BR0 and BR1 settings */ + set_lbc_br(0, old_br0); + set_lbc_or(0, old_or0); + set_lbc_br(1, old_br1); + set_lbc_or(1, old_or1); + return 1; } @@ -196,12 +256,18 @@ static void set_mux_to_diu(void) { ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + /* Set BR0 and BR1 to GPCM mode */ + set_lbc_br(0, new_br0); + set_lbc_or(0, new_or0); + set_lbc_br(1, new_br1); + set_lbc_or(1, new_or1); + /* Enable indirect PIXIS mode */ setbits_8(&pixis->csr, PX_CTL_ALTACC); /* Set the board mux to DIU. This will enable the display. */ out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0)); - out_8(lbc_lcs1_ba, px_brdcfg0); + out_8(lbc_lcs1_ba, px_brdcfg0 | PX_BRDCFG0_ELBC_DIU); in_8(lbc_lcs1_ba); /* Set the chip mux to DIU mode. */