[U-Boot] [PATCH 12/19] fix: nand: pxa3xx: Add SoC-specific enable function

kostap at marvell.com kostap at marvell.com
Wed Aug 29 08:56:11 UTC 2018


From: Igal Liberman <igall at marvell.com>

Add SoC-dependent function to the NAND driver for selecting
NAND interface in DEVBUS MUX register.
This selection is done in the BootROM if the boot device is NAND,
but may be missing othervise.
The NAND is selected only if it is enabled in the DT file.
This patch is fixing NAND access problems for configurations
that use non-NAND devices for boot (like SPI).

Signed-off-by: Igal Liberman <igall at marvell.com>
Signed-off-by: Konstantin Porotchkin <kostap at marvell.com>
Signed-off-by: David Sniatkiwicz <davidsn at marvell.com>
Cc: Stefan Roese <sr at denx.de>
Cc: Simon Glass <sjg at chromium.org>
---
 arch/arm/dts/armada-cp110-master.dtsi  |  7 +++-
 arch/arm/mach-mvebu/armada8k/cpu.c     | 18 ---------
 arch/arm/mach-mvebu/armada8k/soc.c     | 30 ++++++++++++++
 arch/arm/mach-mvebu/cpu.c              | 12 +++++-
 arch/arm/mach-mvebu/include/mach/cpu.h |  3 +-
 drivers/mtd/nand/pxa3xx_nand.c         | 74 +++++++++++++++++++++++++++++-----
 6 files changed, 114 insertions(+), 30 deletions(-)

diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi
index 551d00d..02cee94 100644
--- a/arch/arm/dts/armada-cp110-master.dtsi
+++ b/arch/arm/dts/armada-cp110-master.dtsi
@@ -276,7 +276,12 @@
 
 			cpm_nand: nand at 720000 {
 				compatible = "marvell,mvebu-pxa3xx-nand";
-				reg = <0x720000 0x100>;
+				reg = <0x720000 0x100>,
+				      <0x440700 0x20>,
+				      <0x440208 0x20>;
+				reg-names = "ctrl_base",
+					    "flash_clock",
+					    "dev_mux";
 				#address-cells = <1>;
 
 				clocks = <&cpm_syscon0 1 2>;
diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c
index dd028e5..77e9400 100644
--- a/arch/arm/mach-mvebu/armada8k/cpu.c
+++ b/arch/arm/mach-mvebu/armada8k/cpu.c
@@ -109,24 +109,6 @@ void reset_cpu(ulong ignored)
 	writel(reg, RFU_GLOBAL_SW_RST);
 }
 
-/*
- * TODO - implement this functionality using platform
- *        clock driver once it gets available
- * Return NAND clock in Hz
- */
-u32 mvebu_get_nand_clock(void)
-{
-	unsigned long NAND_FLASH_CLK_CTRL = 0xF2440700UL;
-	unsigned long NF_CLOCK_SEL_MASK = 0x1;
-	u32 reg;
-
-	reg = readl(NAND_FLASH_CLK_CTRL);
-	if (reg & NF_CLOCK_SEL_MASK)
-		return 400 * 1000000;
-	else
-		return 250 * 1000000;
-}
-
 #if defined(CONFIG_DISPLAY_BOARDINFO)
 int print_cpuinfo(void)
 {
diff --git a/arch/arm/mach-mvebu/armada8k/soc.c b/arch/arm/mach-mvebu/armada8k/soc.c
index 511c734..faf1405 100644
--- a/arch/arm/mach-mvebu/armada8k/soc.c
+++ b/arch/arm/mach-mvebu/armada8k/soc.c
@@ -14,6 +14,10 @@
 #define SW_REV_STATUS_OFFSET		16
 #define SW_REV_STATUS_MASK		0xf
 
+#define NF_CLOCK_SEL_MASK		0x1
+#define SOC_MUX_NAND_EN_MASK		0x1
+#define CLOCK_1Mhz			1000000
+
 struct mochi_module {
 	u32 module_type;
 	u32 module_rev;
@@ -128,3 +132,29 @@ void soc_print_device_info(void)
 	else
 		printf("CP%x-A%d\n", cp_type, cp_rev);
 }
+#ifdef CONFIG_NAND_PXA3XX
+/* Return NAND clock in Hz */
+u32 mvebu_get_nand_clock(void __iomem *nand_flash_clk_ctrl_reg)
+{
+	u32 reg;
+
+	if (!nand_flash_clk_ctrl_reg)
+		return 0;
+
+	reg = readl(nand_flash_clk_ctrl_reg);
+	if (reg & NF_CLOCK_SEL_MASK)
+		return 400 * CLOCK_1Mhz;
+	else
+		return 250 * CLOCK_1Mhz;
+}
+
+/* Select NAND in the device bus multiplexer */
+void mvebu_nand_select(void __iomem *soc_dev_multiplex_reg)
+{
+	if (!soc_dev_multiplex_reg)
+		return;
+
+	setbits_le32(soc_dev_multiplex_reg, SOC_MUX_NAND_EN_MASK);
+}
+#endif
+
diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c
index 0d2d398..b1d1b1d 100644
--- a/arch/arm/mach-mvebu/cpu.c
+++ b/arch/arm/mach-mvebu/cpu.c
@@ -15,6 +15,8 @@
 #define DDR_BASE_CS_OFF(n)	(0x0000 + ((n) << 3))
 #define DDR_SIZE_CS_OFF(n)	(0x0004 + ((n) << 3))
 
+#define SOC_MUX_NAND_EN_MASK		0x1
+
 static struct mbus_win windows[] = {
 	/* SPI */
 	{ MBUS_SPI_BASE, MBUS_SPI_SIZE,
@@ -465,7 +467,7 @@ int arch_cpu_init(void)
 }
 #endif /* CONFIG_ARCH_CPU_INIT */
 
-u32 mvebu_get_nand_clock(void)
+u32 mvebu_get_nand_clock(void __iomem *unused)
 {
 	u32 reg;
 
@@ -479,6 +481,14 @@ u32 mvebu_get_nand_clock(void)
 		  NAND_ECC_DIVCKL_RATIO_MASK) >> NAND_ECC_DIVCKL_RATIO_OFFS);
 }
 
+void mvebu_nand_select(void __iomem *soc_dev_multiplex_reg)
+{
+	if (!soc_dev_multiplex_reg)
+		return;
+
+	setbits_le32(soc_dev_multiplex_reg, SOC_MUX_NAND_EN_MASK);
+}
+
 /*
  * SOC specific misc init
  */
diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h
index d104210..e892715 100644
--- a/arch/arm/mach-mvebu/include/mach/cpu.h
+++ b/arch/arm/mach-mvebu/include/mach/cpu.h
@@ -135,7 +135,8 @@ unsigned int mvebu_sdram_bs(enum memory_bank bank);
 void mvebu_sdram_size_adjust(enum memory_bank bank);
 int mvebu_mbus_probe(struct mbus_win windows[], int count);
 int mvebu_soc_family(void);
-u32 mvebu_get_nand_clock(void);
+u32 mvebu_get_nand_clock(void __iomem *maybe_unused);
+void mvebu_nand_select(void __iomem *maybe_unused);
 
 void return_to_bootrom(void);
 
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 5cc75de..b64dd0d 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -249,6 +249,10 @@ struct pxa3xx_nand_info {
 	uint32_t		ndcb1;
 	uint32_t		ndcb2;
 	uint32_t		ndcb3;
+
+	/* SOC related registers for nand */
+	void __iomem		*nand_flash_clk_ctrl_reg;
+	void __iomem		*soc_dev_multiplex_reg;
 };
 
 static struct pxa3xx_nand_timing timing[] = {
@@ -349,13 +353,20 @@ static enum pxa3xx_nand_variant pxa3xx_nand_get_variant(void)
 	return PXA3XX_NAND_VARIANT_ARMADA370;
 }
 
-static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
-				   const struct pxa3xx_nand_timing *t)
+static int pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
+				  const struct pxa3xx_nand_timing *t)
 {
 	struct pxa3xx_nand_info *info = host->info_data;
-	unsigned long nand_clk = mvebu_get_nand_clock();
+	unsigned long nand_clk;
 	uint32_t ndtr0, ndtr1;
 
+	nand_clk = mvebu_get_nand_clock(info->nand_flash_clk_ctrl_reg);
+	if (!nand_clk) {
+		dev_err(&host->info->pdev->dev,
+			"Missinig flash clock register\n");
+		return -EINVAL;
+	}
+
 	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |
 		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |
 		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |
@@ -371,14 +382,16 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
 	info->ndtr1cs0 = ndtr1;
 	nand_writel(info, NDTR0CS0, ndtr0);
 	nand_writel(info, NDTR1CS0, ndtr1);
+
+	return 0;
 }
 
