[PATCH v1 1/2] memory: stm32-fmc2-ebi: add MP25 support
Patrice CHOTARD
patrice.chotard at foss.st.com
Fri Mar 8 12:06:27 CET 2024
On 3/6/24 10:50, Christophe Kerello wrote:
> Add the support of the revision 2 of FMC2 IP.
> - PCSCNTR register has been removed,
> - CFGR register has been added,
> - the bit used to enable the IP has moved from BCR1 to CFGR,
> - the timeout for CEx deassertion has moved from PCSCNTR to BCRx,
> - the continuous clock enable has moved from BCR1 to CFGR,
> - the clk divide ratio has moved from BCR1 to CFGR.
>
> The MP1 SoCs have only one signal to manage all the controllers (NWAIT).
> The MP25 SOC has one RNB signal for the NAND controller and one NWAIT
> signal for the memory controller.
>
> Let's use a platform data structure for parameters that will differ
> between MP1 and MP25.
>
> Signed-off-by: Christophe Kerello <christophe.kerello at foss.st.com>
>
> ---
>
> drivers/memory/stm32-fmc2-ebi.c | 313 ++++++++++++++++++++++++++++++--
> 1 file changed, 301 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c
> index a722a3836f7..c7db16463e8 100644
> --- a/drivers/memory/stm32-fmc2-ebi.c
> +++ b/drivers/memory/stm32-fmc2-ebi.c
> @@ -22,6 +22,7 @@
> #define FMC2_BCR(x) ((x) * 0x8 + FMC2_BCR1)
> #define FMC2_BTR(x) ((x) * 0x8 + FMC2_BTR1)
> #define FMC2_PCSCNTR 0x20
> +#define FMC2_CFGR 0x20
> #define FMC2_BWTR1 0x104
> #define FMC2_BWTR(x) ((x) * 0x8 + FMC2_BWTR1)
>
> @@ -44,6 +45,7 @@
> #define FMC2_BCR_ASYNCWAIT BIT(15)
> #define FMC2_BCR_CPSIZE GENMASK(18, 16)
> #define FMC2_BCR_CBURSTRW BIT(19)
> +#define FMC2_BCR_CSCOUNT GENMASK(21, 20)
> #define FMC2_BCR_NBLSET GENMASK(23, 22)
>
> /* Register: FMC2_BTRx/FMC2_BWTRx */
> @@ -60,6 +62,11 @@
> #define FMC2_PCSCNTR_CSCOUNT GENMASK(15, 0)
> #define FMC2_PCSCNTR_CNTBEN(x) BIT((x) + 16)
>
> +/* Register: FMC2_CFGR */
> +#define FMC2_CFGR_CLKDIV GENMASK(19, 16)
> +#define FMC2_CFGR_CCLKEN BIT(20)
> +#define FMC2_CFGR_FMC2EN BIT(31)
> +
> #define FMC2_MAX_EBI_CE 4
> #define FMC2_MAX_BANKS 5
>
> @@ -76,6 +83,11 @@
> #define FMC2_BCR_MTYP_PSRAM 0x1
> #define FMC2_BCR_MTYP_NOR 0x2
>
> +#define FMC2_BCR_CSCOUNT_0 0x0
> +#define FMC2_BCR_CSCOUNT_1 0x1
> +#define FMC2_BCR_CSCOUNT_64 0x2
> +#define FMC2_BCR_CSCOUNT_256 0x3
> +
> #define FMC2_BXTR_EXTMOD_A 0x0
> #define FMC2_BXTR_EXTMOD_B 0x1
> #define FMC2_BXTR_EXTMOD_C 0x2
> @@ -90,6 +102,7 @@
> #define FMC2_BTR_CLKDIV_MAX 0xf
> #define FMC2_BTR_DATLAT_MAX 0xf
> #define FMC2_PCSCNTR_CSCOUNT_MAX 0xff
> +#define FMC2_CFGR_CLKDIV_MAX 0xf
>
> enum stm32_fmc2_ebi_bank {
> FMC2_EBI1 = 0,
> @@ -103,7 +116,8 @@ enum stm32_fmc2_ebi_register_type {
> FMC2_REG_BCR = 1,
> FMC2_REG_BTR,
> FMC2_REG_BWTR,
> - FMC2_REG_PCSCNTR
> + FMC2_REG_PCSCNTR,
> + FMC2_REG_CFGR
> };
>
> enum stm32_fmc2_ebi_transaction_type {
> @@ -134,9 +148,27 @@ enum stm32_fmc2_ebi_cpsize {
> FMC2_CPSIZE_1024 = 1024
> };
>
> +enum stm32_fmc2_ebi_cscount {
> + FMC2_CSCOUNT_0 = 0,
> + FMC2_CSCOUNT_1 = 1,
> + FMC2_CSCOUNT_64 = 64,
> + FMC2_CSCOUNT_256 = 256
> +};
> +
> +struct stm32_fmc2_ebi;
> +
> +struct stm32_fmc2_ebi_data {
> + const struct stm32_fmc2_prop *child_props;
> + unsigned int nb_child_props;
> + u32 fmc2_enable_reg;
> + u32 fmc2_enable_bit;
> + int (*nwait_used_by_ctrls)(struct stm32_fmc2_ebi *ebi);
> +};
> +
> struct stm32_fmc2_ebi {
> struct clk clk;
> fdt_addr_t io_base;
> + const struct stm32_fmc2_ebi_data *data;
> u8 bank_assigned;
> };
>
> @@ -296,6 +328,24 @@ static u32 stm32_fmc2_ebi_ns_to_clk_period(struct stm32_fmc2_ebi *ebi,
> return DIV_ROUND_UP(nb_clk_cycles, clk_period);
> }
>
> +static u32 stm32_fmc2_ebi_mp25_ns_to_clk_period(struct stm32_fmc2_ebi *ebi,
> + int cs, u32 setup)
> +{
> + u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup);
> + u32 cfgr = readl(ebi->io_base + FMC2_CFGR);
> + u32 clk_period;
> +
> + if (cfgr & FMC2_CFGR_CCLKEN) {
> + clk_period = FIELD_GET(FMC2_CFGR_CLKDIV, cfgr) + 1;
> + } else {
> + u32 btr = readl(ebi->io_base + FMC2_BTR(cs));
> +
> + clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1;
> + }
> +
> + return DIV_ROUND_UP(nb_clk_cycles, clk_period);
> +}
> +
> static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg)
> {
> switch (reg_type) {
> @@ -311,6 +361,9 @@ static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg)
> case FMC2_REG_PCSCNTR:
> *reg = FMC2_PCSCNTR;
> break;
> + case FMC2_REG_CFGR:
> + *reg = FMC2_CFGR;
> + break;
> default:
> return -EINVAL;
> }
> @@ -649,6 +702,26 @@ static int stm32_fmc2_ebi_set_clk_period(struct stm32_fmc2_ebi *ebi,
> return 0;
> }
>
> +static int stm32_fmc2_ebi_mp25_set_clk_period(struct stm32_fmc2_ebi *ebi,
> + const struct stm32_fmc2_prop *prop,
> + int cs, u32 setup)
> +{
> + u32 cfgr = readl(ebi->io_base + FMC2_CFGR);
> + u32 val;
> +
> + if (cfgr & FMC2_CFGR_CCLKEN) {
> + val = setup ? clamp_val(setup - 1, 1, FMC2_CFGR_CLKDIV_MAX) : 1;
> + val = FIELD_PREP(FMC2_CFGR_CLKDIV, val);
> + clrsetbits_le32(ebi->io_base + FMC2_CFGR, FMC2_CFGR_CLKDIV, val);
> + } else {
> + val = setup ? clamp_val(setup - 1, 1, FMC2_BTR_CLKDIV_MAX) : 1;
> + val = FIELD_PREP(FMC2_BTR_CLKDIV, val);
> + clrsetbits_le32(ebi->io_base + FMC2_BTR(cs), FMC2_BTR_CLKDIV, val);
> + }
> +
> + return 0;
> +}
> +
> static int stm32_fmc2_ebi_set_data_latency(struct stm32_fmc2_ebi *ebi,
> const struct stm32_fmc2_prop *prop,
> int cs, u32 setup)
> @@ -689,6 +762,27 @@ static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi,
> return 0;
> }
>
> +static int stm32_fmc2_ebi_mp25_set_max_low_pulse(struct stm32_fmc2_ebi *ebi,
> + const struct stm32_fmc2_prop *prop,
> + int cs, u32 setup)
> +{
> + u32 val;
> +
> + if (setup == FMC2_CSCOUNT_0)
> + val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_0);
> + else if (setup == FMC2_CSCOUNT_1)
> + val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_1);
> + else if (setup <= FMC2_CSCOUNT_64)
> + val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_64);
> + else
> + val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_256);
> +
> + clrsetbits_le32(ebi->io_base + FMC2_BCR(cs),
> + FMC2_BCR_CSCOUNT, val);
> +
> + return 0;
> +}
> +
> static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = {
> /* st,fmc2-ebi-cs-trans-type must be the first property */
> {
> @@ -854,6 +948,171 @@ static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = {
> },
> };
>
> +static const struct stm32_fmc2_prop stm32_fmc2_mp25_child_props[] = {
> + /* st,fmc2-ebi-cs-trans-type must be the first property */
> + {
> + .name = "st,fmc2-ebi-cs-transaction-type",
> + .mprop = true,
> + .set = stm32_fmc2_ebi_set_trans_type,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-cclk-enable",
> + .bprop = true,
> + .reg_type = FMC2_REG_CFGR,
> + .reg_mask = FMC2_CFGR_CCLKEN,
> + .check = stm32_fmc2_ebi_check_sync_trans,
> + .set = stm32_fmc2_ebi_set_bit_field,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-mux-enable",
> + .bprop = true,
> + .reg_type = FMC2_REG_BCR,
> + .reg_mask = FMC2_BCR_MUXEN,
> + .check = stm32_fmc2_ebi_check_mux,
> + .set = stm32_fmc2_ebi_set_bit_field,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-buswidth",
> + .reset_val = FMC2_BUSWIDTH_16,
> + .set = stm32_fmc2_ebi_set_buswidth,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-waitpol-high",
> + .bprop = true,
> + .reg_type = FMC2_REG_BCR,
> + .reg_mask = FMC2_BCR_WAITPOL,
> + .set = stm32_fmc2_ebi_set_bit_field,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-waitcfg-enable",
> + .bprop = true,
> + .reg_type = FMC2_REG_BCR,
> + .reg_mask = FMC2_BCR_WAITCFG,
> + .check = stm32_fmc2_ebi_check_waitcfg,
> + .set = stm32_fmc2_ebi_set_bit_field,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-wait-enable",
> + .bprop = true,
> + .reg_type = FMC2_REG_BCR,
> + .reg_mask = FMC2_BCR_WAITEN,
> + .check = stm32_fmc2_ebi_check_sync_trans,
> + .set = stm32_fmc2_ebi_set_bit_field,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-asyncwait-enable",
> + .bprop = true,
> + .reg_type = FMC2_REG_BCR,
> + .reg_mask = FMC2_BCR_ASYNCWAIT,
> + .check = stm32_fmc2_ebi_check_async_trans,
> + .set = stm32_fmc2_ebi_set_bit_field,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-cpsize",
> + .check = stm32_fmc2_ebi_check_cpsize,
> + .set = stm32_fmc2_ebi_set_cpsize,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-byte-lane-setup-ns",
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_bl_setup,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-address-setup-ns",
> + .reg_type = FMC2_REG_BTR,
> + .reset_val = FMC2_BXTR_ADDSET_MAX,
> + .check = stm32_fmc2_ebi_check_async_trans,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_address_setup,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-address-hold-ns",
> + .reg_type = FMC2_REG_BTR,
> + .reset_val = FMC2_BXTR_ADDHLD_MAX,
> + .check = stm32_fmc2_ebi_check_address_hold,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_address_hold,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-data-setup-ns",
> + .reg_type = FMC2_REG_BTR,
> + .reset_val = FMC2_BXTR_DATAST_MAX,
> + .check = stm32_fmc2_ebi_check_async_trans,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_data_setup,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-bus-turnaround-ns",
> + .reg_type = FMC2_REG_BTR,
> + .reset_val = FMC2_BXTR_BUSTURN_MAX + 1,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_bus_turnaround,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-data-hold-ns",
> + .reg_type = FMC2_REG_BTR,
> + .check = stm32_fmc2_ebi_check_async_trans,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_data_hold,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-clk-period-ns",
> + .reset_val = FMC2_CFGR_CLKDIV_MAX + 1,
> + .check = stm32_fmc2_ebi_check_sync_trans,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_mp25_set_clk_period,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-data-latency-ns",
> + .check = stm32_fmc2_ebi_check_sync_trans,
> + .calculate = stm32_fmc2_ebi_mp25_ns_to_clk_period,
> + .set = stm32_fmc2_ebi_set_data_latency,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-write-address-setup-ns",
> + .reg_type = FMC2_REG_BWTR,
> + .reset_val = FMC2_BXTR_ADDSET_MAX,
> + .check = stm32_fmc2_ebi_check_async_trans,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_address_setup,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-write-address-hold-ns",
> + .reg_type = FMC2_REG_BWTR,
> + .reset_val = FMC2_BXTR_ADDHLD_MAX,
> + .check = stm32_fmc2_ebi_check_address_hold,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_address_hold,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-write-data-setup-ns",
> + .reg_type = FMC2_REG_BWTR,
> + .reset_val = FMC2_BXTR_DATAST_MAX,
> + .check = stm32_fmc2_ebi_check_async_trans,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_data_setup,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-write-bus-turnaround-ns",
> + .reg_type = FMC2_REG_BWTR,
> + .reset_val = FMC2_BXTR_BUSTURN_MAX + 1,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_bus_turnaround,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-write-data-hold-ns",
> + .reg_type = FMC2_REG_BWTR,
> + .check = stm32_fmc2_ebi_check_async_trans,
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_set_data_hold,
> + },
> + {
> + .name = "st,fmc2-ebi-cs-max-low-pulse-ns",
> + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles,
> + .set = stm32_fmc2_ebi_mp25_set_max_low_pulse,
> + },
> +};
> +
> static int stm32_fmc2_ebi_parse_prop(struct stm32_fmc2_ebi *ebi,
> ofnode node,
> const struct stm32_fmc2_prop *prop,
> @@ -915,7 +1174,7 @@ static void stm32_fmc2_ebi_disable_bank(struct stm32_fmc2_ebi *ebi, int cs)
> }
>
> /* NWAIT signal can not be connected to EBI controller and NAND controller */
> -static bool stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi)
> +static int stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi)
> {
> unsigned int cs;
> u32 bcr;
> @@ -926,16 +1185,19 @@ static bool stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi)
>
> bcr = readl(ebi->io_base + FMC2_BCR(cs));
> if ((bcr & FMC2_BCR_WAITEN || bcr & FMC2_BCR_ASYNCWAIT) &&
> - ebi->bank_assigned & BIT(FMC2_NAND))
> - return true;
> + ebi->bank_assigned & BIT(FMC2_NAND)) {
> + log_err("NWAIT signal connected to EBI and NAND controllers\n");
> + return -EINVAL;
> + }
> }
>
> - return false;
> + return 0;
> }
>
> static void stm32_fmc2_ebi_enable(struct stm32_fmc2_ebi *ebi)
> {
> - setbits_le32(ebi->io_base + FMC2_BCR1, FMC2_BCR1_FMC2EN);
> + setbits_le32(ebi->io_base + ebi->data->fmc2_enable_reg,
> + ebi->data->fmc2_enable_bit);
> }
>
> static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi,
> @@ -946,8 +1208,8 @@ static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi,
>
> stm32_fmc2_ebi_disable_bank(ebi, cs);
>
> - for (i = 0; i < ARRAY_SIZE(stm32_fmc2_child_props); i++) {
> - const struct stm32_fmc2_prop *p = &stm32_fmc2_child_props[i];
> + for (i = 0; i < ebi->data->nb_child_props; i++) {
> + const struct stm32_fmc2_prop *p = &ebi->data->child_props[i];
>
> ret = stm32_fmc2_ebi_parse_prop(ebi, node, p, cs);
> if (ret) {
> @@ -1004,9 +1266,10 @@ static int stm32_fmc2_ebi_parse_dt(struct udevice *dev,
> return -ENODEV;
> }
>
> - if (stm32_fmc2_ebi_nwait_used_by_ctrls(ebi)) {
> - dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n");
> - return -EINVAL;
> + if (ebi->data->nwait_used_by_ctrls) {
> + ret = ebi->data->nwait_used_by_ctrls(ebi);
> + if (ret)
> + return ret;
> }
>
> stm32_fmc2_ebi_enable(ebi);
> @@ -1020,6 +1283,10 @@ static int stm32_fmc2_ebi_probe(struct udevice *dev)
> struct reset_ctl reset;
> int ret;
>
> + ebi->data = (void *)dev_get_driver_data(dev);
> + if (!ebi->data)
> + return -EINVAL;
> +
> ebi->io_base = dev_read_addr(dev);
> if (ebi->io_base == FDT_ADDR_T_NONE)
> return -EINVAL;
> @@ -1042,8 +1309,30 @@ static int stm32_fmc2_ebi_probe(struct udevice *dev)
> return stm32_fmc2_ebi_parse_dt(dev, ebi);
> }
>
> +static const struct stm32_fmc2_ebi_data stm32_fmc2_ebi_mp1_data = {
> + .child_props = stm32_fmc2_child_props,
> + .nb_child_props = ARRAY_SIZE(stm32_fmc2_child_props),
> + .fmc2_enable_reg = FMC2_BCR1,
> + .fmc2_enable_bit = FMC2_BCR1_FMC2EN,
> + .nwait_used_by_ctrls = stm32_fmc2_ebi_nwait_used_by_ctrls,
> +};
> +
> +static const struct stm32_fmc2_ebi_data stm32_fmc2_ebi_mp25_data = {
> + .child_props = stm32_fmc2_mp25_child_props,
> + .nb_child_props = ARRAY_SIZE(stm32_fmc2_mp25_child_props),
> + .fmc2_enable_reg = FMC2_CFGR,
> + .fmc2_enable_bit = FMC2_CFGR_FMC2EN,
> +};
> +
> static const struct udevice_id stm32_fmc2_ebi_match[] = {
> - {.compatible = "st,stm32mp1-fmc2-ebi"},
> + {
> + .compatible = "st,stm32mp1-fmc2-ebi",
> + .data = (ulong)&stm32_fmc2_ebi_mp1_data,
> + },
> + {
> + .compatible = "st,stm32mp25-fmc2-ebi",
> + .data = (ulong)&stm32_fmc2_ebi_mp25_data,
> + },
> { /* Sentinel */ }
> };
>
Reviewed-by: Patrice Chotard <patrice.chotard at foss.st.com>
Thanks
Patrice
More information about the U-Boot
mailing list