* [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