public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture
@ 2022-09-28  8:45 Dario Binacchi
  2022-09-28  8:45 ` [PATCH 1/7] dm: clk: add missing stub when CONFIG_CLK is deactivated Dario Binacchi
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Dario Binacchi @ 2022-09-28  8:45 UTC (permalink / raw)
  To: u-boot
  Cc: Amarula patchwork, michael, Dario Binacchi, Fabio Estevam,
	Giulio Benetti, Han Xu, Heinrich Schuchardt, Lukasz Majewski,
	Miquel Raynal, NXP i.MX U-Boot Team, Neil Armstrong,
	Sean Anderson, Simon Glass, Stefano Babic


Debugging and testing the series made it necessary to add some
patches to fix correct clock access and compilation issues raised
by buildman.


Dario Binacchi (3):
  dm: clk: add missing stub when CONFIG_CLK is deactivated
  mtd: mxs_nand: don't get the gpmi_apbh_dma clock
  mtd: mxs_nand: get the clock with the right name

Michael Trimarchi (4):
  clk: imx: gate2 support shared counter and relative clock functions
  clk: imx: clk-imx8mn add gpmi nand clocks
  imx: gpmi: Add register needed to control nand bus timing
  mtd: mxs_nand: Support EDO mode for imx8mn architecture

 arch/arm/include/asm/mach-imx/regs-gpmi.h |   9 +
 drivers/clk/imx/clk-gate2.c               |  15 +-
 drivers/clk/imx/clk-imx8mn.c              |  14 ++
 drivers/clk/imx/clk.h                     |  27 ++-
 drivers/mtd/nand/raw/mxs_nand.c           | 200 ++++++++++++++++++++++
 drivers/mtd/nand/raw/mxs_nand_dt.c        |  79 +++++----
 include/clk.h                             |  32 +++-
 include/mxs_nand.h                        |   3 +
 8 files changed, 333 insertions(+), 46 deletions(-)

-- 
2.32.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/7] dm: clk: add missing stub when CONFIG_CLK is deactivated
  2022-09-28  8:45 [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture Dario Binacchi
@ 2022-09-28  8:45 ` Dario Binacchi
  2022-09-28 16:41   ` Sean Anderson
  2022-09-28  8:45 ` [PATCH 2/7] clk: imx: gate2 support shared counter and relative clock functions Dario Binacchi
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Dario Binacchi @ 2022-09-28  8:45 UTC (permalink / raw)
  To: u-boot
  Cc: Amarula patchwork, michael, Dario Binacchi, Giulio Benetti,
	Heinrich Schuchardt, Neil Armstrong, Sean Anderson, Simon Glass

Add missing stub for functions [devm_]clk_...() when CONFIG_CLK is
deactivated.

Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 include/clk.h | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/include/clk.h b/include/clk.h
index 76bb64bb5ee0..407513e0fa29 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -88,8 +88,9 @@ struct clk_bulk {
 	unsigned int count;
 };
 
-#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK)
 struct phandle_1_arg;
