[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