[PATCH 0/6] memory: ti-aemif: Add DM support

Hi all,
This patch series aims to add DM support for the AEMIF controller that can be found in the DaVinci SoCs.
This controller has already a driver used by the Keystone SoCs so I add my work to it.
As we can now easily import Linux device-trees, I try to stick the most I can to the Linux bindings of the AEMIF controller. To do so I add an 'intermediate' driver called 'ti-aemif-cs'. It's in charge of configuring timings for a given chip select of the AEMIF controller.
Bastien Curutchet (6): memory: ti-aemif: Correct macro to ensure avoiding precedence issues memory: ti-aemif: Make AEMIF driver architecture agnostic memory: ti-aemif: Add ARCH_DAVINCI to architectures that uses TI_AEMIF memory: ti-aemif: Wrap the CS configuration into a function memory: ti-aemif: Add DM support memory: ti-aemif-cs: Compute timing configuration from DT parsing
arch/arm/include/asm/ti-common/ti-aemif.h | 1 + board/ti/ks2_evm/board.c | 4 +- drivers/memory/Kconfig | 2 +- drivers/memory/Makefile | 2 +- drivers/memory/ti-aemif-cs.c | 183 ++++++++++++++++++++++ drivers/memory/ti-aemif-cs.h | 4 + drivers/memory/ti-aemif.c | 63 +++----- 7 files changed, 215 insertions(+), 44 deletions(-) create mode 100644 drivers/memory/ti-aemif-cs.c create mode 100644 drivers/memory/ti-aemif-cs.h

Fix following CHECK pointed out by checkpatch:
CHECK: Macro argument 'cs' may be better as '(cs)' to avoid precedence issues #62: FILE: drivers/memory/ti-aemif.c:15: +#define AEMIF_CONFIG(cs) (0x10 + (cs * 4))
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com --- drivers/memory/ti-aemif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 29131f536a..127a262894 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -12,7 +12,7 @@ #define AEMIF_WAITCYCLE_CONFIG (KS2_AEMIF_CNTRL_BASE + 0x4) #define AEMIF_NAND_CONTROL (KS2_AEMIF_CNTRL_BASE + 0x60) #define AEMIF_ONENAND_CONTROL (KS2_AEMIF_CNTRL_BASE + 0x5c) -#define AEMIF_CONFIG(cs) (KS2_AEMIF_CNTRL_BASE + 0x10 + (cs * 4)) +#define AEMIF_CONFIG(cs) (KS2_AEMIF_CNTRL_BASE + 0x10 + ((cs) * 4))
#define AEMIF_CFG_SELECT_STROBE(v) ((v) ? 1 << 31 : 0) #define AEMIF_CFG_EXTEND_WAIT(v) ((v) ? 1 << 30 : 0)

On Mon, Oct 21, 2024 at 05:13:25PM +0200, Bastien Curutchet wrote:
Fix following CHECK pointed out by checkpatch:
CHECK: Macro argument 'cs' may be better as '(cs)' to avoid precedence issues #62: FILE: drivers/memory/ti-aemif.c:15: +#define AEMIF_CONFIG(cs) (0x10 + (cs * 4))
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com
Reviewed-by: Tom Rini trini@konsulko.com