+
+#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK)
 /**
  * clk_get_by_phandle() - Get a clock by its phandle information (of-platadata)
  * @dev: Device containing the phandle
@@ -258,12 +259,26 @@ int clk_release_all(struct clk *clk, int count);
 void devm_clk_put(struct udevice *dev, struct clk *clk);
 
 #else
+
+static inline int clk_get_by_phandle(struct udevice *dev, const
+				     struct phandle_1_arg *cells,
+				     struct clk *clk)
+{
+	return -ENOSYS;
+}
+
 static inline int clk_get_by_index(struct udevice *dev, int index,
 				   struct clk *clk)
 {
 	return -ENOSYS;
 }
 
+static inline int clk_get_by_index_nodev(ofnode node, int index,
+					 struct clk *clk)
+{
+	return -ENOSYS;
+}
+
 static inline int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk)
 {
 	return -ENOSYS;
@@ -275,6 +290,17 @@ static inline int clk_get_by_name(struct udevice *dev, const char *name,
 	return -ENOSYS;
 }
 
+static inline struct clk *devm_clk_get(struct udevice *dev, const char *id)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline struct clk *devm_clk_get_optional(struct udevice *dev,
+						const char *id)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
 static inline int
 clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk)
 {
@@ -285,6 +311,10 @@ static inline int clk_release_all(struct clk *clk, int count)
 {
 	return -ENOSYS;
 }
+
+static inline void devm_clk_put(struct udevice *dev, struct clk *clk)
+{
+}
 #endif
 
 /**
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/7] clk: imx: gate2 support shared counter and relative clock functions
  2022-09-28  8:45 [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture Dario Binacchi
  2022-09-28  8:45 ` [PATCH 1/7] dm: clk: add missing stub when CONFIG_CLK is deactivated Dario Binacchi
@ 2022-09-28  8:45 ` Dario Binacchi
  2022-09-28  8:45 ` [PATCH 3/7] clk: imx: clk-imx8mn add gpmi nand clocks Dario Binacchi
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Dario Binacchi @ 2022-09-28  8:45 UTC (permalink / raw)
  To: u-boot
  Cc: Amarula patchwork, michael, Dario Binacchi, Lukasz Majewski,
	Sean Anderson, Stefano Babic

From: Michael Trimarchi <michael@amarulasolutions.com>

Add shared counter in order to avoid to swich off clock that
are already used.

Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/clk-gate2.c | 15 ++++++++++++++-
 drivers/clk/imx/clk.h       | 27 +++++++++++++++++++++++----
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index 40b2d4caab49..da2723023778 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -20,6 +20,7 @@
 #include <clk-uclass.h>
 #include <dm/device.h>
 #include <dm/devres.h>
+#include <linux/bug.h>
 #include <linux/clk-provider.h>
 #include <clk.h>
 #include "clk.h"
@@ -33,6 +34,7 @@ struct clk_gate2 {
 	u8		bit_idx;
 	u8		cgr_val;
 	u8		flags;
+	unsigned int	*share_count;
 };
 
 #define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk)
@@ -42,6 +44,9 @@ static int clk_gate2_enable(struct clk *clk)
 	struct clk_gate2 *gate = to_clk_gate2(clk);
 	u32 reg;
 
+	if (gate->share_count && (*gate->share_count)++ > 0)
+		return 0;
+
 	reg = readl(gate->reg);
 	reg &= ~(3 << gate->bit_idx);
 	reg |= gate->cgr_val << gate->bit_idx;
@@ -55,6 +60,13 @@ static int clk_gate2_disable(struct clk *clk)
 	struct clk_gate2 *gate = to_clk_gate2(clk);
 	u32 reg;
 
+	if (gate->share_count) {
+		if (WARN_ON(*gate->share_count == 0))
+			return 0;
+		else if (--(*gate->share_count) > 0)
+			return 0;
+	}
+
 	reg = readl(gate->reg);
 	reg &= ~(3 << gate->bit_idx);
 	writel(reg, gate->reg);
@@ -82,7 +94,7 @@ static const struct clk_ops clk_gate2_ops = {
 struct clk *clk_register_gate2(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 bit_idx, u8 cgr_val,
-		u8 clk_gate2_flags)
+		u8 clk_gate2_flags, unsigned int *share_count)
 {
 	struct clk_gate2 *gate;
 	struct clk *clk;
@@ -96,6 +108,7 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
 	gate->bit_idx = bit_idx;
 	gate->cgr_val = cgr_val;
 	gate->flags = clk_gate2_flags;
+	gate->share_count = share_count;
 
 	clk = &gate->clk;
 
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 46dee35a6735..11f5dca1175b 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -53,7 +53,7 @@ struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
 struct clk *clk_register_gate2(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
 		void __iomem *reg, u8 bit_idx, u8 cgr_val,
-		u8 clk_gate_flags);
+		u8 clk_gate_flags, unsigned int *share_count);
 
 struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
 			  const char *parent_name, void __iomem *base,
@@ -63,7 +63,26 @@ static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
 					void __iomem *reg, u8 shift)
 {
 	return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
-			shift, 0x3, 0);
+			shift, 0x3, 0, NULL);
+}
+
+static inline struct clk *imx_clk_gate2_shared(const char *name,
+					       const char *parent,
+					       void __iomem *reg, u8 shift,
+					       unsigned int *share_count)
+{
+	return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+				  shift, 0x3, 0, share_count);
+}
+
+static inline struct clk *imx_clk_gate2_shared2(const char *name,
+						const char *parent,
+						void __iomem *reg, u8 shift,
+						unsigned int *share_count)
+{
+	return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
+				  CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
+				  share_count);
 }
 
 static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
@@ -71,7 +90,7 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
 {
 	return clk_register_gate2(NULL, name, parent,
 			CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
-			reg, shift, 0x3, 0);
+			reg, shift, 0x3, 0, NULL);
 }
 
 static inline struct clk *imx_clk_gate4_flags(const char *name,
@@ -80,7 +99,7 @@ static inline struct clk *imx_clk_gate4_flags(const char *name,
 {
 	return clk_register_gate2(NULL, name, parent,
 			flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
-			reg, shift, 0x3, 0);
+			reg, shift, 0x3, 0, NULL);
 }
 
 static inline struct clk *imx_clk_fixed_factor(const char *name,
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/7] clk: imx: clk-imx8mn add gpmi nand clocks
  2022-09-28  8:45 [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture Dario Binacchi
  2022-09-28  8:45 ` [PATCH 1/7] dm: clk: add missing stub when CONFIG_CLK is deactivated Dario Binacchi
  2022-09-28  8:45 ` [PATCH 2/7] clk: imx: gate2 support shared counter and relative clock functions Dario Binacchi
@ 2022-09-28  8:45 ` Dario Binacchi
  2022-09-28  8:45 ` [PATCH 4/7] imx: gpmi: Add register needed to control nand bus timing Dario Binacchi
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Dario Binacchi @ 2022-09-28  8:45 UTC (permalink / raw)
  To: u-boot
  Cc: Amarula patchwork, michael, Dario Binacchi, Lukasz Majewski,
	Sean Anderson, Stefano Babic

From: Michael Trimarchi <michael@amarulasolutions.com>

Add gpmi nand clock. Those clock can be used in mxs nand driver
to run nand to EDO mode 5, 4, ...

Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/clk/imx/clk-imx8mn.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index 15d7599cfb7d..35e0d935d390 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -15,6 +15,8 @@
 
 #include "clk.h"
 
+static u32 share_count_nand;
+
 static const char *pll_ref_sels[] = { "clock-osc-24m", "dummy", "dummy", "dummy", };
 static const char *dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
 static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
@@ -90,6 +92,10 @@ static const char *imx8mn_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sy
 static const char *imx8mn_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m", "sys_pll2_500m",
 					   "audio_pll2_out", "sys_pll1_266m", "sys_pll3_out", "sys_pll1_100m", };
 
+static const char * const imx8mn_nand_sels[] = {"osc_24m", "sys_pll2_500m", "audio_pll1_out",
+						"sys_pll1_400m", "audio_pll2_out", "sys_pll3_out",
+						"sys_pll2_250m", "video_pll1_out", };
+
 static const char * const imx8mn_usb_core_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
 						"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
 						"clk_ext3", "audio_pll2_out", };
@@ -268,6 +274,8 @@ static int imx8mn_clk_probe(struct udevice *dev)
 	clk_dm(IMX8MN_CLK_USDHC3,
 	       imx8m_clk_composite("usdhc3", imx8mn_usdhc3_sels,
 				   base + 0xbc80));
+	clk_dm(IMX8MN_CLK_NAND,
+	       imx8m_clk_composite("nand", imx8mn_nand_sels, base + 0xab00));
 	clk_dm(IMX8MN_CLK_QSPI,
 	       imx8m_clk_composite("qspi", imx8mn_qspi_sels, base + 0xab80));
 	clk_dm(IMX8MN_CLK_USB_CORE_REF,
@@ -299,6 +307,12 @@ static int imx8mn_clk_probe(struct udevice *dev)
 	       imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
 	clk_dm(IMX8MN_CLK_QSPI_ROOT,
 	       imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
+	clk_dm(IMX8MN_CLK_NAND_ROOT,
+	       imx_clk_gate2_shared2("nand_root_clk", "nand", base + 0x4300, 0, &share_count_nand));
+	clk_dm(IMX8MN_CLK_NAND_USDHC_BUS_RAWNAND_CLK,
+	       imx_clk_gate2_shared2("nand_usdhc_rawnand_clk",
+				     "nand_usdhc_bus", base + 0x4300, 0,
+				     &share_count_nand));
 	clk_dm(IMX8MN_CLK_USB1_CTRL_ROOT,
 		imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
 
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/7] imx: gpmi: Add register needed to control nand bus timing
  2022-09-28  8:45 [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture Dario Binacchi
                   ` (2 preceding siblings ...)
  2022-09-28  8:45 ` [PATCH 3/7] clk: imx: clk-imx8mn add gpmi nand clocks Dario Binacchi
@ 2022-09-28  8:45 ` Dario Binacchi
  2022-09-28  8:45 ` [PATCH 5/7] mtd: mxs_nand: don't get the gpmi_apbh_dma clock Dario Binacchi
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Dario Binacchi @ 2022-09-28  8:45 UTC (permalink / raw)
  To: u-boot
  Cc: Amarula patchwork, michael, Dario Binacchi, Fabio Estevam,
	NXP i.MX U-Boot Team, Stefano Babic

From: Michael Trimarchi <michael@amarulasolutions.com>

It is used as delay for gpmi write strobe.

Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 arch/arm/include/asm/mach-imx/regs-gpmi.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/include/asm/mach-imx/regs-gpmi.h b/arch/arm/include/asm/mach-imx/regs-gpmi.h
index 33daa53c45df..7a1577863195 100644
--- a/arch/arm/include/asm/mach-imx/regs-gpmi.h
+++ b/arch/arm/include/asm/mach-imx/regs-gpmi.h
@@ -93,6 +93,11 @@ struct mxs_gpmi_regs {
 #define	GPMI_CTRL1_DECOUPLE_CS				(1 << 24)
 #define	GPMI_CTRL1_WRN_DLY_SEL_MASK			(0x3 << 22)
 #define	GPMI_CTRL1_WRN_DLY_SEL_OFFSET			22
+#define	GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS			0x0
+#define	GPMI_CTRL1_WRN_DLY_SEL_6_TO_10NS		0x1
+#define	GPMI_CTRL1_WRN_DLY_SEL_7_TO_12NS		0x2
+#define	GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY			0x3
+
 #define	GPMI_CTRL1_TIMEOUT_IRQ_EN			(1 << 20)
 #define	GPMI_CTRL1_GANGED_RDYBUSY			(1 << 19)
 #define	GPMI_CTRL1_BCH_MODE				(1 << 18)
@@ -111,6 +116,10 @@ struct mxs_gpmi_regs {
 #define	GPMI_CTRL1_ATA_IRQRDY_POLARITY			(1 << 2)
 #define	GPMI_CTRL1_CAMERA_MODE				(1 << 1)
 #define	GPMI_CTRL1_GPMI_MODE				(1 << 0)
+#define	GPMI_CTRL1_CLEAR_MASK				(GPMI_CTRL1_WRN_DLY_SEL_MASK | \
+							 GPMI_CTRL1_DLL_ENABLE | \
+							 GPMI_CTRL1_RDN_DELAY_MASK | \
+							 GPMI_CTRL1_HALF_PERIOD)
 
 #define	GPMI_TIMING0_ADDRESS_SETUP_MASK			(0xff << 16)
 #define	GPMI_TIMING0_ADDRESS_SETUP_OFFSET		16
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/7] mtd: mxs_nand: don't get the gpmi_apbh_dma clock
  2022-09-28  8:45 [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture Dario Binacchi
                   ` (3 preceding siblings ...)
  2022-09-28  8:45 ` [PATCH 4/7] imx: gpmi: Add register needed to control nand bus timing Dario Binacchi
@ 2022-09-28  8:45 ` Dario Binacchi
  2022-09-28  8:45 ` [PATCH 6/7] mtd: mxs_nand: get the clock with the right name Dario Binacchi
  2022-09-28  8:45 ` [PATCH 7/7] mtd: mxs_nand: Support EDO mode for imx8mn architecture Dario Binacchi
  6 siblings, 0 replies; 10+ messages in thread
From: Dario Binacchi @ 2022-09-28  8:45 UTC (permalink / raw)
  To: u-boot; +Cc: Amarula patchwork, michael, Dario Binacchi

This clock name is not present in any U-boot and Linux kernel device
tree.

Fixes: commit a59691280daca ("MXS_NAND: Add clock support for iMX8")
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/mtd/nand/raw/mxs_nand_dt.c | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c
index b9833a646f01..c1e784832f33 100644
--- a/drivers/mtd/nand/raw/mxs_nand_dt.c
+++ b/drivers/mtd/nand/raw/mxs_nand_dt.c
@@ -143,19 +143,6 @@ static int mxs_nand_dt_probe(struct udevice *dev)
 			debug("Can't enable gpmi_apb_bch clk: %d\n", ret);
 			return ret;
 		}
-
-		/* this clock is used for apbh_dma, since the apbh dma does not support DM,
-		  * we optionally enable it here
-		  */
-		ret = clk_get_by_name(dev, "gpmi_apbh_dma", &gpmi_clk);
-		if (ret < 0) {
-			debug("Can't get gpmi_apbh_dma clk: %d\n", ret);
-		} else {
-			ret = clk_enable(&gpmi_clk);
-			if (ret < 0) {
-				debug("Can't enable gpmi_apbh_dma clk: %d\n", ret);
-			}
-		}
 	}
 
 	return mxs_nand_init_ctrl(info);
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/7] mtd: mxs_nand: get the clock with the right name
  2022-09-28  8:45 [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture Dario Binacchi
                   ` (4 preceding siblings ...)
  2022-09-28  8:45 ` [PATCH 5/7] mtd: mxs_nand: don't get the gpmi_apbh_dma clock Dario Binacchi
@ 2022-09-28  8:45 ` Dario Binacchi
  2022-09-28  8:45 ` [PATCH 7/7] mtd: mxs_nand: Support EDO mode for imx8mn architecture Dario Binacchi
  6 siblings, 0 replies; 10+ messages in thread
From: Dario Binacchi @ 2022-09-28  8:45 UTC (permalink / raw)
  To: u-boot; +Cc: Amarula patchwork, michael, Dario Binacchi

Rename the gpmi_apb_bch clock name to gpmi_bch_apb, as you can find in
the device tree.

Fixes: commit a59691280daca ("MXS_NAND: Add clock support for iMX8")
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---

 drivers/mtd/nand/raw/mxs_nand_dt.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c
index c1e784832f33..94ee7ed9ec83 100644
--- a/drivers/mtd/nand/raw/mxs_nand_dt.c
+++ b/drivers/mtd/nand/raw/mxs_nand_dt.c
@@ -132,15 +132,15 @@ static int mxs_nand_dt_probe(struct udevice *dev)
 			return ret;
 		}
 
