mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-09-21 12:11:49 +08:00
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.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
3873d0d107
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user