AEMIF controller is present on other SoCs than the Keystone ones.
Remove Keystone specificities from the driver to be able to use it from other architectures. Adapt the ks2_evm/board.c to fit the new driver.
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com --- arch/arm/include/asm/ti-common/ti-aemif.h | 1 + board/ti/ks2_evm/board.c | 4 +++- drivers/memory/ti-aemif.c | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/arch/arm/include/asm/ti-common/ti-aemif.h b/arch/arm/include/asm/ti-common/ti-aemif.h index a77538673f..11a7384cec 100644 --- a/arch/arm/include/asm/ti-common/ti-aemif.h +++ b/arch/arm/include/asm/ti-common/ti-aemif.h @@ -16,6 +16,7 @@ #define AEMIF_PRESERVE -1
struct aemif_config { + void *base; unsigned mode; unsigned select_strobe; unsigned extend_wait; diff --git a/board/ti/ks2_evm/board.c b/board/ti/ks2_evm/board.c index c6735d37dd..b2f0dced67 100644 --- a/board/ti/ks2_evm/board.c +++ b/board/ti/ks2_evm/board.c @@ -49,8 +49,10 @@ int dram_init(void) gd->ram_size = get_ram_size((long *)CFG_SYS_SDRAM_BASE, CFG_MAX_RAM_BANK_SIZE); #if defined(CONFIG_TI_AEMIF) - if (!(board_is_k2g_ice() || board_is_k2g_i1())) + if (!(board_is_k2g_ice() || board_is_k2g_i1())) { + aemif_configs->base = (void *)KS2_AEMIF_CNTRL_BASE; aemif_init(ARRAY_SIZE(aemif_configs), aemif_configs); + } #endif
if (!(board_is_k2g_ice() || board_is_k2g_i1())) { diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 127a262894..8e7ddde970 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -9,10 +9,10 @@ #include <asm/arch/hardware.h> #include <asm/ti-common/ti-aemif.h>
-#define AEMIF_WAITCYCLE_CONFIG (KS2_AEMIF_CNTRL_BASE + 0x4) -#define AEMIF_NAND_CONTROL (KS2_AEMIF_CNTRL_BASE + 0x60) -#define AEMIF_ONENAND_CONTROL (KS2_AEMIF_CNTRL_BASE + 0x5c) -#define AEMIF_CONFIG(cs) (KS2_AEMIF_CNTRL_BASE + 0x10 + ((cs) * 4)) +#define AEMIF_WAITCYCLE_CONFIG (0x4) +#define AEMIF_NAND_CONTROL (0x60) +#define AEMIF_ONENAND_CONTROL (0x5c) +#define AEMIF_CONFIG(cs) (0x10 + ((cs) * 4))
#define AEMIF_CFG_SELECT_STROBE(v) ((v) ? 1 << 31 : 0) #define AEMIF_CFG_EXTEND_WAIT(v) ((v) ? 1 << 30 : 0) @@ -38,17 +38,17 @@ static void aemif_configure(int cs, struct aemif_config *cfg) unsigned long tmp;
if (cfg->mode == AEMIF_MODE_NAND) { - tmp = __raw_readl(AEMIF_NAND_CONTROL); + tmp = __raw_readl(cfg->base + AEMIF_NAND_CONTROL); tmp |= (1 << cs); - __raw_writel(tmp, AEMIF_NAND_CONTROL); + __raw_writel(tmp, cfg->base + AEMIF_NAND_CONTROL);
} else if (cfg->mode == AEMIF_MODE_ONENAND) { - tmp = __raw_readl(AEMIF_ONENAND_CONTROL); + tmp = __raw_readl(cfg->base + AEMIF_ONENAND_CONTROL); tmp |= (1 << cs); - __raw_writel(tmp, AEMIF_ONENAND_CONTROL); + __raw_writel(tmp, cfg->base + AEMIF_ONENAND_CONTROL); }
- tmp = __raw_readl(AEMIF_CONFIG(cs)); + tmp = __raw_readl(cfg->base + AEMIF_CONFIG(cs));
set_config_field(tmp, SELECT_STROBE, cfg->select_strobe); set_config_field(tmp, EXTEND_WAIT, cfg->extend_wait); @@ -61,7 +61,7 @@ static void aemif_configure(int cs, struct aemif_config *cfg) set_config_field(tmp, TURN_AROUND, cfg->turn_around); set_config_field(tmp, WIDTH, cfg->width);
- __raw_writel(tmp, AEMIF_CONFIG(cs)); + __raw_writel(tmp, cfg->base + AEMIF_CONFIG(cs)); }
void aemif_init(int num_cs, struct aemif_config *config)

On Mon, Oct 21, 2024 at 05:13:26PM +0200, Bastien Curutchet wrote:
AEMIF controller is present on other SoCs than the Keystone ones.
Remove Keystone specificities from the driver to be able to use it from other architectures. Adapt the ks2_evm/board.c to fit the new driver.
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com
Reviewed-by: Tom Rini trini@konsulko.com

TI_AEMIF configuration doesn't depend on ARCH_DAVINCI while the AEMIF controller is present in the DaVinci SoCs.
Add ARCH_DAVINCI to the potential users of the TI_AEMIF driver Add <asm/io.h> to driver's includes to fix build issue on ARCH_DAVINCI
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com --- drivers/memory/Kconfig | 2 +- drivers/memory/ti-aemif.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index d10edd2774..7c40f17698 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -39,7 +39,7 @@ config STM32_FMC2_EBI
config TI_AEMIF tristate "Texas Instruments AEMIF driver" - depends on ARCH_KEYSTONE + depends on ARCH_KEYSTONE || ARCH_DAVINCI help This driver is for the AEMIF module available in Texas Instruments SoCs. AEMIF stands for Asynchronous External Memory Interface and diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 8e7ddde970..82a9c8cf7b 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -7,6 +7,7 @@ */
#include <asm/arch/hardware.h> +#include <asm/io.h> #include <asm/ti-common/ti-aemif.h>
#define AEMIF_WAITCYCLE_CONFIG (0x4)

On Mon, Oct 21, 2024 at 05:13:27PM +0200, Bastien Curutchet wrote:
TI_AEMIF configuration doesn't depend on ARCH_DAVINCI while the AEMIF controller is present in the DaVinci SoCs.
Add ARCH_DAVINCI to the potential users of the TI_AEMIF driver Add <asm/io.h> to driver's includes to fix build issue on ARCH_DAVINCI
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com
Reviewed-by: Tom Rini trini@konsulko.com

Wrap the CS configuration into a aemif_configure_cs() to ease its migration to another driver when adding DM support.
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com --- drivers/memory/ti-aemif.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 82a9c8cf7b..5e9514713f 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -34,21 +34,10 @@ } \ } while (0)
-static void aemif_configure(int cs, struct aemif_config *cfg) +static void aemif_cs_configure(int cs, struct aemif_config *cfg) { unsigned long tmp;
- if (cfg->mode == AEMIF_MODE_NAND) { - tmp = __raw_readl(cfg->base + AEMIF_NAND_CONTROL); - tmp |= (1 << cs); - __raw_writel(tmp, cfg->base + AEMIF_NAND_CONTROL); - - } else if (cfg->mode == AEMIF_MODE_ONENAND) { - tmp = __raw_readl(cfg->base + AEMIF_ONENAND_CONTROL); - tmp |= (1 << cs); - __raw_writel(tmp, cfg->base + AEMIF_ONENAND_CONTROL); - } - tmp = __raw_readl(cfg->base + AEMIF_CONFIG(cs));
set_config_field(tmp, SELECT_STROBE, cfg->select_strobe); @@ -65,6 +54,24 @@ static void aemif_configure(int cs, struct aemif_config *cfg) __raw_writel(tmp, cfg->base + AEMIF_CONFIG(cs)); }
+static void aemif_configure(int cs, struct aemif_config *cfg) +{ + unsigned long tmp; + + if (cfg->mode == AEMIF_MODE_NAND) { + tmp = __raw_readl(cfg->base + AEMIF_NAND_CONTROL); + tmp |= (1 << cs); + __raw_writel(tmp, cfg->base + AEMIF_NAND_CONTROL); + + } else if (cfg->mode == AEMIF_MODE_ONENAND) { + tmp = __raw_readl(cfg->base + AEMIF_ONENAND_CONTROL); + tmp |= (1 << cs); + __raw_writel(tmp, cfg->base + AEMIF_ONENAND_CONTROL); + } + + aemif_cs_configure(cs, cfg); +} + void aemif_init(int num_cs, struct aemif_config *config) { int cs;

The AEMIF's bindings in the Linux tree have a node for the AEMIF controller and then a node for each AEMIF's chip select. This CS node doesn't have a compatible property but describes the timing parameters used by a given chip select. The U-Boot DM framework expects every node to have a 'compatible' property. If no 'compatible' is present in a node, its children won't be parsed by u-boot.
Add DM support to the ti-aemif driver. Add a new ti-aemif-cs driver to comply with the Linux bindings and the U-Boot's DM philosophy. This driver handles the timing parameters of an AEMIF's chip select so move aemif_cs_configure() from ti-aemif.c to ti-aemif-cs.c.
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com --- drivers/memory/Makefile | 2 +- drivers/memory/ti-aemif-cs.c | 61 ++++++++++++++++++++++++++++++++++++ drivers/memory/ti-aemif-cs.h | 4 +++ drivers/memory/ti-aemif.c | 53 ++++++++----------------------- 4 files changed, 79 insertions(+), 41 deletions(-) create mode 100644 drivers/memory/ti-aemif-cs.c create mode 100644 drivers/memory/ti-aemif-cs.h
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index 1cabf8ac9c..fdc83e4e1c 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -3,5 +3,5 @@ obj-$(CONFIG_MEMORY) += memory-uclass.o obj-$(CONFIG_SANDBOX_MEMORY) += memory-sandbox.o obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o obj-$(CONFIG_ATMEL_EBI) += atmel_ebi.o -obj-$(CONFIG_TI_AEMIF) += ti-aemif.o +obj-$(CONFIG_TI_AEMIF) += ti-aemif.o ti-aemif-cs.o obj-$(CONFIG_TI_GPMC) += ti-gpmc.o diff --git a/drivers/memory/ti-aemif-cs.c b/drivers/memory/ti-aemif-cs.c new file mode 100644 index 0000000000..80166e3e6a --- /dev/null +++ b/drivers/memory/ti-aemif-cs.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DaVinci / Keystone2 : AEMIF's chip select configuration + * + */ +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include "ti-aemif-cs.h" + +#define AEMIF_CONFIG(cs) (0x10 + ((cs) * 4)) + +#define AEMIF_CFG_SELECT_STROBE(v) ((v) ? 1 << 31 : 0) +#define AEMIF_CFG_EXTEND_WAIT(v) ((v) ? 1 << 30 : 0) +#define AEMIF_CFG_WR_SETUP(v) (((v) & 0x0f) << 26) +#define AEMIF_CFG_WR_STROBE(v) (((v) & 0x3f) << 20) +#define AEMIF_CFG_WR_HOLD(v) (((v) & 0x07) << 17) +#define AEMIF_CFG_RD_SETUP(v) (((v) & 0x0f) << 13) +#define AEMIF_CFG_RD_STROBE(v) (((v) & 0x3f) << 7) +#define AEMIF_CFG_RD_HOLD(v) (((v) & 0x07) << 4) +#define AEMIF_CFG_TURN_AROUND(v) (((v) & 0x03) << 2) +#define AEMIF_CFG_WIDTH(v) (((v) & 0x03) << 0) + +#define set_config_field(reg, field, val) \ + do { \ + if ((val) != -1) { \ + (reg) &= ~AEMIF_CFG_##field(0xffffffff); \ + (reg) |= AEMIF_CFG_##field((val)); \ + } \ + } while (0) + +void aemif_cs_configure(int cs, struct aemif_config *cfg) +{ + unsigned long tmp; + + tmp = __raw_readl(cfg->base + AEMIF_CONFIG(cs)); + + set_config_field(tmp, SELECT_STROBE, cfg->select_strobe); + set_config_field(tmp, EXTEND_WAIT, cfg->extend_wait); + set_config_field(tmp, WR_SETUP, cfg->wr_setup); + set_config_field(tmp, WR_STROBE, cfg->wr_strobe); + set_config_field(tmp, WR_HOLD, cfg->wr_hold); + set_config_field(tmp, RD_SETUP, cfg->rd_setup); + set_config_field(tmp, RD_STROBE, cfg->rd_strobe); + set_config_field(tmp, RD_HOLD, cfg->rd_hold); + set_config_field(tmp, TURN_AROUND, cfg->turn_around); + set_config_field(tmp, WIDTH, cfg->width); + + __raw_writel(tmp, cfg->base + AEMIF_CONFIG(cs)); +} + +static const struct udevice_id aemif_cs_ids[] = { + { .compatible = "ti,da850-aemif-cs", }, + {}, +}; + +U_BOOT_DRIVER(ti_aemif_cs) = { + .name = "ti_aemif_cs", + .id = UCLASS_MEMORY, + .of_match = aemif_cs_ids, +}; diff --git a/drivers/memory/ti-aemif-cs.h b/drivers/memory/ti-aemif-cs.h new file mode 100644 index 0000000000..62e6c6ed1a --- /dev/null +++ b/drivers/memory/ti-aemif-cs.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#include <asm/ti-common/ti-aemif.h> + +void aemif_cs_configure(int cs, struct aemif_config *cfg); diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index 5e9514713f..b26423c457 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -9,50 +9,12 @@ #include <asm/arch/hardware.h> #include <asm/io.h> #include <asm/ti-common/ti-aemif.h> +#include <dm.h> +#include "ti-aemif-cs.h"
#define AEMIF_WAITCYCLE_CONFIG (0x4) #define AEMIF_NAND_CONTROL (0x60) #define AEMIF_ONENAND_CONTROL (0x5c) -#define AEMIF_CONFIG(cs) (0x10 + ((cs) * 4)) - -#define AEMIF_CFG_SELECT_STROBE(v) ((v) ? 1 << 31 : 0) -#define AEMIF_CFG_EXTEND_WAIT(v) ((v) ? 1 << 30 : 0) -#define AEMIF_CFG_WR_SETUP(v) (((v) & 0x0f) << 26) -#define AEMIF_CFG_WR_STROBE(v) (((v) & 0x3f) << 20) -#define AEMIF_CFG_WR_HOLD(v) (((v) & 0x07) << 17) -#define AEMIF_CFG_RD_SETUP(v) (((v) & 0x0f) << 13) -#define AEMIF_CFG_RD_STROBE(v) (((v) & 0x3f) << 7) -#define AEMIF_CFG_RD_HOLD(v) (((v) & 0x07) << 4) -#define AEMIF_CFG_TURN_AROUND(v) (((v) & 0x03) << 2) -#define AEMIF_CFG_WIDTH(v) (((v) & 0x03) << 0) - -#define set_config_field(reg, field, val) \ - do { \ - if (val != -1) { \ - reg &= ~AEMIF_CFG_##field(0xffffffff); \ - reg |= AEMIF_CFG_##field(val); \ - } \ - } while (0) - -static void aemif_cs_configure(int cs, struct aemif_config *cfg) -{ - unsigned long tmp; - - tmp = __raw_readl(cfg->base + AEMIF_CONFIG(cs)); - - set_config_field(tmp, SELECT_STROBE, cfg->select_strobe); - set_config_field(tmp, EXTEND_WAIT, cfg->extend_wait); - set_config_field(tmp, WR_SETUP, cfg->wr_setup); - set_config_field(tmp, WR_STROBE, cfg->wr_strobe); - set_config_field(tmp, WR_HOLD, cfg->wr_hold); - set_config_field(tmp, RD_SETUP, cfg->rd_setup); - set_config_field(tmp, RD_STROBE, cfg->rd_strobe); - set_config_field(tmp, RD_HOLD, cfg->rd_hold); - set_config_field(tmp, TURN_AROUND, cfg->turn_around); - set_config_field(tmp, WIDTH, cfg->width); - - __raw_writel(tmp, cfg->base + AEMIF_CONFIG(cs)); -}
static void aemif_configure(int cs, struct aemif_config *cfg) { @@ -84,3 +46,14 @@ void aemif_init(int num_cs, struct aemif_config *config) for (cs = 0; cs < num_cs; cs++) aemif_configure(cs, config + cs); } + +static const struct udevice_id aemif_ids[] = { + { .compatible = "ti,da850-aemif", }, + {}, +}; + +U_BOOT_DRIVER(ti_aemif) = { + .name = "ti_aemif", + .id = UCLASS_MEMORY, + .of_match = aemif_ids, +};

The Linux bindings of the AEMIF offer properties that specify the transaction timings for each chips select.
Add parsing of these properties to calculate the chip select's configuration from them and the rate of the AEMIF's reference clock.
Signed-off-by: Bastien Curutchet bastien.curutchet@bootlin.com --- drivers/memory/ti-aemif-cs.c | 122 +++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+)
diff --git a/drivers/memory/ti-aemif-cs.c b/drivers/memory/ti-aemif-cs.c index 80166e3e6a..0fcfee6f0b 100644 --- a/drivers/memory/ti-aemif-cs.c +++ b/drivers/memory/ti-aemif-cs.c @@ -5,6 +5,7 @@ */ #include <asm/io.h> #include <clk.h> +#include <div64.h> #include <dm.h> #include "ti-aemif-cs.h"
@@ -21,6 +22,20 @@ #define AEMIF_CFG_TURN_AROUND(v) (((v) & 0x03) << 2) #define AEMIF_CFG_WIDTH(v) (((v) & 0x03) << 0)
+#define SSTROBE_EN 0x1 +#define EW_EN 0x1 + +#define WSETUP_MAX 0xf +#define WSTROBE_MAX 0x3f +#define WHOLD_MAX 0x7 +#define RSETUP_MAX 0xf +#define RSTROBE_MAX 0x3f +#define RHOLD_MAX 0x7 +#define TA_MAX 0x3 + +#define WIDTH_8BITS 0x0 +#define WIDTH_16BITS 0x1 + #define set_config_field(reg, field, val) \ do { \ if ((val) != -1) { \ @@ -49,6 +64,111 @@ void aemif_cs_configure(int cs, struct aemif_config *cfg) __raw_writel(tmp, cfg->base + AEMIF_CONFIG(cs)); }
+struct ti_aemif_cs { + void __iomem *base; + struct clk *clk; +}; + +static unsigned int aemif_calc_cfg(ulong rate, u64 timing_ns, u32 max_cfg) +{ + u64 result; + + if (!timing_ns) + return 0; + + result = DIV_ROUND_UP_ULL(timing_ns * rate, 1000000000ULL); + + if (result - 1 > max_cfg) + return max_cfg; + + return result - 1; +} + +static int aemif_cs_set_timings(struct udevice *dev) +{ + struct ti_aemif_cs *priv = dev_get_priv(dev); + ulong rate = clk_get_rate(priv->clk); + struct aemif_config cfg = {}; + u32 val; + u32 cs; + + if (dev_read_u32(dev, "ti,cs-chipselect", &cs)) + return -EINVAL; + +/* + * On DaVinci SoCs, chipselect is in range [2-5] + * On Keystone SoCs, chipselect is in range [0-3] + * The logic to access the configuration registers expects the CS to be in the + * Keystone range so a -2 offset is applied on DaVinci SoCs + */ + if (IS_ENABLED(CONFIG_ARCH_DAVINCI)) { + if (cs < 2 || cs > 5) + return -EINVAL; + cs -= 2; + } else if (IS_ENABLED(CONFIG_ARCH_KEYSTONE)) { + if (cs > 3) + return -EINVAL; + } + + if (dev_read_bool(dev, "ti,cs-select-strobe-mode")) + cfg.select_strobe = SSTROBE_EN; + + if (dev_read_bool(dev, "ti,cs-extended-wait-mode")) + cfg.extend_wait = EW_EN; + + val = dev_read_u32_default(dev, "ti,cs-write-setup-ns", U32_MAX); + cfg.wr_setup = aemif_calc_cfg(rate, val, WSETUP_MAX); + + val = dev_read_u32_default(dev, "ti,cs-write-strobe-ns", U32_MAX); + cfg.wr_strobe = aemif_calc_cfg(rate, val, WSTROBE_MAX); + + val = dev_read_u32_default(dev, "ti,cs-write-hold-ns", U32_MAX); + cfg.wr_hold = aemif_calc_cfg(rate, val, WHOLD_MAX); + + val = dev_read_u32_default(dev, "ti,cs-read-setup-ns", U32_MAX); + cfg.rd_setup = aemif_calc_cfg(rate, val, RSETUP_MAX); + + val = dev_read_u32_default(dev, "ti,cs-read-strobe-ns", U32_MAX); + cfg.rd_strobe = aemif_calc_cfg(rate, val, RSTROBE_MAX); + + val = dev_read_u32_default(dev, "ti,cs-read-hold-ns", U32_MAX); + cfg.rd_hold = aemif_calc_cfg(rate, val, RHOLD_MAX); + + val = dev_read_u32_default(dev, "ti,cs-min-turnaround-ns", U32_MAX); + cfg.turn_around = aemif_calc_cfg(rate, val, TA_MAX); + + val = dev_read_u32_default(dev, "ti,cs-bus-width", 8); + if (val == 16) + cfg.width = WIDTH_16BITS; + else + cfg.width = WIDTH_8BITS; + + cfg.base = priv->base; + aemif_cs_configure(cs, &cfg); + + return 0; +} + +static int aemif_cs_probe(struct udevice *dev) +{ + struct ti_aemif_cs *priv = dev_get_priv(dev); + struct udevice *aemif; + + aemif = dev_get_parent(dev); + if (!aemif) + return -ENODEV; + + priv->base = dev_read_addr_ptr(aemif); + if (!priv->base) + return -EINVAL; + + priv->clk = devm_clk_get(aemif, "aemif"); + if (IS_ERR(priv->clk)) + return -EINVAL; + + return aemif_cs_set_timings(dev); +} + static const struct udevice_id aemif_cs_ids[] = { { .compatible = "ti,da850-aemif-cs", }, {}, @@ -58,4 +178,6 @@ U_BOOT_DRIVER(ti_aemif_cs) = { .name = "ti_aemif_cs", .id = UCLASS_MEMORY, .of_match = aemif_cs_ids, + .probe = aemif_cs_probe, + .priv_auto = sizeof(struct ti_aemif_cs), };

On Mon, 21 Oct 2024 17:13:24 +0200, Bastien Curutchet wrote:
This patch series aims to add DM support for the AEMIF controller that can be found in the DaVinci SoCs.
This controller has already a driver used by the Keystone SoCs so I add my work to it.
As we can now easily import Linux device-trees, I try to stick the most I can to the Linux bindings of the AEMIF controller. To do so I add an 'intermediate' driver called 'ti-aemif-cs'. It's in charge of configuring timings for a given chip select of the AEMIF controller.
[...]
Applied to u-boot/master, thanks!
participants (2)
-
Bastien Curutchet
-
Tom Rini