-		ret = clk_get_by_name(dev, "gpmi_apb_bch", &gpmi_clk);
+		ret = clk_get_by_name(dev, "gpmi_bch_apb", &gpmi_clk);
 		if (ret < 0) {
-			debug("Can't get gpmi_apb_bch clk: %d\n", ret);
+			debug("Can't get gpmi_bch_apb clk: %d\n", ret);
 			return ret;
 		}
 
 		ret = clk_enable(&gpmi_clk);
 		if (ret < 0) {
-			debug("Can't enable gpmi_apb_bch clk: %d\n", ret);
+			debug("Can't enable gpmi_bch_apb clk: %d\n", ret);
 			return ret;
 		}
 	}
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/7] mtd: mxs_nand: Support EDO mode for imx8mn architecture
  2022-09-28  8:45 [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture Dario Binacchi
                   ` (5 preceding siblings ...)
  2022-09-28  8:45 ` [PATCH 6/7] mtd: mxs_nand: get the clock with the right name Dario Binacchi
@ 2022-09-28  8:45 ` Dario Binacchi
  2022-10-09  8:40   ` Dario Binacchi
  6 siblings, 1 reply; 10+ messages in thread
From: Dario Binacchi @ 2022-09-28  8:45 UTC (permalink / raw)
  To: u-boot; +Cc: Amarula patchwork, michael, Dario Binacchi, Han Xu, Miquel Raynal

From: Michael Trimarchi <michael@amarulasolutions.com>

Add support for imx8mn architecture in order to run the NAND
in fast edo mode.

Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>

---

 drivers/mtd/nand/raw/mxs_nand.c    | 200 +++++++++++++++++++++++++++++
 drivers/mtd/nand/raw/mxs_nand_dt.c |  66 ++++++----
 include/mxs_nand.h                 |   3 +
 3 files changed, 242 insertions(+), 27 deletions(-)

diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c
index 7893e9d7e343..65eab4c8088a 100644
--- a/drivers/mtd/nand/raw/mxs_nand.c
+++ b/drivers/mtd/nand/raw/mxs_nand.c
@@ -14,6 +14,7 @@
  */
 
 #include <common.h>
+#include <clk.h>
 #include <cpu_func.h>
 #include <dm.h>
 #include <dm/device_compat.h>
@@ -26,10 +27,12 @@
 #include <asm/io.h>
 #include <asm/mach-imx/regs-bch.h>
 #include <asm/mach-imx/regs-gpmi.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/sizes.h>
 #include <linux/types.h>
+#include <linux/math64.h>
 
 #define	MXS_NAND_DMA_DESCRIPTOR_COUNT		4
 
@@ -49,6 +52,10 @@
 #endif
 
 #define	MXS_NAND_BCH_TIMEOUT			10000
+#define	USEC_PER_SEC				1000000
+#define	NSEC_PER_SEC				1000000000L
+
+#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period)
 
 struct nand_ecclayout fake_ecc_layout;
 
@@ -1344,6 +1351,196 @@ err1:
 	return ret;
 }
 
