Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions arch/arm64/boot/dts/allwinner/sun60i-a733-demo-aiot.dts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@
};
};

&gmac {
assigned-clocks = <&ccu CLK_GMAC0_PHY>;
assigned-clock-rates = <25000000>;
tx-internal-delay-ps = <1000>;
rx-internal-delay-ps = <2000>;
phy-mode = "rgmii";
phy-handle = <&rgmii_phy>;
status = "okay";
};

&mdio {
status = "okay";

rgmii_phy: phy@1 {
compatible = "ethernet-phy-id001c.c916",
"ethernet-phy-ieee802.3-c22";
reg = <1>;
assigned-clocks = <&ccu CLK_GMAC0_PHY>;
assigned-clock-rates = <25000000>;
clocks = <&ccu CLK_GMAC0_PHY>;
reset-gpios = <&pio 7 16 GPIO_ACTIVE_LOW>;
reset-assert-us = <10000>;
reset-deassert-us = <30000>;
};
};

&mmc0 {
/* Missing v(q)mmc-supply which is SWOUT2/CLDO3 of AXP318 */
bus-width = <4>;
Expand Down
60 changes: 60 additions & 0 deletions arch/arm64/boot/dts/allwinner/sun60i-a733.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,16 @@
interrupt-controller;
#interrupt-cells = <3>;

gmac_pins: gmac-pins {
pins = "PH0", "PH1", "PH2", "PH3", "PH4", "PH5",
"PH6", "PH7", "PH8", "PH9", "PH10",
"PH11", "PH12", "PH13", "PH14", "PH15";
function = "rgmii0";
allwinner,pinmux = <5>;
drive-strength = <20>;
bias-pull-up;
};

mmc0_pins: mmc0-pins {
pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
function = "sdc0";
Expand Down Expand Up @@ -319,6 +329,56 @@
#size-cells = <0>;
};

gmac: gmac@4500000 {
compatible = "allwinner,sun60i-a733-gmac210",
"snps,dwmac-5.20";
reg = <0x0 0x4500000 0x0 0x8000>,
<0x0 0x4508000 0x0 0x8000>;
clocks = <&ccu CLK_GMAC0>, <&ccu CLK_GMAC0_MBUS>, <&ccu CLK_GMAC0_PHY>;
clock-names = "stmmaceth", "mbus", "phy";
resets = <&ccu RST_BUS_GMAC0_AXI>, <&ccu RST_BUS_GMAC0>;
reset-names = "stmmaceth", "ahb";
interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq",
"tx0_irq",
"rx0_irq";
pinctrl-names = "default";
pinctrl-0 = <&gmac_pins>;
status = "disabled";

snps,fixed-burst;
snps,ent-tx-lpi-clockgating;
snps,axi-config = <&gmac_stmmac_axi_setup>;
snps,mtl-rx-config = <&gmac_mtl_rx_setup>;
snps,mtl-tx-config = <&gmac_mtl_tx_setup>;

mdio: mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};

gmac_stmmac_axi_setup: stmmac-axi-config {
snps,lpi_en;
snps,wr_osr_lmt = <0xf>;
snps,rd_osr_lmt = <0xf>;
snps,blen = <256 128 64 32 16 8 4>;
};

gmac_mtl_rx_setup: rx-queues-config {
snps,rx-queues-to-use = <1>;
queue0 {};
};

gmac_mtl_tx_setup: tx_queues-config {
snps,tx-queues-to-use = <1>;
queue0 {};
};
};

r_ccu: r_ccu@7010000 {
compatible = "allwinner,sun60iw2-r-ccu";
reg = <0x0 0x07010000 0x0 0x340>;
Expand Down
155 changes: 146 additions & 9 deletions drivers/net/ethernet/stmicro/stmmac/dwmac-sun55i.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
/* RMII specific bits */
#define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */
/* Generic system control EMAC_CLK bits */
#define SYSCON_ETXDC_H_MASK GENMASK(17, 16)
#define SYSCON_ETXDC_MASK GENMASK(12, 10)
#define SYSCON_ERXDC_MASK GENMASK(9, 5)
/* EMAC PHY Interface Type */
Expand All @@ -37,8 +38,20 @@
#define SYSCON_ETCS_EXT_GMII 0x1
#define SYSCON_ETCS_INT_GMII 0x2

#define SYSCON_ETXDC_FULL_MASK GENMASK(4, 0)

struct sun55i_priv_data {
void __iomem *glue;
u32 glue_setting;
};

typedef int (*gmac_plat_init)(struct device *dev,
struct plat_stmmacenet_data *plat,
struct stmmac_resources *res);

static int sun55i_gmac200_set_syscon(struct device *dev,
struct plat_stmmacenet_data *plat)
struct plat_stmmacenet_data *plat,
struct stmmac_resources *res)
{
struct device_node *node = dev->of_node;
struct regmap *regmap;
Expand All @@ -55,10 +68,10 @@ static int sun55i_gmac200_set_syscon(struct device *dev,
"tx-delay must be a multiple of 100ps\n");
val /= 100;
dev_dbg(dev, "set tx-delay to %x\n", val);
if (!FIELD_FIT(SYSCON_ETXDC_MASK, val))
if (!FIELD_FIT(SYSCON_ETXDC_FULL_MASK, val))
return dev_err_probe(dev, -EINVAL,
"TX clock delay exceeds maximum (%u00ps > %lu00ps)\n",
val, FIELD_MAX(SYSCON_ETXDC_MASK));
val, FIELD_MAX(SYSCON_ETXDC_FULL_MASK));

reg |= FIELD_PREP(SYSCON_ETXDC_MASK, val);
}
Expand Down Expand Up @@ -102,14 +115,125 @@ static int sun55i_gmac200_set_syscon(struct device *dev,
return 0;
}

