Commit 3873d0d1 authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'series-to-deliver-ethernet-for-stm32mp13'

Christophe Roullier says:

====================
Series to deliver Ethernet for STM32MP13

STM32MP13 is STM32 SOC with 2 GMACs instances
    GMAC IP version is SNPS 4.20.
    GMAC IP configure with 1 RX and 1 TX queue.
    DMA HW capability register supported
    RX Checksum Offload Engine supported
    TX Checksum insertion supported
    Wake-Up On Lan supported
    TSO supported
Rework dwmac glue to simplify management for next stm32 (integrate RFC from Marek)

V2: - Remark from Rob Herring (add Krzysztof's ack in patch 02/11, update in yaml)
      Remark from Serge Semin (upate commits msg)
V3: - Remove PHY regulator patch and Ethernet2 DT because need to clarify how to
      manage PHY regulator (in glue or PHY side)
    - Integrate RFC from Marek
    - Remark from Rob Herring in YAML documentation
V4: - Remark from Marek (remove max-speed, extra space in DT, update commit msg)
    - Remark from Rasmus (add sign-off, add base-commit)
    - Remark from Sai Krishna Gajula
V5: - Fix warning during build CHECK_DTBS
    - Remark from Marek (glue + DT update)
    - Remark from Krzysztof about YAML (Make it symmetric)
V6: - Replace pr_debug by dev_dbg
    - Split serie driver/DTs separately
V7: - Remark from Marek (update sysconfig register mask)
====================

Link: https://lore.kernel.org/r/20240611083606.733453-1-christophe.roullier@foss.st.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 5f703ce5 50bbc039
......@@ -22,18 +22,17 @@ select:
enum:
- st,stm32-dwmac
- st,stm32mp1-dwmac
- st,stm32mp13-dwmac
required:
- compatible
allOf:
- $ref: snps,dwmac.yaml#
properties:
compatible:
oneOf:
- items:
- enum:
- st,stm32mp1-dwmac
- st,stm32mp13-dwmac
- const: snps,dwmac-4.20a
- items:
- enum:
......@@ -75,12 +74,15 @@ properties:
st,syscon:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- minItems: 2
items:
- description: phandle to the syscon node which encompases the glue register
- description: offset of the control register
- description: field to set mask in register
description:
Should be phandle/offset pair. The phandle to the syscon node which
encompases the glue register, and the offset of the control register
encompases the glue register, the offset of the control register and
the mask to set bitfield in control register
st,ext-phyclk:
description:
......@@ -112,12 +114,39 @@ required:
unevaluatedProperties: false
allOf:
- $ref: snps,dwmac.yaml#
- if:
properties:
compatible:
contains:
enum:
- st,stm32mp1-dwmac
- st,stm32-dwmac
then:
properties:
st,syscon:
items:
minItems: 2
maxItems: 2
- if:
properties:
compatible:
contains:
enum:
- st,stm32mp13-dwmac
then:
properties:
st,syscon:
items:
minItems: 3
maxItems: 3
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <dt-bindings/reset/stm32mp1-resets.h>
#include <dt-bindings/mfd/stm32h7-rcc.h>
//Example 1
ethernet0: ethernet@5800a000 {
compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";
......
......@@ -58,7 +58,7 @@
* Below table summarizes the clock requirement and clock sources for
* supported phy interface modes.
* __________________________________________________________________________
*|PHY_MODE | Normal | PHY wo crystal| PHY wo crystal |No 125Mhz from PHY|
*|PHY_MODE | Normal | PHY wo crystal| PHY wo crystal |No 125MHz from PHY|
*| | | 25MHz | 50MHz | |
* ---------------------------------------------------------------------------
*| MII | - | eth-ck | n/a | n/a |
......@@ -90,6 +90,7 @@ struct stm32_dwmac {
int eth_ref_clk_sel_reg;
int irq_pwr_wakeup;
u32 mode_reg; /* MAC glue-logic mode register */
u32 mode_mask;
struct regmap *regmap;
u32 speed;
const struct stm32_ops *ops;
......@@ -102,8 +103,9 @@ struct stm32_ops {
void (*resume)(struct stm32_dwmac *dwmac);
int (*parse_data)(struct stm32_dwmac *dwmac,
struct device *dev);
u32 syscfg_eth_mask;
bool clk_rx_enable_in_suspend;
bool is_mp13;
u32 syscfg_clr_off;
};
static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac, bool resume)
......@@ -157,65 +159,137 @@ static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat, bool resume)
return stm32_dwmac_clk_enable(dwmac, resume);
}
static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
static int stm32mp1_select_ethck_external(struct plat_stmmacenet_data *plat_dat)
{
struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
u32 reg = dwmac->mode_reg, clk_rate;
int val;
clk_rate = clk_get_rate(dwmac->clk_eth_ck);
dwmac->enable_eth_ck = false;
switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
if (clk_rate == ETH_CK_F_25M && dwmac->ext_phyclk)
dwmac->enable_eth_ck = true;
val = SYSCFG_PMCR_ETH_SEL_MII;
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
dwmac->enable_eth_ck = dwmac->ext_phyclk;
return 0;
case PHY_INTERFACE_MODE_GMII:
dwmac->enable_eth_ck = dwmac->eth_clk_sel_reg ||
dwmac->ext_phyclk;
return 0;
case PHY_INTERFACE_MODE_RMII:
dwmac->enable_eth_ck = dwmac->eth_ref_clk_sel_reg ||
dwmac->ext_phyclk;
return 0;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
dwmac->enable_eth_ck = dwmac->eth_clk_sel_reg ||
dwmac->ext_phyclk;
return 0;
default:
dwmac->enable_eth_ck = false;
dev_err(dwmac->dev, "Mode %s not supported",
phy_modes(plat_dat->mac_interface));
return -EINVAL;
}
}
static int stm32mp1_validate_ethck_rate(struct plat_stmmacenet_data *plat_dat)
{
struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
const u32 clk_rate = clk_get_rate(dwmac->clk_eth_ck);
switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_GMII:
if (clk_rate == ETH_CK_F_25M)
return 0;
break;
case PHY_INTERFACE_MODE_RMII:
if (clk_rate == ETH_CK_F_25M || clk_rate == ETH_CK_F_50M)
return 0;
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
if (clk_rate == ETH_CK_F_25M || clk_rate == ETH_CK_F_125M)
return 0;
break;
default:
break;
}
dev_err(dwmac->dev, "Mode %s does not match eth-ck frequency %d Hz",
phy_modes(plat_dat->mac_interface), clk_rate);
return -EINVAL;
}
static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat)
{
struct stm32_dwmac *dwmac = plat_dat->bsp_priv;
u32 reg = dwmac->mode_reg;
int val = 0;
switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_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 (!dwmac->ops->is_mp13) /* Select MII mode on STM32MP15xx */
val |= SYSCFG_PMCR_ETH_SEL_MII;
break;
case PHY_INTERFACE_MODE_GMII:
val = SYSCFG_PMCR_ETH_SEL_GMII;
if (clk_rate == ETH_CK_F_25M &&
(dwmac->eth_clk_sel_reg || dwmac->ext_phyclk)) {
dwmac->enable_eth_ck = true;
if (dwmac->enable_eth_ck)
val |= SYSCFG_PMCR_ETH_CLK_SEL;
}
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_GMII\n");
break;
case PHY_INTERFACE_MODE_RMII:
val = SYSCFG_PMCR_ETH_SEL_RMII;
if ((clk_rate == ETH_CK_F_25M || clk_rate == ETH_CK_F_50M) &&
(dwmac->eth_ref_clk_sel_reg || dwmac->ext_phyclk)) {
dwmac->enable_eth_ck = true;
if (dwmac->enable_eth_ck)
val |= SYSCFG_PMCR_ETH_REF_CLK_SEL;
}
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
val = SYSCFG_PMCR_ETH_SEL_RGMII;
if ((clk_rate == ETH_CK_F_25M || clk_rate == ETH_CK_F_125M) &&
(dwmac->eth_clk_sel_reg || dwmac->ext_phyclk)) {
dwmac->enable_eth_ck = true;
if (dwmac->enable_eth_ck)
val |= SYSCFG_PMCR_ETH_CLK_SEL;
}
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n");
break;
default:
pr_debug("SYSCFG init : Do not manage %d interface\n",
plat_dat->mac_interface);
dev_err(dwmac->dev, "Mode %s not supported",
phy_modes(plat_dat->mac_interface));
/* Do not manage others interfaces */
return -EINVAL;
}
dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->mac_interface));
/* Shift value at correct ethernet MAC offset in SYSCFG_PMCSETR */
val <<= ffs(dwmac->mode_mask) - ffs(SYSCFG_MP1_ETH_MASK);
/* Need to update PMCCLRR (clear register) */
regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET,
dwmac->ops->syscfg_eth_mask);
regmap_write(dwmac->regmap, dwmac->ops->syscfg_clr_off,
dwmac->mode_mask);
/* Update PMCSETR (set register) */
return regmap_update_bits(dwmac->regmap, reg,
dwmac->ops->syscfg_eth_mask, val);
dwmac->mode_mask, val);
}
static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat)
{
int ret;
ret = stm32mp1_select_ethck_external(plat_dat);
if (ret)
return ret;
ret = stm32mp1_validate_ethck_rate(plat_dat);
if (ret)
return ret;
return stm32mp1_configure_pmcr(plat_dat);
}
static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat)
......@@ -227,21 +301,21 @@ static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat)
switch (plat_dat->mac_interface) {
case PHY_INTERFACE_MODE_MII:
val = SYSCFG_MCU_ETH_SEL_MII;
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
break;
case PHY_INTERFACE_MODE_RMII:
val = SYSCFG_MCU_ETH_SEL_RMII;
pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
break;
default:
pr_debug("SYSCFG init : Do not manage %d interface\n",
plat_dat->mac_interface);
dev_err(dwmac->dev, "Mode %s not supported",
phy_modes(plat_dat->mac_interface));
/* Do not manage others interfaces */
return -EINVAL;
}
dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->mac_interface));
return regmap_update_bits(dwmac->regmap, reg,
dwmac->ops->syscfg_eth_mask, val << 23);
SYSCFG_MCU_ETH_MASK, val << 23);
}
static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac, bool suspend)
......@@ -286,8 +360,19 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac,
return PTR_ERR(dwmac->regmap);
err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->mode_reg);
if (err)
if (err) {
dev_err(dev, "Can't get sysconfig mode offset (%d)\n", err);
return err;
}
dwmac->mode_mask = SYSCFG_MP1_ETH_MASK;
err = of_property_read_u32_index(np, "st,syscon", 2, &dwmac->mode_mask);
if (err) {
if (dwmac->ops->is_mp13)
dev_err(dev, "Sysconfig register mask must be set (%d)\n", err);
else
dev_dbg(dev, "Warning sysconfig register mask not set\n");
}
return err;
}
......@@ -305,7 +390,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac,
/* Gigabit Ethernet 125MHz clock selection. */
dwmac->eth_clk_sel_reg = of_property_read_bool(np, "st,eth-clk-sel");
/* Ethernet 50Mhz RMII clock selection */
/* Ethernet 50MHz RMII clock selection */
dwmac->eth_ref_clk_sel_reg =
of_property_read_bool(np, "st,eth-ref-clk-sel");
......@@ -478,8 +563,7 @@ static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops,
stm32_dwmac_suspend, stm32_dwmac_resume);
static struct stm32_ops stm32mcu_dwmac_data = {
.set_mode = stm32mcu_set_mode,
.syscfg_eth_mask = SYSCFG_MCU_ETH_MASK
.set_mode = stm32mcu_set_mode
};
static struct stm32_ops stm32mp1_dwmac_data = {
......@@ -487,13 +571,25 @@ static struct stm32_ops stm32mp1_dwmac_data = {
.suspend = stm32mp1_suspend,
.resume = stm32mp1_resume,
.parse_data = stm32mp1_parse_data,
.syscfg_eth_mask = SYSCFG_MP1_ETH_MASK,
.syscfg_clr_off = 0x44,
.is_mp13 = false,
.clk_rx_enable_in_suspend = true
};
static struct stm32_ops stm32mp13_dwmac_data = {
.set_mode = stm32mp1_set_mode,
.suspend = stm32mp1_suspend,
.resume = stm32mp1_resume,
.parse_data = stm32mp1_parse_data,
.syscfg_clr_off = 0x08,
.is_mp13 = true,
.clk_rx_enable_in_suspend = true
};
static const struct of_device_id stm32_dwmac_match[] = {
{ .compatible = "st,stm32-dwmac", .data = &stm32mcu_dwmac_data},
{ .compatible = "st,stm32mp1-dwmac", .data = &stm32mp1_dwmac_data},
{ .compatible = "st,stm32mp13-dwmac", .data = &stm32mp13_dwmac_data},
{ }
};
MODULE_DEVICE_TABLE(of, stm32_dwmac_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment