X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=board%2Ffreescale%2Fp1022ds%2Fdiu.c;h=918b4b9f6ac37839f21fcecfeb1def1d787ac80d;hb=04909251fdecac9d05e527b83e86e043e8df00ea;hp=8f5305ca1f9c448283359c6794ecda69df6fe367;hpb=006915fbb0e3c1c9927fe32c4e92cb011f8499e7;p=platform%2Fkernel%2Fu-boot.git diff --git a/board/freescale/p1022ds/diu.c b/board/freescale/p1022ds/diu.c index 8f5305c..918b4b9 100644 --- a/board/freescale/p1022ds/diu.c +++ b/board/freescale/p1022ds/diu.c @@ -1,17 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2010 Freescale Semiconductor, Inc. + * Copyright 2010-2011 Freescale Semiconductor, Inc. * Authors: Timur Tabi * * 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. */ #include +#include #include +#include +#include #include #include #include @@ -62,6 +61,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 +74,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 +82,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 */ + + /* + * 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); + } - /* 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); + /* + * 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 +154,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,16 +187,15 @@ 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); } -#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS - /* * set_mux_to_lbc - disable the DIU so that we can read/write to elbc * @@ -167,12 +222,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)); @@ -183,6 +236,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; } @@ -198,12 +257,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. */ @@ -211,6 +276,68 @@ static void set_mux_to_diu(void) in_be32(&gur->pmuxcr); } +/* + * pixis_read - board-specific function to read from the PIXIS + * + * This function overrides the generic pixis_read() function, so that it can + * use PIXIS indirect mode if necessary. + */ +u8 pixis_read(unsigned int reg) +{ + ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + + /* Use indirect mode if the mux is currently set to DIU mode */ + if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) != + PMUXCR_ELBCDIU_NOR16) { + out_8(lbc_lcs0_ba, reg); + return in_8(lbc_lcs1_ba); + } else { + void *p = (void *)PIXIS_BASE; + + return in_8(p + reg); + } +} + +/* + * pixis_write - board-specific function to write to the PIXIS + * + * This function overrides the generic pixis_write() function, so that it can + * use PIXIS indirect mode if necessary. + */ +void pixis_write(unsigned int reg, u8 value) +{ + ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + + /* Use indirect mode if the mux is currently set to DIU mode */ + if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) != + PMUXCR_ELBCDIU_NOR16) { + out_8(lbc_lcs0_ba, reg); + out_8(lbc_lcs1_ba, value); + /* Do a read-back to ensure the write completed */ + in_8(lbc_lcs1_ba); + } else { + void *p = (void *)PIXIS_BASE; + + out_8(p + reg, value); + } +} + +void pixis_bank_reset(void) +{ + /* + * For some reason, a PIXIS bank reset does not work if the PIXIS is + * in indirect mode, so switch to direct mode first. + */ + set_mux_to_lbc(); + + out_8(&pixis->vctl, 0); + out_8(&pixis->vctl, 1); + + while (1); +} + +#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS + void flash_write8(u8 value, void *addr) { int sw = set_mux_to_lbc();