static struct mac_device_info *sun60i_dwmac_setup(void *opriv)
{
struct stmmac_priv *stmmac_priv = opriv;
struct sun55i_priv_data *priv = stmmac_priv->plat->bsp_priv;

stmmac_priv->hw = devm_kzalloc(stmmac_priv->device,
sizeof(*stmmac_priv->hw), GFP_KERNEL);
if (!stmmac_priv->hw)
return NULL;

writel(priv->glue_setting, priv->glue);
udelay(100);

dwmac4_setup(stmmac_priv);

return stmmac_priv->hw;
}

static int sun60i_gmac210_plat_init(struct device *dev,
struct plat_stmmacenet_data *plat,
struct stmmac_resources *res)
{
struct platform_device *pdev = to_platform_device(dev);
struct sun55i_priv_data *priv = plat->bsp_priv;
struct device_node *node = dev->of_node;
u32 val, reg = 0;

priv->glue = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(priv->glue))
return dev_err_probe(dev, PTR_ERR(priv->glue),
"Unable to map glue region\n");

if (!of_property_read_u32(node, "tx-internal-delay-ps", &val)) {
if (val % 100)
return dev_err_probe(dev, -EINVAL,
"tx-delay must be a multiple of 100ps\n");
val /= 100;
dev_dbg(dev, "set tx-delay to %x\n", val);
if (!FIELD_FIT(SYSCON_ETXDC_FULL_MASK, val))
return dev_err_probe(dev, -EINVAL,
"TX clock delay exceeds maximum (%u00ps > %lu00ps)\n",
val, FIELD_MAX(SYSCON_ETXDC_MASK));

reg |= FIELD_PREP(SYSCON_ETXDC_MASK,
FIELD_GET(GENMASK(2, 0), val));
reg |= FIELD_PREP(SYSCON_ETXDC_H_MASK,
FIELD_GET(GENMASK(4, 3), val));
}

if (!of_property_read_u32(node, "rx-internal-delay-ps", &val)) {
if (val % 100)
return dev_err_probe(dev, -EINVAL,
"rx-delay must be a multiple of 100ps\n");
val /= 100;
dev_dbg(dev, "set rx-delay to %x\n", val);
if (!FIELD_FIT(SYSCON_ERXDC_MASK, val))
return dev_err_probe(dev, -EINVAL,
"RX clock delay exceeds maximum (%u00ps > %lu00ps)\n",
val, FIELD_MAX(SYSCON_ERXDC_MASK));

reg |= FIELD_PREP(SYSCON_ERXDC_MASK, val);
}

switch (plat->phy_interface) {
case PHY_INTERFACE_MODE_MII:
/* default */
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
/*
* It seems the "internal GMAC transmit clock" isn't correctly
* supplied, and we must rely on the external RGMII clock
* supplied through RGMII0-CLKIN. Why?
*/
reg |= SYSCON_EPIT | SYSCON_ETCS_EXT_GMII;
break;
case PHY_INTERFACE_MODE_RMII:
reg |= SYSCON_RMII_EN;
break;
default:
return dev_err_probe(dev, -EINVAL, "Unsupported interface mode: %s",
phy_modes(plat->phy_interface));
}

priv->glue_setting = reg;

res->tx_irq[0] = platform_get_irq_byname(pdev, "tx0_irq");
if (res->tx_irq[0] < 0)
return dev_err_probe(dev, res->tx_irq[0],
"Unable to request tx0_irq\n");

res->rx_irq[0] = platform_get_irq_byname(pdev, "rx0_irq");
if (res->rx_irq[0] < 0)
return dev_err_probe(dev, res->rx_irq[0],
"Unable to request rx0_irq\n");

plat->flags |= STMMAC_FLAG_MULTI_MSI_EN;
plat->setup = sun60i_dwmac_setup;

return 0;
}


static int sun55i_gmac200_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
struct stmmac_resources stmmac_res;
struct device *dev = &pdev->dev;
struct sun55i_priv_data *priv;
gmac_plat_init init;
struct clk *clk;
int ret;

priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

ret = stmmac_get_platform_resources(pdev, &stmmac_res);
if (ret)
return ret;
Expand All @@ -118,29 +242,42 @@ static int sun55i_gmac200_probe(struct platform_device *pdev)
if (IS_ERR(plat_dat))
return PTR_ERR(plat_dat);

plat_dat->bsp_priv = priv;

/* BSP disables it */
plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE;
plat_dat->host_dma_width = 32;

ret = sun55i_gmac200_set_syscon(dev, plat_dat);
clk = devm_clk_get_optional_enabled(dev, "mbus");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk),
"Failed to get or enable mbus clock\n");

init = of_device_get_match_data(dev);
ret = init(dev, plat_dat, &stmmac_res);
if (ret)
return ret;

clk = devm_clk_get_enabled(dev, "mbus");
clk = devm_clk_get_optional_enabled(dev, "phy");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk),
"Failed to get or enable MBUS clock\n");
"Failed to get or enable phy clock\n");

ret = devm_regulator_get_enable_optional(dev, "phy");
if (ret)
if (ret && ret != -ENODEV)
return dev_err_probe(dev, ret, "Failed to get or enable PHY supply\n");

return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
}

static const struct of_device_id sun55i_gmac200_match[] = {
{ .compatible = "allwinner,sun55i-a523-gmac200" },
{ }
{
.compatible = "allwinner,sun55i-a523-gmac200",
.data = sun55i_gmac200_set_syscon,
}, {
.compatible = "allwinner,sun60i-a733-gmac210",
.data = sun60i_gmac210_plat_init,
}, { }
};
MODULE_DEVICE_TABLE(of, sun55i_gmac200_match);

Expand Down