+/*
+ * <1> Firstly, we should know what's the GPMI-clock means.
+ *     The GPMI-clock is the internal clock in the gpmi nand controller.
+ *     If you set 100MHz to gpmi nand controller, the GPMI-clock's period
+ *     is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
+ *
+ * <2> Secondly, we should know what's the frequency on the nand chip pins.
+ *     The frequency on the nand chip pins is derived from the GPMI-clock.
+ *     We can get it from the following equation:
+ *
+ *         F = G / (DS + DH)
+ *
+ *         F  : the frequency on the nand chip pins.
+ *         G  : the GPMI clock, such as 100MHz.
+ *         DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
+ *         DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
+ *
+ * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
+ *     the nand EDO(extended Data Out) timing could be applied.
+ *     The GPMI implements a feedback read strobe to sample the read data.
+ *     The feedback read strobe can be delayed to support the nand EDO timing
+ *     where the read strobe may deasserts before the read data is valid, and
+ *     read data is valid for some time after read strobe.
+ *
+ *     The following figure illustrates some aspects of a NAND Flash read:
+ *
+ *                   |<---tREA---->|
+ *                   |             |
+ *                   |         |   |
+ *                   |<--tRP-->|   |
+ *                   |         |   |
+ *                  __          ___|__________________________________
+ *     RDN            \________/   |
+ *                                 |
+ *                                 /---------\
+ *     Read Data    --------------<           >---------
+ *                                 \---------/
+ *                                |     |
+ *                                |<-D->|
+ *     FeedbackRDN  ________             ____________
+ *                          \___________/
+ *
+ *          D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
+ *
+ *
+ * <4> Now, we begin to describe how to compute the right RDN_DELAY.
+ *
+ *  4.1) From the aspect of the nand chip pins:
+ *        Delay = (tREA + C - tRP)               {1}
+ *
+ *        tREA : the maximum read access time.
+ *        C    : a constant to adjust the delay. default is 4000ps.
+ *        tRP  : the read pulse width, which is exactly:
+ *                   tRP = (GPMI-clock-period) * DATA_SETUP
+ *
+ *  4.2) From the aspect of the GPMI nand controller:
+ *         Delay = RDN_DELAY * 0.125 * RP        {2}
+ *
+ *         RP   : the DLL reference period.
+ *            if (GPMI-clock-period > DLL_THRETHOLD)
+ *                   RP = GPMI-clock-period / 2;
+ *            else
+ *                   RP = GPMI-clock-period;
+ *
+ *            Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
+ *            is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
+ *            is 16000ps, but in mx6q, we use 12000ps.
+ *
+ *  4.3) since {1} equals {2}, we get:
+ *
+ *                     (tREA + 4000 - tRP) * 8
+ *         RDN_DELAY = -----------------------     {3}
+ *                           RP
+ */
+static void mxs_compute_timings(struct nand_chip *chip,
+				const struct nand_sdr_timings *sdr)
+{
+	struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
+	unsigned long clk_rate;
+	unsigned int dll_wait_time_us;
+	unsigned int dll_threshold_ps = nand_info->max_chain_delay;
+	unsigned int period_ps, reference_period_ps;
+	unsigned int data_setup_cycles, data_hold_cycles, addr_setup_cycles;
+	unsigned int tRP_ps;
+	bool use_half_period;
+	int sample_delay_ps, sample_delay_factor;
+	u16 busy_timeout_cycles;
+	u8 wrn_dly_sel;
+	u32 timing0;
+	u32 timing1;
+	u32 ctrl1n;
+
+	if (sdr->tRC_min >= 30000) {
+		/* ONFI non-EDO modes [0-3] */
+		clk_rate = 22000000;
+		wrn_dly_sel = GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
+	} else if (sdr->tRC_min >= 25000) {
+		/* ONFI EDO mode 4 */
+		clk_rate = 80000000;
+		wrn_dly_sel = GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+		debug("%s, setting ONFI onfi edo 4\n", __func__);
+	} else {
+		/* ONFI EDO mode 5 */
+		clk_rate = 100000000;
+		wrn_dly_sel = GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
+		debug("%s, setting ONFI onfi edo 5\n", __func__);
+	}
+
+	/* SDR core timings are given in picoseconds */
+	period_ps = div_u64((u64)NSEC_PER_SEC * 1000, clk_rate);
+
+	addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
+	data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
+	data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
+	busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max, period_ps);
+
+	timing0 = (addr_setup_cycles << GPMI_TIMING0_ADDRESS_SETUP_OFFSET) |
+		      (data_hold_cycles << GPMI_TIMING0_DATA_HOLD_OFFSET) |
+		      (data_setup_cycles << GPMI_TIMING0_DATA_SETUP_OFFSET);
+	timing1 = (busy_timeout_cycles * 4096) << GPMI_TIMING1_DEVICE_BUSY_TIMEOUT_OFFSET;
+
+	/*
+	 * Derive NFC ideal delay from {3}:
+	 *
+	 *                     (tREA + 4000 - tRP) * 8
+	 *         RDN_DELAY = -----------------------
+	 *                                RP
+	 */
+	if (period_ps > dll_threshold_ps) {
+		use_half_period = true;
+		reference_period_ps = period_ps / 2;
+	} else {
+		use_half_period = false;
+		reference_period_ps = period_ps;
+	}
+
+	tRP_ps = data_setup_cycles * period_ps;
+	sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8;
+	if (sample_delay_ps > 0)
+		sample_delay_factor = sample_delay_ps / reference_period_ps;
+	else
+		sample_delay_factor = 0;
+
+	ctrl1n = (wrn_dly_sel << GPMI_CTRL1_WRN_DLY_SEL_OFFSET);
+	if (sample_delay_factor)
+		ctrl1n |= (sample_delay_factor << GPMI_CTRL1_RDN_DELAY_OFFSET) |
+			GPMI_CTRL1_DLL_ENABLE |
+			(use_half_period ? GPMI_CTRL1_HALF_PERIOD : 0);
+
+	writel(timing0, &nand_info->gpmi_regs->hw_gpmi_timing0);
+	writel(timing1, &nand_info->gpmi_regs->hw_gpmi_timing1);
+
+	/*
+	 * Clear several CTRL1 fields, DLL must be disabled when setting
+	 * RDN_DELAY or HALF_PERIOD.
+	 */
+	writel(GPMI_CTRL1_CLEAR_MASK, &nand_info->gpmi_regs->hw_gpmi_ctrl1_clr);
+	writel(ctrl1n, &nand_info->gpmi_regs->hw_gpmi_ctrl1_set);
+
+	clk_set_rate(nand_info->gpmi_clk, clk_rate);
+
+	/* Wait 64 clock cycles before using the GPMI after enabling the DLL */
+	dll_wait_time_us = USEC_PER_SEC / clk_rate * 64;
+	if (!dll_wait_time_us)
+		dll_wait_time_us = 1;
+
+	/* Wait for the DLL to settle. */
+	udelay(dll_wait_time_us);
+}
+
+static int mxs_nand_setup_interface(struct mtd_info *mtd, int chipnr,
+				    const struct nand_data_interface *conf)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	const struct nand_sdr_timings *sdr;
+
+	sdr = nand_get_sdr_timings(conf);
+	if (IS_ERR(sdr))
+		return PTR_ERR(sdr);
+
+	/* Stop here if this call was just a check */
+	if (chipnr < 0)
+		return 0;
+
+	/* Do the actual derivation of the controller timings */
+	mxs_compute_timings(chip, sdr);
+
+	return 0;
+}
+
 int mxs_nand_init_spl(struct nand_chip *nand)
 {
 	struct mxs_nand_info *nand_info;
@@ -1432,6 +1629,9 @@ int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info)
 	nand->read_buf		= mxs_nand_read_buf;
 	nand->write_buf		= mxs_nand_write_buf;
 
