]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - board/freescale/p1022ds/diu.c
Add GPL-2.0+ SPDX-License-Identifier to source files
[karo-tx-uboot.git] / board / freescale / p1022ds / diu.c
index 7d1f6aa1246113373ef4e83baaade14cddcf798a..6fd4d953b6e60f6456c971ae349227d9170b0df8 100644 (file)
@@ -4,10 +4,7 @@
  *
  * 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 <common.h>
@@ -63,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)
 {
@@ -74,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;
@@ -88,10 +87,63 @@ int platform_diu_init(unsigned int xres, unsigned int yres, const char *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) |
@@ -134,12 +186,13 @@ int platform_diu_init(unsigned int xres, unsigned int yres, const char *port)
        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);
 }
 
 /*
@@ -168,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));
@@ -184,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;
        }
 
@@ -199,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. */