[U-Boot] [PATCH] p1022ds: use weak CFI flash accessors when DIU is enabled

Timur Tabi timur at freescale.com
Thu Sep 16 22:08:15 CEST 2010


On the Freescale P1022, the DIU and the LBC share address pins, which means
that when the DIU is active (e.g. the console is on the DVI display), NOR flash
cannot be accessed.  So we use the weak accessor function feature of the CFI
flash code to temporarily switch the pin mux from LBC to DIU whenever we want
to read or write flash.  This has a significant performance penalty, but it's
the only way to make it work.

This change allows the 'saveenv' command to work when the video display is
enabled.  Writing to flash with the 'cp' command works, but reading from flash
with the 'md' and 'cp' commands does not.  Also, while flash is being written
to, the video display will be blank.

Signed-off-by: Timur Tabi <timur at freescale.com>
---
 board/freescale/p1022ds/diu.c |  205 +++++++++++++++++++++++++++++++++++++++--
 include/configs/P1022DS.h     |    6 +
 2 files changed, 203 insertions(+), 8 deletions(-)

diff --git a/board/freescale/p1022ds/diu.c b/board/freescale/p1022ds/diu.c
index be6e9a8..1d50ed2 100644
--- a/board/freescale/p1022ds/diu.c
+++ b/board/freescale/p1022ds/diu.c
@@ -14,8 +14,6 @@
 #include <command.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_FSL_DIU_FB
-
 #include "../common/ngpixis.h"
 #include "../common/fsl_diu_fb.h"
 
@@ -24,7 +22,13 @@
 #include <video_fb.h>
 #endif
 
-#define PX_BRDCFG0_ELBC_DIU	0x02
+/* The CTL register is called 'csr' in the ngpixis_t structure */
+#define PX_CTL_ALTACC		0x80
+
+#define PX_BRDCFG0_ELBC_SPI_MASK	0xc0
+#define PX_BRDCFG0_ELBC_SPI_ELBC	0x00
+#define PX_BRDCFG0_ELBC_SPI_NULL	0xc0
+#define PX_BRDCFG0_ELBC_DIU		0x02
 
 #define PX_BRDCFG1_DVIEN	0x80
 #define PX_BRDCFG1_DFPEN	0x40
@@ -63,6 +67,15 @@
 #define AD_DEFAULT
 static int xres, yres;
 
+/* Variables used by the DIU/LBC switching code.  It's safe to makes these
+ * global, because the DIU requires DDR, so we'll only run this code after
+ * relocation.
+ */
+static u8 px_brdcfg0;
+static u32 pmuxcr;
+static void *lbc_lcs0_ba;
+static void *lbc_lcs1_ba;
+
 void diu_set_pixel_clock(unsigned int pixclock)
 {
 	ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
@@ -88,6 +101,10 @@ int p1022ds_diu_init(void)
 	u32 pixel_format;
 	u8 temp;
 
+	/* 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);
+
 	pixel_format = cpu_to_le32(AD_BYTE_F | (3 << AD_ALPHA_C_SHIFT) |
 		(0 << AD_BLUE_C_SHIFT) | (1 << AD_GREEN_C_SHIFT) |
 		(2 << AD_RED_C_SHIFT) | (8 << AD_COMP_3_SHIFT) |
@@ -114,17 +131,23 @@ int p1022ds_diu_init(void)
 	out_8(&pixis->brdcfg1, temp);
 
 	/*
+	 * Enable PIXIS indirect access mode.  This is a hack that allows us to
+	 * access PIXIS registers even when the LBC pins have been muxed to the
+	 * DIU.
+	 */
+	setbits_8(&pixis->csr, PX_CTL_ALTACC);
+
+	/*
 	 * Route the LAD pins to the DIU.  This will disable access to the eLBC,
 	 * which means we won't be able to read/write any NOR flash addresses!
 	 */
-	out_8(&pixis->brdcfg0, in_8(&pixis->brdcfg0) | PX_BRDCFG0_ELBC_DIU);
-	/* we must do the dummy read from eLBC to sync the write as above */
-	in_8(&pixis->brdcfg0);
+	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);
 
 	/* Setting PMUXCR to switch to DVI from ELBC */
-	/* Set pmuxcr to allow both i2c1 and i2c2 */
 	clrsetbits_be32(&gur->pmuxcr, 0xc0000000, 0x40000000);
-	in_be32(&gur->pmuxcr);
+	pmuxcr = in_be32(&gur->pmuxcr);
 
 	return fsl_diu_init(xres, pixel_format, 0);
 }
@@ -169,4 +192,170 @@ void *video_hw_init(void)
 
 #endif
 