+	if (nand_info->gpmi_clk)
+		nand->setup_data_interface = mxs_nand_setup_interface;
+
 	/* first scan to find the device and get the page size */
 	if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL))
 		goto err_free_buffers;
diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c
index 94ee7ed9ec83..a922a22b2730 100644
--- a/drivers/mtd/nand/raw/mxs_nand_dt.c
+++ b/drivers/mtd/nand/raw/mxs_nand_dt.c
@@ -22,22 +22,27 @@
 
 struct mxs_nand_dt_data {
 	unsigned int max_ecc_strength_supported;
+	int max_chain_delay; /* See the async EDO mode */
 };
 
 static const struct mxs_nand_dt_data mxs_nand_imx6q_data = {
 	.max_ecc_strength_supported = 40,
+	.max_chain_delay = 12000,
 };
 
 static const struct mxs_nand_dt_data mxs_nand_imx6sx_data = {
 	.max_ecc_strength_supported = 62,
+	.max_chain_delay = 12000,
 };
 
 static const struct mxs_nand_dt_data mxs_nand_imx7d_data = {
 	.max_ecc_strength_supported = 62,
+	.max_chain_delay = 12000,
 };
 
 static const struct mxs_nand_dt_data mxs_nand_imx8qxp_data = {
 	.max_ecc_strength_supported = 62,
+	.max_chain_delay = 12000,
 };
 
 static const struct udevice_id mxs_nand_dt_ids[] = {
@@ -72,8 +77,10 @@ static int mxs_nand_dt_probe(struct udevice *dev)
 	int ret;
 
 	data = (void *)dev_get_driver_data(dev);
-	if (data)
+	if (data) {
 		info->max_ecc_strength_supported = data->max_ecc_strength_supported;
+		info->max_chain_delay = data->max_chain_delay;
+	}
 
 	info->dev = dev;
 
@@ -92,44 +99,49 @@ static int mxs_nand_dt_probe(struct udevice *dev)
 
 	info->use_minimum_ecc = dev_read_bool(dev, "fsl,use-minimum-ecc");
 
-	if (IS_ENABLED(CONFIG_CLK) && IS_ENABLED(CONFIG_IMX8)) {
+	if (IS_ENABLED(CONFIG_CLK) &&
+	    (IS_ENABLED(CONFIG_IMX8) || IS_ENABLED(CONFIG_IMX8M))) {
 		/* Assigned clock already set clock */
 		struct clk gpmi_clk;
 
-		ret = clk_get_by_name(dev, "gpmi_io", &gpmi_clk);
-		if (ret < 0) {
+		info->gpmi_clk = devm_clk_get(dev, "gpmi_io");
+
+		if (IS_ERR(info->gpmi_clk)) {
+			ret = PTR_ERR(info->gpmi_clk);
 			debug("Can't get gpmi io clk: %d\n", ret);
 			return ret;
 		}
 
-		ret = clk_enable(&gpmi_clk);
+		ret = clk_enable(info->gpmi_clk);
 		if (ret < 0) {
 			debug("Can't enable gpmi io clk: %d\n", ret);
 			return ret;
 		}
 
-		ret = clk_get_by_name(dev, "gpmi_apb", &gpmi_clk);
-		if (ret < 0) {
-			debug("Can't get gpmi_apb clk: %d\n", ret);
-			return ret;
-		}
-
-		ret = clk_enable(&gpmi_clk);
-		if (ret < 0) {
-			debug("Can't enable gpmi_apb clk: %d\n", ret);
-			return ret;
-		}
-
-		ret = clk_get_by_name(dev, "gpmi_bch", &gpmi_clk);
-		if (ret < 0) {
-			debug("Can't get gpmi_bch clk: %d\n", ret);
-			return ret;
-		}
-
-		ret = clk_enable(&gpmi_clk);
-		if (ret < 0) {
-			debug("Can't enable gpmi_bch clk: %d\n", ret);
-			return ret;
+		if (IS_ENABLED(CONFIG_IMX8)) {
+			ret = clk_get_by_name(dev, "gpmi_apb", &gpmi_clk);
+			if (ret < 0) {
+				debug("Can't get gpmi_apb clk: %d\n", ret);
+				return ret;
+			}
+
+			ret = clk_enable(&gpmi_clk);
+			if (ret < 0) {
+				debug("Can't enable gpmi_apb clk: %d\n", ret);
+				return ret;
+			}
+
+			ret = clk_get_by_name(dev, "gpmi_bch", &gpmi_clk);
+			if (ret < 0) {
+				debug("Can't get gpmi_bch clk: %d\n", ret);
+				return ret;
+			}
+
+			ret = clk_enable(&gpmi_clk);
+			if (ret < 0) {
+				debug("Can't enable gpmi_bch clk: %d\n", ret);
+				return ret;
+			}
 		}
 
 		ret = clk_get_by_name(dev, "gpmi_bch_apb", &gpmi_clk);
diff --git a/include/mxs_nand.h b/include/mxs_nand.h
index 741dc8734eae..bb5b84b8c26e 100644
--- a/include/mxs_nand.h
+++ b/include/mxs_nand.h
@@ -12,6 +12,7 @@
 #include <asm/cache.h>
 #include <nand.h>
 #include <asm/mach-imx/dma.h>
+#include <clk.h>
 
 /**
  * @gf_len:                   The length of Galois Field. (e.g., 13 or 14)
@@ -43,6 +44,7 @@ struct mxs_nand_info {
 	struct nand_chip chip;
 	struct udevice *dev;
 	unsigned int	max_ecc_strength_supported;
+	int		max_chain_delay;
 	bool		use_minimum_ecc;
 	int		cur_chip;
 
@@ -59,6 +61,7 @@ struct mxs_nand_info {
 
 	struct mxs_gpmi_regs *gpmi_regs;
 	struct mxs_bch_regs *bch_regs;
+	struct clk *gpmi_clk;
 
 	/* Functions with altered behaviour */
 	int		(*hooked_read_oob)(struct mtd_info *mtd,
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/7] dm: clk: add missing stub when CONFIG_CLK is deactivated
  2022-09-28  8:45 ` [PATCH 1/7] dm: clk: add missing stub when CONFIG_CLK is deactivated Dario Binacchi
@ 2022-09-28 16:41   ` Sean Anderson
  0 siblings, 0 replies; 10+ messages in thread
From: Sean Anderson @ 2022-09-28 16:41 UTC (permalink / raw)
  To: Dario Binacchi, u-boot
  Cc: Amarula patchwork, michael, Giulio Benetti, Heinrich Schuchardt,
	Neil Armstrong, Simon Glass

On 9/28/22 04:45, Dario Binacchi wrote:
> Add missing stub for functions [devm_]clk_...() when CONFIG_CLK is
> deactivated.
> 
> Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
> ---
> 
>   include/clk.h | 32 +++++++++++++++++++++++++++++++-
>   1 file changed, 31 insertions(+), 1 deletion(-)
> 
> diff --git a/include/clk.h b/include/clk.h
> index 76bb64bb5ee0..407513e0fa29 100644
> --- a/include/clk.h
> +++ b/include/clk.h
> @@ -88,8 +88,9 @@ struct clk_bulk {
>   	unsigned int count;
>   };
>   
> -#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK)
>   struct phandle_1_arg;
> +
> +#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK)
>   /**
>    * clk_get_by_phandle() - Get a clock by its phandle information (of-platadata)
>    * @dev: Device containing the phandle
> @@ -258,12 +259,26 @@ int clk_release_all(struct clk *clk, int count);
>   void devm_clk_put(struct udevice *dev, struct clk *clk);
>   
>   #else
> +
> +static inline int clk_get_by_phandle(struct udevice *dev, const
> +				     struct phandle_1_arg *cells,
> +				     struct clk *clk)
> +{
> +	return -ENOSYS;
> +}
> +
>   static inline int clk_get_by_index(struct udevice *dev, int index,
>   				   struct clk *clk)
>   {
>   	return -ENOSYS;
>   }
>   
> +static inline int clk_get_by_index_nodev(ofnode node, int index,
> +					 struct clk *clk)
> +{
> +	return -ENOSYS;
> +}
> +
>   static inline int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk)
>   {
>   	return -ENOSYS;
> @@ -275,6 +290,17 @@ static inline int clk_get_by_name(struct udevice *dev, const char *name,
>   	return -ENOSYS;
>   }
>   
> +static inline struct clk *devm_clk_get(struct udevice *dev, const char *id)
> +{
> +	return ERR_PTR(-ENOSYS);
> +}
> +
> +static inline struct clk *devm_clk_get_optional(struct udevice *dev,
> +						const char *id)
> +{
> +	return ERR_PTR(-ENOSYS);
> +}
> +
>   static inline int
>   clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk)
>   {
> @@ -285,6 +311,10 @@ static inline int clk_release_all(struct clk *clk, int count)
>   {
>   	return -ENOSYS;
>   }
> +
> +static inline void devm_clk_put(struct udevice *dev, struct clk *clk)
> +{
> +}
>   #endif
>   
>   /**

Reviewed-by: Sean Anderson <seanga2@gmail.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 7/7] mtd: mxs_nand: Support EDO mode for imx8mn architecture
  2022-09-28  8:45 ` [PATCH 7/7] mtd: mxs_nand: Support EDO mode for imx8mn architecture Dario Binacchi
@ 2022-10-09  8:40   ` Dario Binacchi
  0 siblings, 0 replies; 10+ messages in thread
From: Dario Binacchi @ 2022-10-09  8:40 UTC (permalink / raw)
  To: u-boot; +Cc: Amarula patchwork, michael, Han Xu, Miquel Raynal

Hi Michael,

On Wed, Sep 28, 2022 at 10:45 AM Dario Binacchi <
dario.binacchi@amarulasolutions.com> wrote:

> From: Michael Trimarchi <michael@amarulasolutions.com>
>
> Add support for imx8mn architecture in order to run the NAND
> in fast edo mode.
>
> Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
>
> ---
>
>  drivers/mtd/nand/raw/mxs_nand.c    | 200 +++++++++++++++++++++++++++++
>  drivers/mtd/nand/raw/mxs_nand_dt.c |  66 ++++++----
>  include/mxs_nand.h                 |   3 +
>  3 files changed, 242 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/mxs_nand.c
> b/drivers/mtd/nand/raw/mxs_nand.c
> index 7893e9d7e343..65eab4c8088a 100644
> --- a/drivers/mtd/nand/raw/mxs_nand.c
> +++ b/drivers/mtd/nand/raw/mxs_nand.c
> @@ -14,6 +14,7 @@
>   */
>
>  #include <common.h>
> +#include <clk.h>
>  #include <cpu_func.h>
>  #include <dm.h>
>  #include <dm/device_compat.h>
> @@ -26,10 +27,12 @@
>  #include <asm/io.h>
>  #include <asm/mach-imx/regs-bch.h>
>  #include <asm/mach-imx/regs-gpmi.h>
> +#include <linux/delay.h>
>  #include <linux/errno.h>
>  #include <linux/mtd/rawnand.h>
>  #include <linux/sizes.h>
>  #include <linux/types.h>
> +#include <linux/math64.h>
>
>  #define        MXS_NAND_DMA_DESCRIPTOR_COUNT           4
>
> @@ -49,6 +52,10 @@
>  #endif
>
>  #define        MXS_NAND_BCH_TIMEOUT                    10000
> +#define        USEC_PER_SEC                            1000000
> +#define        NSEC_PER_SEC                            1000000000L
> +
> +#define TO_CYCLES(duration, period) DIV_ROUND_UP_ULL(duration, period)
>
>  struct nand_ecclayout fake_ecc_layout;
>
> @@ -1344,6 +1351,196 @@ err1:
>         return ret;
>  }
>
> +/*
> + * <1> Firstly, we should know what's the GPMI-clock means.
> + *     The GPMI-clock is the internal clock in the gpmi nand controller.
> + *     If you set 100MHz to gpmi nand controller, the GPMI-clock's period
> + *     is 10ns. Mark the GPMI-clock's period as GPMI-clock-period.
> + *
> + * <2> Secondly, we should know what's the frequency on the nand chip
> pins.
> + *     The frequency on the nand chip pins is derived from the GPMI-clock.
> + *     We can get it from the following equation:
> + *
> + *         F = G / (DS + DH)
> + *
> + *         F  : the frequency on the nand chip pins.
> + *         G  : the GPMI clock, such as 100MHz.
> + *         DS : GPMI_HW_GPMI_TIMING0:DATA_SETUP
> + *         DH : GPMI_HW_GPMI_TIMING0:DATA_HOLD
> + *
> + * <3> Thirdly, when the frequency on the nand chip pins is above 33MHz,
> + *     the nand EDO(extended Data Out) timing could be applied.
> + *     The GPMI implements a feedback read strobe to sample the read data.
> + *     The feedback read strobe can be delayed to support the nand EDO
> timing
> + *     where the read strobe may deasserts before the read data is valid,
> and
> + *     read data is valid for some time after read strobe.
> + *
> + *     The following figure illustrates some aspects of a NAND Flash read:
> + *
> + *                   |<---tREA---->|
> + *                   |             |
> + *                   |         |   |
> + *                   |<--tRP-->|   |
> + *                   |         |   |
> + *                  __          ___|__________________________________
> + *     RDN            \________/   |
> + *                                 |
> + *                                 /---------\
> + *     Read Data    --------------<           >---------
> + *                                 \---------/
> + *                                |     |
> + *                                |<-D->|
> + *     FeedbackRDN  ________             ____________
> + *                          \___________/
> + *
> + *          D stands for delay, set in the HW_GPMI_CTRL1:RDN_DELAY.
> + *
> + *
> + * <4> Now, we begin to describe how to compute the right RDN_DELAY.
> + *
> + *  4.1) From the aspect of the nand chip pins:
> + *        Delay = (tREA + C - tRP)               {1}
> + *
> + *        tREA : the maximum read access time.
> + *        C    : a constant to adjust the delay. default is 4000ps.
> + *        tRP  : the read pulse width, which is exactly:
> + *                   tRP = (GPMI-clock-period) * DATA_SETUP
> + *
> + *  4.2) From the aspect of the GPMI nand controller:
> + *         Delay = RDN_DELAY * 0.125 * RP        {2}
> + *
> + *         RP   : the DLL reference period.
> + *            if (GPMI-clock-period > DLL_THRETHOLD)
> + *                   RP = GPMI-clock-period / 2;
> + *            else
> + *                   RP = GPMI-clock-period;
> + *
> + *            Set the HW_GPMI_CTRL1:HALF_PERIOD if GPMI-clock-period
> + *            is greater DLL_THRETHOLD. In other SOCs, the DLL_THRETHOLD
> + *            is 16000ps, but in mx6q, we use 12000ps.
> + *
> + *  4.3) since {1} equals {2}, we get:
> + *
> + *                     (tREA + 4000 - tRP) * 8
> + *         RDN_DELAY = -----------------------     {3}
> + *                           RP
> + */
> +static void mxs_compute_timings(struct nand_chip *chip,
> +                               const struct nand_sdr_timings *sdr)
> +{
> +       struct mxs_nand_info *nand_info = nand_get_controller_data(chip);
> +       unsigned long clk_rate;
> +       unsigned int dll_wait_time_us;
> +       unsigned int dll_threshold_ps = nand_info->max_chain_delay;
> +       unsigned int period_ps, reference_period_ps;
> +       unsigned int data_setup_cycles, data_hold_cycles,
> addr_setup_cycles;
> +       unsigned int tRP_ps;
> +       bool use_half_period;
> +       int sample_delay_ps, sample_delay_factor;
> +       u16 busy_timeout_cycles;
> +       u8 wrn_dly_sel;
> +       u32 timing0;
> +       u32 timing1;
> +       u32 ctrl1n;
> +
> +       if (sdr->tRC_min >= 30000) {
> +               /* ONFI non-EDO modes [0-3] */
> +               clk_rate = 22000000;
> +               wrn_dly_sel = GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS;
> +       } else if (sdr->tRC_min >= 25000) {
> +               /* ONFI EDO mode 4 */
> +               clk_rate = 80000000;
> +               wrn_dly_sel = GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
> +               debug("%s, setting ONFI onfi edo 4\n", __func__);
> +       } else {
> +               /* ONFI EDO mode 5 */
> +               clk_rate = 100000000;
> +               wrn_dly_sel = GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY;
> +               debug("%s, setting ONFI onfi edo 5\n", __func__);
> +       }
> +
> +       /* SDR core timings are given in picoseconds */
> +       period_ps = div_u64((u64)NSEC_PER_SEC * 1000, clk_rate);
> +
> +       addr_setup_cycles = TO_CYCLES(sdr->tALS_min, period_ps);
> +       data_setup_cycles = TO_CYCLES(sdr->tDS_min, period_ps);
> +       data_hold_cycles = TO_CYCLES(sdr->tDH_min, period_ps);
> +       busy_timeout_cycles = TO_CYCLES(sdr->tWB_max + sdr->tR_max,
> period_ps);
> +
> +       timing0 = (addr_setup_cycles << GPMI_TIMING0_ADDRESS_SETUP_OFFSET)
> |
> +                     (data_hold_cycles << GPMI_TIMING0_DATA_HOLD_OFFSET) |
> +                     (data_setup_cycles <<
> GPMI_TIMING0_DATA_SETUP_OFFSET);
> +       timing1 = (busy_timeout_cycles * 4096) <<
> GPMI_TIMING1_DEVICE_BUSY_TIMEOUT_OFFSET;
> +
> +       /*
> +        * Derive NFC ideal delay from {3}:
> +        *
> +        *                     (tREA + 4000 - tRP) * 8
> +        *         RDN_DELAY = -----------------------
> +        *                                RP
> +        */
> +       if (period_ps > dll_threshold_ps) {
> +               use_half_period = true;
> +               reference_period_ps = period_ps / 2;
> +       } else {
> +               use_half_period = false;
> +               reference_period_ps = period_ps;
> +       }
> +
> +       tRP_ps = data_setup_cycles * period_ps;
> +       sample_delay_ps = (sdr->tREA_max + 4000 - tRP_ps) * 8;
> +       if (sample_delay_ps > 0)
> +               sample_delay_factor = sample_delay_ps /
> reference_period_ps;
> +       else
> +               sample_delay_factor = 0;
> +
> +       ctrl1n = (wrn_dly_sel << GPMI_CTRL1_WRN_DLY_SEL_OFFSET);
> +       if (sample_delay_factor)
> +               ctrl1n |= (sample_delay_factor <<
> GPMI_CTRL1_RDN_DELAY_OFFSET) |
> +                       GPMI_CTRL1_DLL_ENABLE |
> +                       (use_half_period ? GPMI_CTRL1_HALF_PERIOD : 0);
> +
> +       writel(timing0, &nand_info->gpmi_regs->hw_gpmi_timing0);
> +       writel(timing1, &nand_info->gpmi_regs->hw_gpmi_timing1);
> +
> +       /*
> +        * Clear several CTRL1 fields, DLL must be disabled when setting
> +        * RDN_DELAY or HALF_PERIOD.
> +        */
> +       writel(GPMI_CTRL1_CLEAR_MASK,
> &nand_info->gpmi_regs->hw_gpmi_ctrl1_clr);
> +       writel(ctrl1n, &nand_info->gpmi_regs->hw_gpmi_ctrl1_set);
> +
> +       clk_set_rate(nand_info->gpmi_clk, clk_rate);
> +
> +       /* Wait 64 clock cycles before using the GPMI after enabling the
> DLL */
> +       dll_wait_time_us = USEC_PER_SEC / clk_rate * 64;
> +       if (!dll_wait_time_us)
> +               dll_wait_time_us = 1;
> +
> +       /* Wait for the DLL to settle. */
> +       udelay(dll_wait_time_us);
> +}
> +
> +static int mxs_nand_setup_interface(struct mtd_info *mtd, int chipnr,
> +                                   const struct nand_data_interface *conf)
> +{
> +       struct nand_chip *chip = mtd_to_nand(mtd);
> +       const struct nand_sdr_timings *sdr;
> +
> +       sdr = nand_get_sdr_timings(conf);
> +       if (IS_ERR(sdr))
> +               return PTR_ERR(sdr);
> +
> +       /* Stop here if this call was just a check */
> +       if (chipnr < 0)
> +               return 0;
> +
> +       /* Do the actual derivation of the controller timings */
> +       mxs_compute_timings(chip, sdr);
> +
> +       return 0;
> +}
> +
>  int mxs_nand_init_spl(struct nand_chip *nand)
>  {
>         struct mxs_nand_info *nand_info;
> @@ -1432,6 +1629,9 @@ int mxs_nand_init_ctrl(struct mxs_nand_info
> *nand_info)
>         nand->read_buf          = mxs_nand_read_buf;
>         nand->write_buf         = mxs_nand_write_buf;
>
> +       if (nand_info->gpmi_clk)
> +               nand->setup_data_interface = mxs_nand_setup_interface;
> +
>         /* first scan to find the device and get the page size */
>         if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL))
>                 goto err_free_buffers;
> diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c
> b/drivers/mtd/nand/raw/mxs_nand_dt.c
> index 94ee7ed9ec83..a922a22b2730 100644
> --- a/drivers/mtd/nand/raw/mxs_nand_dt.c
> +++ b/drivers/mtd/nand/raw/mxs_nand_dt.c
> @@ -22,22 +22,27 @@
>
>  struct mxs_nand_dt_data {
>         unsigned int max_ecc_strength_supported;
> +       int max_chain_delay; /* See the async EDO mode */
>  };
>
>  static const struct mxs_nand_dt_data mxs_nand_imx6q_data = {
>         .max_ecc_strength_supported = 40,
> +       .max_chain_delay = 12000,
>  };
>
>  static const struct mxs_nand_dt_data mxs_nand_imx6sx_data = {
>         .max_ecc_strength_supported = 62,
> +       .max_chain_delay = 12000,
>  };
>
>  static const struct mxs_nand_dt_data mxs_nand_imx7d_data = {
>         .max_ecc_strength_supported = 62,
> +       .max_chain_delay = 12000,
>  };
>
>  static const struct mxs_nand_dt_data mxs_nand_imx8qxp_data = {
>         .max_ecc_strength_supported = 62,
> +       .max_chain_delay = 12000,
>  };
>
>  static const struct udevice_id mxs_nand_dt_ids[] = {
> @@ -72,8 +77,10 @@ static int mxs_nand_dt_probe(struct udevice *dev)
>         int ret;
>
>         data = (void *)dev_get_driver_data(dev);
> -       if (data)
> +       if (data) {
>                 info->max_ecc_strength_supported =
> data->max_ecc_strength_supported;
> +               info->max_chain_delay = data->max_chain_delay;
> +       }
>
>         info->dev = dev;
>
> @@ -92,44 +99,49 @@ static int mxs_nand_dt_probe(struct udevice *dev)
>
>         info->use_minimum_ecc = dev_read_bool(dev, "fsl,use-minimum-ecc");
>
> -       if (IS_ENABLED(CONFIG_CLK) && IS_ENABLED(CONFIG_IMX8)) {
> +       if (IS_ENABLED(CONFIG_CLK) &&
> +           (IS_ENABLED(CONFIG_IMX8) || IS_ENABLED(CONFIG_IMX8M))) {
>                 /* Assigned clock already set clock */
>                 struct clk gpmi_clk;
>
> -               ret = clk_get_by_name(dev, "gpmi_io", &gpmi_clk);
> -               if (ret < 0) {
> +               info->gpmi_clk = devm_clk_get(dev, "gpmi_io");
> +
> +               if (IS_ERR(info->gpmi_clk)) {
> +                       ret = PTR_ERR(info->gpmi_clk);
>                         debug("Can't get gpmi io clk: %d\n", ret);
>                         return ret;
>                 }
>
> -               ret = clk_enable(&gpmi_clk);
> +               ret = clk_enable(info->gpmi_clk);
>                 if (ret < 0) {
>                         debug("Can't enable gpmi io clk: %d\n", ret);
>                         return ret;
>                 }
>
> -               ret = clk_get_by_name(dev, "gpmi_apb", &gpmi_clk);
> -               if (ret < 0) {
> -                       debug("Can't get gpmi_apb clk: %d\n", ret);
> -                       return ret;
> -               }
> -
> -               ret = clk_enable(&gpmi_clk);
> -               if (ret < 0) {
> -                       debug("Can't enable gpmi_apb clk: %d\n", ret);
> -                       return ret;
> -               }
> -
> -               ret = clk_get_by_name(dev, "gpmi_bch", &gpmi_clk);
> -               if (ret < 0) {
> -                       debug("Can't get gpmi_bch clk: %d\n", ret);
> -                       return ret;
> -               }
> -
> -               ret = clk_enable(&gpmi_clk);
> -               if (ret < 0) {
> -                       debug("Can't enable gpmi_bch clk: %d\n", ret);
> -                       return ret;
> +               if (IS_ENABLED(CONFIG_IMX8)) {
> +                       ret = clk_get_by_name(dev, "gpmi_apb", &gpmi_clk);
> +                       if (ret < 0) {
> +                               debug("Can't get gpmi_apb clk: %d\n", ret);
> +                               return ret;
> +                       }
> +
> +                       ret = clk_enable(&gpmi_clk);
> +                       if (ret < 0) {
> +                               debug("Can't enable gpmi_apb clk: %d\n",
> ret);
> +                               return ret;
> +                       }
> +
> +                       ret = clk_get_by_name(dev, "gpmi_bch", &gpmi_clk);
> +                       if (ret < 0) {
> +                               debug("Can't get gpmi_bch clk: %d\n", ret);
> +                               return ret;
> +                       }
> +
> +                       ret = clk_enable(&gpmi_clk);
> +                       if (ret < 0) {
> +                               debug("Can't enable gpmi_bch clk: %d\n",
> ret);
> +                               return ret;
> +                       }
>                 }
>
>                 ret = clk_get_by_name(dev, "gpmi_bch_apb", &gpmi_clk);
> diff --git a/include/mxs_nand.h b/include/mxs_nand.h
> index 741dc8734eae..bb5b84b8c26e 100644
> --- a/include/mxs_nand.h
> +++ b/include/mxs_nand.h
> @@ -12,6 +12,7 @@
>  #include <asm/cache.h>
>  #include <nand.h>
>  #include <asm/mach-imx/dma.h>
> +#include <clk.h>
>
>  /**
>   * @gf_len:                   The length of Galois Field. (e.g., 13 or 14)
> @@ -43,6 +44,7 @@ struct mxs_nand_info {
>         struct nand_chip chip;
>         struct udevice *dev;
>         unsigned int    max_ecc_strength_supported;
> +       int             max_chain_delay;
>         bool            use_minimum_ecc;
>         int             cur_chip;
>
> @@ -59,6 +61,7 @@ struct mxs_nand_info {
>
>         struct mxs_gpmi_regs *gpmi_regs;
>         struct mxs_bch_regs *bch_regs;
> +       struct clk *gpmi_clk;
>
>         /* Functions with altered behaviour */
>         int             (*hooked_read_oob)(struct mtd_info *mtd,
> --
> 2.32.0
>
>
All the series applied to nand-next, thanks!

Dario


-- 

*Dario Binacchi*

Embedded Linux Developer

dario.binacchi@amarulasolutions.com

__________________________________


*Amarula Solutions SRL*

Via Le Canevare 30, 31100 Treviso, Veneto, IT

T. +39 042 243 5310
info@amarulasolutions.com

www.amarulasolutions.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2022-10-09  8:40 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-09-28  8:45 [PATCH 0/7] Support NAND ONFI EDO mode for imx8mn architecture Dario Binacchi
2022-09-28  8:45 ` [PATCH 1/7] dm: clk: add missing stub when CONFIG_CLK is deactivated Dario Binacchi
2022-09-28 16:41   ` Sean Anderson
2022-09-28  8:45 ` [PATCH 2/7] clk: imx: gate2 support shared counter and relative clock functions Dario Binacchi
2022-09-28  8:45 ` [PATCH 3/7] clk: imx: clk-imx8mn add gpmi nand clocks Dario Binacchi
2022-09-28  8:45 ` [PATCH 4/7] imx: gpmi: Add register needed to control nand bus timing Dario Binacchi
2022-09-28  8:45 ` [PATCH 5/7] mtd: mxs_nand: don't get the gpmi_apbh_dma clock Dario Binacchi
2022-09-28  8:45 ` [PATCH 6/7] mtd: mxs_nand: get the clock with the right name Dario Binacchi
2022-09-28  8:45 ` [PATCH 7/7] mtd: mxs_nand: Support EDO mode for imx8mn architecture Dario Binacchi
2022-10-09  8:40   ` Dario Binacchi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox