From 7a7b13838f11f6dbb3049a44b8884e9139f39b5e Mon Sep 17 00:00:00 2001 From: Bastien Curutchet Date: Mon, 21 Oct 2024 17:13:25 +0200 Subject: [PATCH 1/6] memory: ti-aemif: Correct macro to ensure avoiding precedence issues 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 Reviewed-by: Tom Rini --- 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) From 1ba44c8eed7c1c623f7010401bb0b8d2e59a8d8a Mon Sep 17 00:00:00 2001 From: Bastien Curutchet Date: Mon, 21 Oct 2024 17:13:26 +0200 Subject: [PATCH 2/6] memory: ti-aemif: Make AEMIF driver architecture agnostic 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 Reviewed-by: Tom Rini --- 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 #include -#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) From f437f786cdba7bd909c480977cfc4de5ab004c3f Mon Sep 17 00:00:00 2001 From: Bastien Curutchet Date: Mon, 21 Oct 2024 17:13:27 +0200 Subject: [PATCH 3/6] memory: ti-aemif: Add ARCH_DAVINCI to architectures that uses TI_AEMIF 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 to driver's includes to fix build issue on ARCH_DAVINCI Signed-off-by: Bastien Curutchet Reviewed-by: Tom Rini --- 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 +#include #include #define AEMIF_WAITCYCLE_CONFIG (0x4) From 4b43602c8b05ad51ec430f81319c56c40dd00c77 Mon Sep 17 00:00:00 2001 From: Bastien Curutchet Date: Mon, 21 Oct 2024 17:13:28 +0200 Subject: [PATCH 4/6] memory: ti-aemif: Wrap the CS configuration into a function 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 --- 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; From 94e45f7b50ea20589d6a91e4d245e96a6c590252 Mon Sep 17 00:00:00 2001 From: Bastien Curutchet Date: Mon, 21 Oct 2024 17:13:29 +0200 Subject: [PATCH 5/6] memory: ti-aemif: Add DM support 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 --- 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 +#include +#include +#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 + +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 #include #include +#include +#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, +}; From ea21cde01de8f6e3ffed75a995123183f411773e Mon Sep 17 00:00:00 2001 From: Bastien Curutchet Date: Mon, 21 Oct 2024 17:13:30 +0200 Subject: [PATCH 6/6] memory: ti-aemif-cs: Compute timing configuration from DT parsing 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 --- 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 #include +#include #include #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), };