+#ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
+
+#define PMUXCR_ELBCDIU_MASK	0xc0000000
+#define PMUXCR_ELBCDIU_NOR16	0x80000000
+/**
+ * set_mux_to_lbc - disable the DIU so that we can read/write to elbc
+ *
+ * On the Freescale P1022, the DIU video signal and the LBC address/data lines
+ * share the same pins, which means that when the DIU is active (e.g. the
+ * console is on the DVI display), NOR flash cannot be accessed.  So we use the
+ * weak accessor feature of the CFI flash code to temporarily switch the pin
+ * mux from DIU to LBC whenever we want to read or write flash.  This has a
+ * significant performance penalty, but it's the only way to make it work.
+ *
+ * There are two muxes: one on the chip, and one on the board. The chip mux
+ * controls whether the pins are used for the DIU or the LBC, and it is
+ * set via PMUXCR.  The board mux controls whether those signals go to
+ * the video connector or the NOR flash chips, and it is set via the ngPIXIS.
+ */
+static int set_mux_to_lbc(void)
+{
+	ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+
+	/* Switch the muxes only if they're currently set to DIU mode */
+	if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) == PMUXCR_ELBCDIU_NOR16) {
+		/*
+		 * 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);
+
+		/*
+		 * Disable indirect PIXIS mode
+		 */
+		out_8(lbc_lcs0_ba, offsetof(ngpixis_t, csr));
+		clrbits_8(lbc_lcs1_ba, PX_CTL_ALTACC);
+
+		/*
+		 * Set the chip mux to LBC mode, so that writes go to flash.
+		 */
+		out_be32(&gur->pmuxcr, (pmuxcr & ~PMUXCR_ELBCDIU_MASK) |
+			 PMUXCR_ELBCDIU_NOR16);
+		in_be32(&gur->pmuxcr);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * set_mux_to_diu - re-enable the DIU muxing
+ *
+ * This function restores the chip and board muxing to point to the DIU.
+ */
+static void set_mux_to_diu(void)
+{
+	ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+
+	/* 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);
+	in_8(lbc_lcs1_ba);
+
+	/* Set the chip mux to DIU mode. */
+	out_be32(&gur->pmuxcr, pmuxcr);
+	in_be32(&gur->pmuxcr);
+}
+
+void flash_write8(u8 value, void *addr)
+{
+	int sw = set_mux_to_lbc();
+
+	__raw_writeb(value, addr);
+	if (sw)
+		set_mux_to_diu();
+}
+
+void flash_write16(u16 value, void *addr)
+{
+	int sw = set_mux_to_lbc();
+
+	__raw_writew(value, addr);
+	if (sw)
+		set_mux_to_diu();
+}
+
+void flash_write32(u32 value, void *addr)
+{
+	int sw = set_mux_to_lbc();
+
+	__raw_writel(value, addr);
+	if (sw)
+		set_mux_to_diu();
+}
+
+void flash_write64(u64 value, void *addr)
+{
+	int sw = set_mux_to_lbc();
+
+	/* There is no __raw_writeq(), so do the write manually */
+	*(volatile u64 *)addr = value;
+	if (sw)
+		set_mux_to_diu();
+}
+
+u8 flash_read8(void *addr)
+{
+	u8 ret;
+
+	int sw = set_mux_to_lbc();
+
+	ret = __raw_readb(addr);
+	if (sw)
+		set_mux_to_diu();
+
+	return ret;
+}
+
+u16 flash_read16(void *addr)
+{
+	u16 ret;
+
+	int sw = set_mux_to_lbc();
+
+	ret = __raw_readw(addr);
+	if (sw)
+		set_mux_to_diu();
+
+	return ret;
+}
+
+u32 flash_read32(void *addr)
+{
+	u32 ret;
+
+	int sw = set_mux_to_lbc();
+
+	ret = __raw_readl(addr);
+	if (sw)
+		set_mux_to_diu();
+
+	return ret;
+}
+
+u64 flash_read64(void *addr)
+{
+	u64 ret;
+
+	int sw = set_mux_to_lbc();
+
+	ret = *(volatile u64 *)addr;
+	if (sw)
+		set_mux_to_diu();
+
+	return ret;
+}
+
 #endif
diff --git a/include/configs/P1022DS.h b/include/configs/P1022DS.h
index d518c69..a4910a6 100644
--- a/include/configs/P1022DS.h
+++ b/include/configs/P1022DS.h
@@ -190,6 +190,12 @@
 #define CONFIG_VGA_AS_SINGLE_DEVICE
 #define CONFIG_VIDEO_LOGO
 #define CONFIG_VIDEO_BMP_LOGO
+#define CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS
+/*
+ * With CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS, flash I/O is really slow, so
+ * disable empty flash sector detection, which is I/O-intensive.
+ */
+#undef CONFIG_SYS_FLASH_EMPTY_INFO
 #endif
 
 /*
-- 
1.7.2.3




More information about the U-Boot mailing list