-static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
-				       const struct nand_sdr_timings *t)
+static int pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
+				      const struct nand_sdr_timings *t)
 {
 	struct pxa3xx_nand_info *info = host->info_data;
 	struct nand_chip *chip = &host->chip;
-	unsigned long nand_clk = mvebu_get_nand_clock();
+	unsigned long nand_clk;
 	uint32_t ndtr0, ndtr1;
 
 	u32 tCH_min = DIV_ROUND_UP(t->tCH_min, 1000);
@@ -391,6 +404,13 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
 	u32 tWHR_min = DIV_ROUND_UP(t->tWHR_min, 1000);
 	u32 tAR_min = DIV_ROUND_UP(t->tAR_min, 1000);
 
+	nand_clk = mvebu_get_nand_clock(info->nand_flash_clk_ctrl_reg);
+	if (!nand_clk) {
+		dev_err(&host->info->pdev->dev,
+			"Missinig flash clock register\n");
+		return -EINVAL;
+	}
+
 	/* fallback to a default value if tR = 0 */
 	if (!tR)
 		tR = 20000;
@@ -410,6 +430,8 @@ static void pxa3xx_nand_set_sdr_timing(struct pxa3xx_nand_host *host,
 	info->ndtr1cs0 = ndtr1;
 	nand_writel(info, NDTR0CS0, ndtr0);
 	nand_writel(info, NDTR1CS0, ndtr1);
+
+	return 0;
 }
 
 static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host)
@@ -419,7 +441,7 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host)
 	struct pxa3xx_nand_info *info = host->info_data;
 	const struct pxa3xx_nand_flash *f = NULL;
 	struct mtd_info *mtd = nand_to_mtd(&host->chip);
-	int mode, id, ntypes, i;
+	int mode, id, ntypes, i, ret;
 
 	mode = onfi_get_async_timing_mode(chip);
 	if (mode == ONFI_TIMING_MODE_UNKNOWN) {
@@ -442,7 +464,9 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host)
 			return -EINVAL;
 		}
 
-		pxa3xx_nand_set_timing(host, f->timing);
+		ret = pxa3xx_nand_set_timing(host, f->timing);
+		if (ret)
+			return ret;
 
 		if (f->flash_width == 16) {
 			info->reg_ndcr |= NDCR_DWIDTH_M;
@@ -459,7 +483,9 @@ static int pxa3xx_nand_init_timings(struct pxa3xx_nand_host *host)
 		if (IS_ERR(timings))
 			return PTR_ERR(timings);
 
-		pxa3xx_nand_set_sdr_timing(host, timings);
+		ret = pxa3xx_nand_set_sdr_timing(host, timings);
+		if (ret)
+			return ret;
 	}
 
 	return 0;
@@ -1593,6 +1619,8 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info)
 	struct pxa3xx_nand_platform_data *pdata;
 	const void *blob = gd->fdt_blob;
 	int node = -1;
+	int index;
+	fdt_addr_t addr;
 
 	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -1614,6 +1642,26 @@ static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info)
 			(void __iomem *)fdtdec_get_addr_size_auto_noparent(
 					blob, node, "reg", 0, NULL, true);
 
+		index = fdt_stringlist_search(blob, node, "reg-names",
+					      "flash_clock");
+		if (index > 0) {
+			addr = fdtdec_get_addr_size_auto_noparent(
+					blob, node, "reg", index, NULL, true);
+			if (addr != FDT_ADDR_T_NONE)
+				info->nand_flash_clk_ctrl_reg =
+					(void __iomem *)addr;
+		}
+
+		index = fdt_stringlist_search(blob, node, "reg-names",
+					      "dev_mux");
+		if (index > 0) {
+			addr = fdtdec_get_addr_size_auto_noparent(
+					blob, node, "reg", index, NULL, true);
+			if (addr != FDT_ADDR_T_NONE)
+				info->soc_dev_multiplex_reg =
+					(void __iomem *)addr;
+		}
+
 		pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1);
 		if (pdata->num_cs != 1) {
 			pr_err("pxa3xx driver supports single CS only\n");
@@ -1660,6 +1708,14 @@ static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
 
 	pdata = info->pdata;
 
+	/* If the NAND flash is enabled in DT, but the boot image is not
+	 * running from NAND, it may be needed to enable NAND on SOC
+	 * DEVBUS MUX level.
+	 * When the boot device is NAND, such configuration is done
+	 * in the BootROM.
+	 */
+	mvebu_nand_select(info->soc_dev_multiplex_reg);
+
 	ret = alloc_nand_resource(info);
 	if (ret) {
 		dev_err(&pdev->dev, "alloc nand resource failed\n");
-- 
2.7.4



More information about the U-Boot mailing list