summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2024-04-19 07:28:43 -0600
committerTom Rini <[email protected]>2024-04-19 14:25:04 -0600
commitaf04f37a78c7e61597fb9ed6db2c8f8d7f8b0f92 (patch)
tree2f724d6d7776f4a79bcc41274035240ed3b0b6a5 /drivers
parentc9e25d8c1d2c844ab76a7b0195f293275dcfdc6e (diff)
parentb0283b5e3d37daff48b45c3f98d298844603def4 (diff)
Merge tag 'u-boot-stm32-20240419' of https://source.denx.de/u-boot/custodians/u-boot-stm
MP1: _ Add OHCI HCD support for STM32MP15xx DHSOM _ Report OTP-CLOSED instead of rev.? on closed STM32MP15xx _ Initialize TAMP_SMCR BKP..PROT fields on STM32MP15xx _ Jump to ep on successful resume in PSCI suspend code _ Add FASTBOOT support for STM32MP13 _ Fix/Rework key and leds management for STM32MP13/15 _ net: dwc_eth_qos: Clean up STM32 glue code and add STM32MP13xx support MP2: _ Add stm32-fmc-ebi support _ Add: sdmmc2 support and fix AARCH64 compilation
Diffstat (limited to 'drivers')
-rw-r--r--drivers/memory/stm32-fmc2-ebi.c449
-rw-r--r--drivers/mmc/stm32_sdmmc2.c9
-rw-r--r--drivers/mtd/nand/raw/stm32_fmc2_nand.c47
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/dwc_eth_qos.c171
-rw-r--r--drivers/net/dwc_eth_qos.h2
-rw-r--r--drivers/net/dwc_eth_qos_stm32.c325
7 files changed, 815 insertions, 189 deletions
diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c
index a722a3836f7..1ce96077858 100644
--- a/drivers/memory/stm32-fmc2-ebi.c
+++ b/drivers/memory/stm32-fmc2-ebi.c
@@ -22,8 +22,15 @@
#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_SR 0x84
#define FMC2_BWTR1 0x104
#define FMC2_BWTR(x) ((x) * 0x8 + FMC2_BWTR1)
+#define FMC2_SECCFGR 0x300
+#define FMC2_CIDCFGR0 0x30c
+#define FMC2_CIDCFGR(x) ((x) * 0x8 + FMC2_CIDCFGR0)
+#define FMC2_SEMCR0 0x310
+#define FMC2_SEMCR(x) ((x) * 0x8 + FMC2_SEMCR0)
/* Register: FMC2_BCR1 */
#define FMC2_BCR1_CCLKEN BIT(20)
@@ -44,6 +51,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,8 +68,28 @@
#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)
+
+/* Register: FMC2_SR */
+#define FMC2_SR_ISOST GENMASK(1, 0)
+
+/* Register: FMC2_CIDCFGR */
+#define FMC2_CIDCFGR_CFEN BIT(0)
+#define FMC2_CIDCFGR_SEMEN BIT(1)
+#define FMC2_CIDCFGR_SCID GENMASK(6, 4)
+#define FMC2_CIDCFGR_SEMWLC1 BIT(17)
+
+/* Register: FMC2_SEMCR */
+#define FMC2_SEMCR_SEM_MUTEX BIT(0)
+#define FMC2_SEMCR_SEMCID GENMASK(6, 4)
+
#define FMC2_MAX_EBI_CE 4
#define FMC2_MAX_BANKS 5
+#define FMC2_MAX_RESOURCES 6
+#define FMC2_CID1 1
#define FMC2_BCR_CPSIZE_0 0x0
#define FMC2_BCR_CPSIZE_128 0x1
@@ -76,6 +104,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 +123,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 +137,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,10 +169,30 @@ 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);
+ int (*check_rif)(struct stm32_fmc2_ebi *ebi, u32 resource);
+};
+
struct stm32_fmc2_ebi {
struct clk clk;
fdt_addr_t io_base;
+ const struct stm32_fmc2_ebi_data *data;
u8 bank_assigned;
+ bool access_granted;
};
/*
@@ -209,6 +264,28 @@ static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi,
return -EINVAL;
}
+static int stm32_fmc2_ebi_mp25_check_cclk(struct stm32_fmc2_ebi *ebi,
+ const struct stm32_fmc2_prop *prop,
+ int cs)
+{
+ if (!ebi->access_granted)
+ return -EACCES;
+
+ return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs);
+}
+
+static int stm32_fmc2_ebi_mp25_check_clk_period(struct stm32_fmc2_ebi *ebi,
+ const struct stm32_fmc2_prop *prop,
+ int cs)
+{
+ u32 cfgr = readl(ebi->io_base + FMC2_CFGR);
+
+ if (cfgr & FMC2_CFGR_CCLKEN && !ebi->access_granted)
+ return -EACCES;
+
+ return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs);
+}
+
static int stm32_fmc2_ebi_check_async_trans(struct stm32_fmc2_ebi *ebi,
const struct stm32_fmc2_prop *prop,
int cs)
@@ -296,6 +373,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 +406,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 +747,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 +807,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 +993,235 @@ 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_mp25_check_cclk,
+ .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_mp25_check_clk_period,
+ .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_mp25_check_rif(struct stm32_fmc2_ebi *ebi, u32 resource)
+{
+ u32 seccfgr, cidcfgr, semcr;
+ int cid;
+
+ if (resource >= FMC2_MAX_RESOURCES)
+ return -EINVAL;
+
+ seccfgr = readl(ebi->io_base + FMC2_SECCFGR);
+ if (seccfgr & BIT(resource)) {
+ if (resource)
+ log_err("resource %d is configured as secure\n",
+ resource);
+
+ return -EACCES;
+ }
+
+ cidcfgr = readl(ebi->io_base + FMC2_CIDCFGR(resource));
+ if (!(cidcfgr & FMC2_CIDCFGR_CFEN))
+ /* CID filtering is turned off: access granted */
+ return 0;
+
+ if (!(cidcfgr & FMC2_CIDCFGR_SEMEN)) {
+ /* Static CID mode */
+ cid = FIELD_GET(FMC2_CIDCFGR_SCID, cidcfgr);
+ if (cid != FMC2_CID1) {
+ if (resource)
+ log_err("static CID%d set for resource %d\n",
+ cid, resource);
+
+ return -EACCES;
+ }
+
+ return 0;
+ }
+
+ /* Pass-list with semaphore mode */
+ if (!(cidcfgr & FMC2_CIDCFGR_SEMWLC1)) {
+ if (resource)
+ log_err("CID1 is block-listed for resource %d\n",
+ resource);
+
+ return -EACCES;
+ }
+
+ semcr = readl(ebi->io_base + FMC2_SEMCR(resource));
+ if (!(semcr & FMC2_SEMCR_SEM_MUTEX)) {
+ setbits_le32(ebi->io_base + FMC2_SEMCR(resource),
+ FMC2_SEMCR_SEM_MUTEX);
+ semcr = readl(ebi->io_base + FMC2_SEMCR(resource));
+ }
+
+ cid = FIELD_GET(FMC2_SEMCR_SEMCID, semcr);
+ if (cid != FMC2_CID1) {
+ if (resource)
+ log_err("resource %d is already used by CID%d\n",
+ resource, cid);
+
+ return -EACCES;
+ }
+
+ return 0;
+}
+
static int stm32_fmc2_ebi_parse_prop(struct stm32_fmc2_ebi *ebi,
ofnode node,
const struct stm32_fmc2_prop *prop,
@@ -915,7 +1283,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 +1294,22 @@ 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);
+ if (!ebi->access_granted)
+ return;
+
+ 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 +1320,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) {
@@ -987,6 +1361,14 @@ static int stm32_fmc2_ebi_parse_dt(struct udevice *dev,
return -EINVAL;
}
+ if (ebi->data->check_rif) {
+ ret = ebi->data->check_rif(ebi, bank + 1);
+ if (ret) {
+ dev_err(dev, "bank access failed: %d\n", bank);
+ return ret;
+ }
+ }
+
if (bank < FMC2_MAX_EBI_CE) {
ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank);
if (ret) {
@@ -1004,9 +1386,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 +1403,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;
@@ -1039,11 +1426,49 @@ static int stm32_fmc2_ebi_probe(struct udevice *dev)
reset_deassert(&reset);
}
+ /* Check if CFGR register can be modified */
+ ebi->access_granted = true;
+ if (ebi->data->check_rif) {
+ ret = ebi->data->check_rif(ebi, 0);
+ if (ret) {
+ ebi->access_granted = false;
+
+ /* In case of CFGR is secure, just check that the FMC2 is enabled */
+ if (readl(ebi->io_base + FMC2_SR) & FMC2_SR_ISOST) {
+ dev_err(dev, "FMC2 is not ready to be used.\n");
+ return -EACCES;
+ }
+ }
+ }
+
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,
+ .check_rif = stm32_fmc2_ebi_mp25_check_rif,
+};
+
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 */ }
};
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c
index a2b111a8435..39ae79ba129 100644
--- a/drivers/mmc/stm32_sdmmc2.c
+++ b/drivers/mmc/stm32_sdmmc2.c
@@ -220,9 +220,9 @@ static void stm32_sdmmc2_start_data(struct udevice *dev,
if (data->flags & MMC_DATA_READ) {
data_ctrl |= SDMMC_DCTRL_DTDIR;
- idmabase0 = (u32)data->dest;
+ idmabase0 = (u32)(long)data->dest;
} else {
- idmabase0 = (u32)data->src;
+ idmabase0 = (u32)(long)data->src;
}
/* Set the SDMMC DataLength value */
@@ -463,8 +463,8 @@ retry_cmd:
stm32_sdmmc2_start_cmd(dev, cmd, cmdat, &ctx);
- dev_dbg(dev, "send cmd %d data: 0x%x @ 0x%x\n",
- cmd->cmdidx, data ? ctx.data_length : 0, (unsigned int)data);
+ dev_dbg(dev, "send cmd %d data: 0x%x @ 0x%p\n",
+ cmd->cmdidx, data ? ctx.data_length : 0, data);
ret = stm32_sdmmc2_end_cmd(dev, cmd, &ctx);
@@ -789,6 +789,7 @@ static int stm32_sdmmc2_bind(struct udevice *dev)
static const struct udevice_id stm32_sdmmc2_ids[] = {
{ .compatible = "st,stm32-sdmmc2" },
+ { .compatible = "st,stm32mp25-sdmmc2" },
{ }
};
diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
index 3528824575b..d284b8cbb12 100644
--- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c
+++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c
@@ -34,7 +34,7 @@
#define FMC2_RB_DELAY_US 30
/* Max chip enable */
-#define FMC2_MAX_CE 2
+#define FMC2_MAX_CE 4
/* Timings */
#define FMC2_THIZ 1
@@ -160,6 +160,11 @@ static inline struct stm32_fmc2_nand *to_fmc2_nand(struct nand_chip *chip)
return container_of(chip, struct stm32_fmc2_nand, chip);
}
+struct stm32_fmc2_nfc_data {
+ int max_ncs;
+ struct udevice *(*get_cdev)(struct udevice *dev);
+};
+
struct stm32_fmc2_nfc {
struct nand_hw_control base;
struct stm32_fmc2_nand nand;
@@ -169,6 +174,7 @@ struct stm32_fmc2_nfc {
fdt_addr_t cmd_base[FMC2_MAX_CE];
fdt_addr_t addr_base[FMC2_MAX_CE];
struct clk clk;
+ const struct stm32_fmc2_nfc_data *data;
u8 cs_assigned;
int cs_sel;
@@ -815,7 +821,7 @@ static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc, ofnode node)
}
for (i = 0; i < nand->ncs; i++) {
- if (cs[i] >= FMC2_MAX_CE) {
+ if (cs[i] >= nfc->data->max_ncs) {
log_err("Invalid reg value: %d\n", nand->cs_used[i]);
return -EINVAL;
}
@@ -906,10 +912,18 @@ static int stm32_fmc2_nfc_probe(struct udevice *dev)
spin_lock_init(&nfc->controller.lock);
init_waitqueue_head(&nfc->controller.wq);
- cdev = stm32_fmc2_nfc_get_cdev(dev);
- if (!cdev)
+ nfc->data = (void *)dev_get_driver_data(dev);
+ if (!nfc->data)
return -EINVAL;
+ if (nfc->data->get_cdev) {
+ cdev = nfc->data->get_cdev(dev);
+ if (!cdev)
+ return -EINVAL;
+ } else {
+ cdev = dev->parent;
+ }
+
ret = stm32_fmc2_nfc_parse_dt(dev, nfc);
if (ret)
return ret;
@@ -921,7 +935,7 @@ static int stm32_fmc2_nfc_probe(struct udevice *dev)
if (dev == cdev)
start_region = 1;
- for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE;
+ for (chip_cs = 0, mem_region = start_region; chip_cs < nfc->data->max_ncs;
chip_cs++, mem_region += 3) {
if (!(nfc->cs_assigned & BIT(chip_cs)))
continue;
@@ -1033,9 +1047,28 @@ static int stm32_fmc2_nfc_probe(struct udevice *dev)
return nand_register(0, mtd);
}
+static const struct stm32_fmc2_nfc_data stm32_fmc2_nfc_mp1_data = {
+ .max_ncs = 2,
+ .get_cdev = stm32_fmc2_nfc_get_cdev,
+};
+
+static const struct stm32_fmc2_nfc_data stm32_fmc2_nfc_mp25_data = {
+ .max_ncs = 4,
+};
+
static const struct udevice_id stm32_fmc2_nfc_match[] = {
- { .compatible = "st,stm32mp15-fmc2" },
- { .compatible = "st,stm32mp1-fmc2-nfc" },
+ {
+ .compatible = "st,stm32mp15-fmc2",
+ .data = (ulong)&stm32_fmc2_nfc_mp1_data,
+ },
+ {
+ .compatible = "st,stm32mp1-fmc2-nfc",
+ .data = (ulong)&stm32_fmc2_nfc_mp1_data,
+ },
+ {
+ .compatible = "st,stm32mp25-fmc2-nfc",
+ .data = (ulong)&stm32_fmc2_nfc_mp25_data,
+ },
{ /* Sentinel */ }
};
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 6677366ebd6..dc3404519d6 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o
obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o
obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o
obj-$(CONFIG_DWC_ETH_QOS_STARFIVE) += dwc_eth_qos_starfive.o
+obj-$(CONFIG_DWC_ETH_QOS_STM32) += dwc_eth_qos_stm32.o
obj-$(CONFIG_E1000) += e1000.o
obj-$(CONFIG_E1000_SPI) += e1000_spi.o
obj-$(CONFIG_EEPRO100) += eepro100.o
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 67d80d987ff..32a5d52165a 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -295,58 +295,6 @@ err:
#endif
}
-static int eqos_start_clks_stm32(struct udevice *dev)
-{
-#ifdef CONFIG_CLK
- struct eqos_priv *eqos = dev_get_priv(dev);
- int ret;
-
- debug("%s(dev=%p):\n", __func__, dev);
-
- ret = clk_enable(&eqos->clk_master_bus);
- if (ret < 0) {
- pr_err("clk_enable(clk_master_bus) failed: %d\n", ret);
- goto err;
- }
-
- ret = clk_enable(&eqos->clk_rx);
- if (ret < 0) {
- pr_err("clk_enable(clk_rx) failed: %d\n", ret);
- goto err_disable_clk_master_bus;
- }
-
- ret = clk_enable(&eqos->clk_tx);
- if (ret < 0) {
- pr_err("clk_enable(clk_tx) failed: %d\n", ret);
- goto err_disable_clk_rx;
- }
-
- if (clk_valid(&eqos->clk_ck) && !eqos->clk_ck_enabled) {
- ret = clk_enable(&eqos->clk_ck);
- if (ret < 0) {
- pr_err("clk_enable(clk_ck) failed: %d\n", ret);
- goto err_disable_clk_tx;
- }
- eqos->clk_ck_enabled = true;
- }
-#endif
-
- debug("%s: OK\n", __func__);
- return 0;
-
-#ifdef CONFIG_CLK
-err_disable_clk_tx:
- clk_disable(&eqos->clk_tx);
-err_disable_clk_rx:
- clk_disable(&eqos->clk_rx);
-err_disable_clk_master_bus:
- clk_disable(&eqos->clk_master_bus);
-err:
- debug("%s: FAILED: %d\n", __func__, ret);
- return ret;
-#endif
-}
-
static int eqos_stop_clks_tegra186(struct udevice *dev)
{
#ifdef CONFIG_CLK
@@ -365,22 +313,6 @@ static int eqos_stop_clks_tegra186(struct udevice *dev)
return 0;
}
-static int eqos_stop_clks_stm32(struct udevice *dev)
-{
-#ifdef CONFIG_CLK
- struct eqos_priv *eqos = dev_get_priv(dev);
-
- debug("%s(dev=%p):\n", __func__, dev);
-
- clk_disable(&eqos->clk_tx);
- clk_disable(&eqos->clk_rx);
- clk_disable(&eqos->clk_master_bus);
-#endif
-
- debug("%s: OK\n", __func__);
- return 0;
-}
-
static int eqos_start_resets_tegra186(struct udevice *dev)
{
struct eqos_priv *eqos = dev_get_priv(dev);
@@ -493,17 +425,6 @@ static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev)
#endif
}
-static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev)
-{
-#ifdef CONFIG_CLK
- struct eqos_priv *eqos = dev_get_priv(dev);
-
- return clk_get_rate(&eqos->clk_master_bus);
-#else
- return 0;
-#endif
-}
-
static int eqos_set_full_duplex(struct udevice *dev)
{
struct eqos_priv *eqos = dev_get_priv(dev);
@@ -1415,57 +1336,6 @@ err_free_reset_eqos:
return ret;
}
-static int eqos_probe_resources_stm32(struct udevice *dev)
-{
- struct eqos_priv *eqos = dev_get_priv(dev);
- int ret;
- phy_interface_t interface;
-
- debug("%s(dev=%p):\n", __func__, dev);
-
- interface = eqos->config->interface(dev);
-
- if (interface == PHY_INTERFACE_MODE_NA) {
- pr_err("Invalid PHY interface\n");
- return -EINVAL;
- }
-
- ret = board_interface_eth_init(dev, interface);
- if (ret)
- return -EINVAL;
-
- ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
- if (ret) {
- pr_err("clk_get_by_name(master_bus) failed: %d\n", ret);
- goto err_probe;
- }
-
- ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx);
- if (ret) {
- pr_err("clk_get_by_name(rx) failed: %d\n", ret);
- goto err_probe;
- }
-
- ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx);
- if (ret) {
- pr_err("clk_get_by_name(tx) failed: %d\n", ret);
- goto err_probe;
- }
-
- /* Get ETH_CLK clocks (optional) */
- ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck);
- if (ret)
- pr_warn("No phy clock provided %d", ret);
-
- debug("%s: OK\n", __func__);
- return 0;
-
-err_probe:
-
- debug("%s: returns %d\n", __func__, ret);
- return ret;
-}
-
static phy_interface_t eqos_get_interface_tegra186(const struct udevice *dev)
{
return PHY_INTERFACE_MODE_MII;
@@ -1484,12 +1354,6 @@ static int eqos_remove_resources_tegra186(struct udevice *dev)
return 0;
}
-static int eqos_remove_resources_stm32(struct udevice *dev)
-{
- debug("%s(dev=%p):\n", __func__, dev);
- return 0;
-}
-
static int eqos_probe(struct udevice *dev)
{
struct eqos_priv *eqos = dev_get_priv(dev);
@@ -1633,35 +1497,6 @@ static const struct eqos_config __maybe_unused eqos_tegra186_config = {
.ops = &eqos_tegra186_ops
};
-static struct eqos_ops eqos_stm32_ops = {
- .eqos_inval_desc = eqos_inval_desc_generic,
- .eqos_flush_desc = eqos_flush_desc_generic,
- .eqos_inval_buffer = eqos_inval_buffer_generic,
- .eqos_flush_buffer = eqos_flush_buffer_generic,
- .eqos_probe_resources = eqos_probe_resources_stm32,
- .eqos_remove_resources = eqos_remove_resources_stm32,
- .eqos_stop_resets = eqos_null_ops,
- .eqos_start_resets = eqos_null_ops,
- .eqos_stop_clks = eqos_stop_clks_stm32,
- .eqos_start_clks = eqos_start_clks_stm32,
- .eqos_calibrate_pads = eqos_null_ops,
- .eqos_disable_calibration = eqos_null_ops,
- .eqos_set_tx_clk_speed = eqos_null_ops,
- .eqos_get_enetaddr = eqos_null_ops,
- .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32
-};
-
-static const struct eqos_config __maybe_unused eqos_stm32_config = {
- .reg_access_always_ok = false,
- .mdio_wait = 10000,
- .swr_wait = 50,
- .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV,
- .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
- .axi_bus_width = EQOS_AXI_WIDTH_64,
- .interface = dev_read_phy_mode,
- .ops = &eqos_stm32_ops
-};
-
static const struct udevice_id eqos_ids[] = {
#if IS_ENABLED(CONFIG_DWC_ETH_QOS_TEGRA186)
{
@@ -1671,8 +1506,12 @@ static const struct udevice_id eqos_ids[] = {
#endif
#if IS_ENABLED(CONFIG_DWC_ETH_QOS_STM32)
{
+ .compatible = "st,stm32mp13-dwmac",
+ .data = (ulong)&eqos_stm32mp13_config
+ },
+ {
.compatible = "st,stm32mp1-dwmac",
- .data = (ulong)&eqos_stm32_config
+ .data = (ulong)&eqos_stm32mp15_config
},
#endif
#if IS_ENABLED(CONFIG_DWC_ETH_QOS_IMX)
diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h
index e3222e1e17e..8b3d0d464d3 100644
--- a/drivers/net/dwc_eth_qos.h
+++ b/drivers/net/dwc_eth_qos.h
@@ -290,4 +290,6 @@ int eqos_null_ops(struct udevice *dev);
extern struct eqos_config eqos_imx_config;
extern struct eqos_config eqos_rockchip_config;
extern struct eqos_config eqos_qcom_config;
+extern struct eqos_config eqos_stm32mp13_config;
+extern struct eqos_config eqos_stm32mp15_config;
extern struct eqos_config eqos_jh7110_config;
diff --git a/drivers/net/dwc_eth_qos_stm32.c b/drivers/net/dwc_eth_qos_stm32.c
new file mode 100644
index 00000000000..fbc08bba1d6
--- /dev/null
+++ b/drivers/net/dwc_eth_qos_stm32.c
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024, Marek Vasut <[email protected]>
+ *
+ * This is code moved from drivers/net/dwc_eth_qos.c , which is:
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ */
+
+#include <asm/cache.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <errno.h>
+#include <eth_phy.h>
+#include <log.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <miiphy.h>
+#include <net.h>
+#include <netdev.h>
+#include <phy.h>
+#include <regmap.h>
+#include <reset.h>
+#include <syscon.h>
+#include <wait_bit.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+
+#include "dwc_eth_qos.h"
+
+/* SYSCFG registers */
+#define SYSCFG_PMCSETR 0x04
+#define SYSCFG_PMCCLRR_MP13 0x08
+#define SYSCFG_PMCCLRR_MP15 0x44
+
+#define SYSCFG_PMCSETR_ETH1_MASK GENMASK(23, 16)
+#define SYSCFG_PMCSETR_ETH2_MASK GENMASK(31, 24)
+
+#define SYSCFG_PMCSETR_ETH_CLK_SEL BIT(16)
+#define SYSCFG_PMCSETR_ETH_REF_CLK_SEL BIT(17)
+
+/* STM32MP15xx specific bit */
+#define SYSCFG_PMCSETR_ETH_SELMII BIT(20)
+
+#define SYSCFG_PMCSETR_ETH_SEL_MASK GENMASK(23, 21)
+#define SYSCFG_PMCSETR_ETH_SEL_GMII_MII 0x0
+#define SYSCFG_PMCSETR_ETH_SEL_RGMII 0x1
+#define SYSCFG_PMCSETR_ETH_SEL_RMII 0x4
+
+static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev)
+{
+ struct eqos_priv __maybe_unused *eqos = dev_get_priv(dev);
+
+ if (!CONFIG_IS_ENABLED(CLK))
+ return 0;
+
+ return clk_get_rate(&eqos->clk_master_bus);
+}
+
+static int eqos_start_clks_stm32(struct udevice *dev)
+{
+ struct eqos_priv __maybe_unused *eqos = dev_get_priv(dev);
+ int ret;
+
+ if (!CONFIG_IS_ENABLED(CLK))
+ return 0;
+
+ dev_dbg(dev, "%s:\n", __func__);
+
+ ret = clk_enable(&eqos->clk_master_bus);
+ if (ret < 0) {
+ dev_err(dev, "clk_enable(clk_master_bus) failed: %d\n", ret);
+ goto err;
+ }
+
+ ret = clk_enable(&eqos->clk_rx);
+ if (ret < 0) {
+ dev_err(dev, "clk_enable(clk_rx) failed: %d\n", ret);
+ goto err_disable_clk_master_bus;
+ }
+
+ ret = clk_enable(&eqos->clk_tx);
+ if (ret < 0) {
+ dev_err(dev, "clk_enable(clk_tx) failed: %d\n", ret);
+ goto err_disable_clk_rx;
+ }
+
+ if (clk_valid(&eqos->clk_ck) && !eqos->clk_ck_enabled) {
+ ret = clk_enable(&eqos->clk_ck);
+ if (ret < 0) {
+ dev_err(dev, "clk_enable(clk_ck) failed: %d\n", ret);
+ goto err_disable_clk_tx;
+ }
+ eqos->clk_ck_enabled = true;
+ }
+
+ dev_dbg(dev, "%s: OK\n", __func__);
+ return 0;
+
+err_disable_clk_tx:
+ clk_disable(&eqos->clk_tx);
+err_disable_clk_rx:
+ clk_disable(&eqos->clk_rx);
+err_disable_clk_master_bus:
+ clk_disable(&eqos->clk_master_bus);
+err:
+ dev_dbg(dev, "%s: FAILED: %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int eqos_stop_clks_stm32(struct udevice *dev)
+{
+ struct eqos_priv __maybe_unused *eqos = dev_get_priv(dev);
+
+ if (!CONFIG_IS_ENABLED(CLK))
+ return 0;
+
+ dev_dbg(dev, "%s:\n", __func__);
+
+ clk_disable(&eqos->clk_tx);
+ clk_disable(&eqos->clk_rx);
+ clk_disable(&eqos->clk_master_bus);
+
+ dev_dbg(dev, "%s: OK\n", __func__);
+
+ return 0;
+}
+
+static int eqos_probe_syscfg_stm32(struct udevice *dev,
+ phy_interface_t interface_type)
+{
+ /* Ethernet 50MHz RMII clock selection. */
+ const bool eth_ref_clk_sel = dev_read_bool(dev, "st,eth-ref-clk-sel");
+ /* SoC is STM32MP13xx with two ethernet MACs */
+ const bool is_mp13 = device_is_compatible(dev, "st,stm32mp13-dwmac");
+ /* Gigabit Ethernet 125MHz clock selection. */
+ const bool eth_clk_sel = dev_read_bool(dev, "st,eth-clk-sel");
+ /* Ethernet clock source is RCC. */
+ const bool ext_phyclk = dev_read_bool(dev, "st,ext-phyclk");
+ struct regmap *regmap;
+ u32 regmap_mask;
+ u32 value;
+
+ regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscon");
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ regmap_mask = dev_read_u32_index_default(dev, "st,syscon", 2,
+ SYSCFG_PMCSETR_ETH1_MASK);
+
+ switch (interface_type) {
+ case PHY_INTERFACE_MODE_MII:
+ dev_dbg(dev, "PHY_INTERFACE_MODE_MII\n");
+ value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
+ SYSCFG_PMCSETR_ETH_SEL_GMII_MII);
+ /*
+ * STM32MP15xx supports both MII and GMII, STM32MP13xx MII only.
+ * SYSCFG_PMCSETR ETH_SELMII is present only on STM32MP15xx and
+ * acts as a selector between 0:GMII and 1:MII. As STM32MP13xx
+ * supports only MII, ETH_SELMII is not present.
+ */
+ if (!is_mp13) /* Select MII mode on STM32MP15xx */
+ value |= SYSCFG_PMCSETR_ETH_SELMII;
+ break;
+ case PHY_INTERFACE_MODE_GMII: /* STM32MP15xx only */
+ dev_dbg(dev, "PHY_INTERFACE_MODE_GMII\n");
+ value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
+ SYSCFG_PMCSETR_ETH_SEL_GMII_MII);
+ /*
+ * If eth_clk_sel is set, use internal ETH_CLKx clock from RCC,
+ * otherwise use external clock from IO pin (requires matching
+ * GPIO block AF setting of that pin).
+ */
+ if (eth_clk_sel || ext_phyclk)
+ value |= SYSCFG_PMCSETR_ETH_CLK_SEL;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ dev_dbg(dev, "PHY_INTERFACE_MODE_RMII\n");
+ value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
+ SYSCFG_PMCSETR_ETH_SEL_RMII);
+ /*
+ * If eth_ref_clk_sel is set, use internal clock from RCC,
+ * otherwise use external clock from ETHn_RX_CLK/ETHn_REF_CLK
+ * IO pin (requires matching GPIO block AF setting of that
+ * pin).
+ */
+ if (eth_ref_clk_sel || ext_phyclk)
+ value |= SYSCFG_PMCSETR_ETH_REF_CLK_SEL;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ dev_dbg(dev, "PHY_INTERFACE_MODE_RGMII\n");
+ value = FIELD_PREP(SYSCFG_PMCSETR_ETH_SEL_MASK,
+ SYSCFG_PMCSETR_ETH_SEL_RGMII);
+ /*
+ * If eth_clk_sel is set, use internal ETH_CLKx clock from RCC,
+ * otherwise use external clock from ETHx_CLK125 pin (requires
+ * matching GPIO block AF setting of that pin).
+ */
+ if (eth_clk_sel || ext_phyclk)
+ value |= SYSCFG_PMCSETR_ETH_CLK_SEL;
+ break;
+ default:
+ dev_dbg(dev, "Do not manage %d interface\n",
+ interface_type);
+ /* Do not manage others interfaces */
+ return -EINVAL;
+ }
+
+ /* Shift value at correct ethernet MAC offset in SYSCFG_PMCSETR */
+ value <<= ffs(regmap_mask) - ffs(SYSCFG_PMCSETR_ETH1_MASK);
+
+ /* Update PMCCLRR (clear register) */
+ regmap_write(regmap, is_mp13 ?
+ SYSCFG_PMCCLRR_MP13 : SYSCFG_PMCCLRR_MP15,
+ regmap_mask);
+
+ return regmap_update_bits(regmap, SYSCFG_PMCSETR, regmap_mask, value);
+}
+
+static int eqos_probe_resources_stm32(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ phy_interface_t interface;
+ int ret;
+
+ dev_dbg(dev, "%s:\n", __func__);
+
+ interface = eqos->config->interface(dev);
+
+ if (interface == PHY_INTERFACE_MODE_NA) {
+ dev_err(dev, "Invalid PHY interface\n");
+ return -EINVAL;
+ }
+
+ ret = eqos_probe_syscfg_stm32(dev, interface);
+ if (ret)
+ return -EINVAL;
+
+ ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
+ if (ret) {
+ dev_err(dev, "clk_get_by_name(master_bus) failed: %d\n", ret);
+ goto err_probe;
+ }
+
+ ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx);
+ if (ret) {
+ dev_err(dev, "clk_get_by_name(rx) failed: %d\n", ret);
+ goto err_probe;
+ }
+
+ ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx);
+ if (ret) {
+ dev_err(dev, "clk_get_by_name(tx) failed: %d\n", ret);
+ goto err_probe;
+ }
+
+ /* Get ETH_CLK clocks (optional) */
+ ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck);
+ if (ret)
+ dev_warn(dev, "No phy clock provided %d\n", ret);
+
+ dev_dbg(dev, "%s: OK\n", __func__);
+
+ return 0;
+
+err_probe:
+
+ dev_dbg(dev, "%s: returns %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int eqos_remove_resources_stm32(struct udevice *dev)
+{
+ dev_dbg(dev, "%s:\n", __func__);
+
+ return 0;
+}
+
+static struct eqos_ops eqos_stm32_ops = {
+ .eqos_inval_desc = eqos_inval_desc_generic,
+ .eqos_flush_desc = eqos_flush_desc_generic,
+ .eqos_inval_buffer = eqos_inval_buffer_generic,
+ .eqos_flush_buffer = eqos_flush_buffer_generic,
+ .eqos_probe_resources = eqos_probe_resources_stm32,
+ .eqos_remove_resources = eqos_remove_resources_stm32,
+ .eqos_stop_resets = eqos_null_ops,
+ .eqos_start_resets = eqos_null_ops,
+ .eqos_stop_clks = eqos_stop_clks_stm32,
+ .eqos_start_clks = eqos_start_clks_stm32,
+ .eqos_calibrate_pads = eqos_null_ops,
+ .eqos_disable_calibration = eqos_null_ops,
+ .eqos_set_tx_clk_speed = eqos_null_ops,
+ .eqos_get_enetaddr = eqos_null_ops,
+ .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32
+};
+
+struct eqos_config __maybe_unused eqos_stm32mp13_config = {
+ .reg_access_always_ok = false,
+ .mdio_wait = 10000,
+ .swr_wait = 50,
+ .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
+ .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
+ .axi_bus_width = EQOS_AXI_WIDTH_32,
+ .interface = dev_read_phy_mode,
+ .ops = &eqos_stm32_ops
+};
+
+struct eqos_config __maybe_unused eqos_stm32mp15_config = {
+ .reg_access_always_ok = false,
+ .mdio_wait = 10000,
+ .swr_wait = 50,
+ .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV,
+ .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
+ .axi_bus_width = EQOS_AXI_WIDTH_64,
+ .interface = dev_read_phy_mode,
+ .ops = &eqos_stm32_ops
+};