
Hi Joe,
Any comments/feedback on this v3 patch?
Thanks.
Regards, Joyce Ooi
-----Original Message----- From: Ooi, Joyce Sent: Friday, November 9, 2018 6:16 PM To: Joe Hershberger joe.hershberger@ni.com Cc: Grygorii Strashko grygorii.strashko@ti.com; Neil Armstrong narmstrong@baylibre.com; Mario Six mario.six@gdsys.cc; Florian Fainelli f.fainelli@gmail.com; Priyanka Jain priyanka.jain@nxp.com; Ooi, Joyce joyce.ooi@intel.com; See, Chin Liang chin.liang.see@intel.com; Ong, Hean Loong hean.loong.ong@intel.com; u-boot@lists.denx.de Subject: [PATCH v3] net: phy: add TSE PCS support to dwmac-socfpga
This adds support for TSE PCS (Triple Speed Ethernet Physical Coding Sublayer) that uses SGMII adapter when the phy-mode in device tree is set to sgmii.
Signed-off-by: Ooi, Joyce joyce.ooi@intel.com
arch/arm/mach-socfpga/include/mach/misc.h | 3 + arch/arm/mach-socfpga/misc_s10.c | 6 + drivers/net/Makefile | 3 +- drivers/net/designware.c | 5 + drivers/net/designware.h | 1 + drivers/net/dwmac_socfpga.c | 122 +++++++++++++++++++ drivers/net/phy/altr_tse_pcs.c | 184 +++++++++++++++++++++++++++++ drivers/net/phy/altr_tse_pcs.h | 56 +++++++++ 8 files changed, 379 insertions(+), 1 deletions(-) create mode 100644 drivers/net/phy/altr_tse_pcs.c create mode 100644 drivers/net/phy/altr_tse_pcs.h
v2: add a __weak function to make it compatible for all socfpga platforms v3: remove __weak function and use board-specific implementation instead
diff --git a/arch/arm/mach-socfpga/include/mach/misc.h b/arch/arm/mach- socfpga/include/mach/misc.h index 4fc9570..751705e 100644 --- a/arch/arm/mach-socfpga/include/mach/misc.h +++ b/arch/arm/mach-socfpga/include/mach/misc.h @@ -30,6 +30,9 @@ void socfpga_init_security_policies(void); void socfpga_sdram_remap_zero(void); #endif
+#ifdef CONFIG_TARGET_SOCFPGA_STRATIX10 +int socfpga_test_fpga_ready(void); +#endif void do_bridge_reset(int enable);
#endif /* _MISC_H_ */ diff --git a/arch/arm/mach-socfpga/misc_s10.c b/arch/arm/mach- socfpga/misc_s10.c index e599362..3cd9c30 100644 --- a/arch/arm/mach-socfpga/misc_s10.c +++ b/arch/arm/mach-socfpga/misc_s10.c @@ -11,6 +11,7 @@ #include <miiphy.h> #include <netdev.h> #include <asm/io.h> +#include <asm/arch/mailbox_s10.h> #include <asm/arch/reset_manager.h> #include <asm/arch/system_manager.h> #include <asm/arch/misc.h> @@ -91,6 +92,11 @@ static int socfpga_set_phymode(void)
return 0; }
+int socfpga_test_fpga_ready(void) +{
- return mbox_get_fpga_config_status(MBOX_CONFIG_STATUS);
+} #else static int socfpga_set_phymode(void) { diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 48a2878..c2333b5 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -14,7 +14,7 @@ obj-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o obj-$(CONFIG_CS8900) += cs8900.o obj-$(CONFIG_TULIP) += dc2114x.o obj-$(CONFIG_ETH_DESIGNWARE) += designware.o -obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o +obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac-socfpga.o obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o obj-$(CONFIG_DNET) += dnet.o obj-$(CONFIG_E1000) += e1000.o @@ -73,3 +73,4 @@ obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_FSL_PFE) += pfe_eth/ obj-$(CONFIG_SNI_AVE) += sni_ave.o +dwmac-socfpga-objs := phy/altr_tse_pcs.o dwmac_socfpga.o diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 19db0a8..666cf41 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -235,6 +235,8 @@ static int dw_adjust_link(struct dw_eth_dev *priv, struct eth_mac_regs *mac_p, struct phy_device *phydev) { u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN;
struct udevice *dev = priv->phydev->dev;
struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev);
if (!phydev->link) { printf("%s: No link.\n", phydev->dev->name); @@ -254,6
+256,9 @@ static int dw_adjust_link(struct dw_eth_dev *priv, struct eth_mac_regs *mac_p,
writel(conf, &mac_p->conf);
- if (dw_pdata->pcs_adjust_link)
dw_pdata->pcs_adjust_link(dev, phydev);
- printf("Speed: %d, %s duplex%s\n", phydev->speed, (phydev->duplex) ? "full" : "half", (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); diff --git
a/drivers/net/designware.h b/drivers/net/designware.h index dea12b7..3a5a93f 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -255,6 +255,7 @@ extern const struct eth_ops designware_eth_ops; struct dw_eth_pdata { struct eth_pdata eth_pdata; u32 reset_delays[3];
- void (*pcs_adjust_link)(struct udevice *dev, struct phy_device
+*phydev); };
int designware_eth_init(struct dw_eth_dev *priv, u8 *enetaddr); diff --git a/drivers/net/dwmac_socfpga.c b/drivers/net/dwmac_socfpga.c index 08fc967..7d13f3c 100644 --- a/drivers/net/dwmac_socfpga.c +++ b/drivers/net/dwmac_socfpga.c @@ -9,12 +9,16 @@ #include <asm/io.h> #include <dm.h> #include <clk.h> +#include <fdt_support.h> #include <phy.h> #include <regmap.h> #include <reset.h> #include <syscon.h> #include "designware.h" +#include "phy/altr_tse_pcs.h"
+#include <asm/arch/misc.h> +#include <asm/arch/reset_manager.h> #include <asm/arch/system_manager.h>
enum dwmac_type { @@ -27,8 +31,123 @@ struct dwmac_socfpga_platdata { struct dw_eth_pdata dw_eth_pdata; enum dwmac_type type; void *phy_intf;
- struct tse_pcs pcs;
};
+static void socfpga_tse_pcs_adjust_link(struct udevice *dev,
struct phy_device *phydev)
+{
- struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev);
- phys_addr_t tse_pcs_base = pdata->pcs.tse_pcs_base;
- phys_addr_t sgmii_adapter_base = pdata->pcs.sgmii_adapter_base;
- if ((tse_pcs_base) && (sgmii_adapter_base))
writew(SGMII_ADAPTER_DISABLE,
sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
- if ((tse_pcs_base) && (sgmii_adapter_base))
tse_pcs_fix_mac_speed(&pdata->pcs, phydev, phydev->speed);
}
+static int socfpga_dw_tse_pcs_init(struct udevice *dev) {
- struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev);
- struct dw_eth_pdata *dw_pdata = &pdata->dw_eth_pdata;
- struct eth_pdata *eth_pdata = &pdata->dw_eth_pdata.eth_pdata;
- phys_addr_t tse_pcs_base = pdata->pcs.tse_pcs_base;
- phys_addr_t sgmii_adapter_base = pdata->pcs.sgmii_adapter_base;
- const fdt32_t *reg;
- int ret = 0;
- int parent, index, na, ns, offset, len;
- offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev),
"altr,gmii-to-sgmii-converter");
- if (offset > 0) {
+#ifdef CONFIG_TARGET_SOCFPGA_STRATIX10
/* check FPGA status */
ret = socfpga_test_fpga_ready();
if (ret) {
debug("%s: FPGA not ready (%d)\n", __func__, ret);
return -EPERM;
}
+#endif
/* enable HPS bridge */
do_bridge_reset(1);
parent = fdt_parent_offset(gd->fdt_blob, offset);
if (parent < 0) {
debug("s10-hps-bridge DT not found\n");
return -ENODEV;
}
na = fdt_address_cells(gd->fdt_blob, parent);
if (na < 1) {
debug("bad #address-cells\n");
return -EINVAL;
}
ns = fdt_size_cells(gd->fdt_blob, parent);
if (ns < 1) {
debug("bad #size-cells\n");
return -EINVAL;
}
index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names",
"eth_tse_control_port");
if (index < 0) {
debug("fail to find eth_tse_control_port: %s\n",
fdt_strerror(index));
return -ENOENT;
}
reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
return -EINVAL;
reg += index * (na + ns);
tse_pcs_base = fdt_translate_address((void *)gd->fdt_blob,
offset, reg);
if (tse_pcs_base == FDT_ADDR_T_NONE) {
debug("tse pcs address not found\n");
return -EINVAL;
}
index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names",
"gmii_to_sgmii_adapter_avalon_slave");
if (index < 0) {
debug("fail to find
gmii_to_sgmii_adapter_avalon_slave: %s\n",
fdt_strerror(index));
return -EINVAL;
}
reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
return -EINVAL;
reg += index * (na + ns);
sgmii_adapter_base = fdt_translate_address((void *)gd-
fdt_blob,
offset, reg);
if (sgmii_adapter_base == FDT_ADDR_T_NONE) {
debug("gmii-to-sgmii adapter address not found\n");
return -EINVAL;
}
if (eth_pdata->phy_interface ==
PHY_INTERFACE_MODE_SGMII) {
if (tse_pcs_init(tse_pcs_base, &pdata->pcs) != 0) {
debug("Unable to intiialize TSE PCS\n");
return -EINVAL;
}
}
/* Clear sgmii_adapter_base first */
writel(0, sgmii_adapter_base);
pdata->pcs.tse_pcs_base = tse_pcs_base;
pdata->pcs.sgmii_adapter_base = sgmii_adapter_base;
dw_pdata->pcs_adjust_link = socfpga_tse_pcs_adjust_link;
- }
- return ret;
+}
static int dwmac_socfpga_ofdata_to_platdata(struct udevice *dev) { struct dwmac_socfpga_platdata *pdata = dev_get_platdata(dev); @@ - 94,6 +213,7 @@ static int dwmac_socfpga_probe(struct udevice *dev) switch (edata->phy_interface) { case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_GMII:
case PHY_INTERFACE_MODE_SGMII: modereg =
SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; break; case PHY_INTERFACE_MODE_RMII: @@ -122,6 +242,8 @@ static int dwmac_socfpga_probe(struct udevice *dev) reset_release_bulk(&reset_bulk); }
- socfpga_dw_tse_pcs_init(dev);
- return designware_eth_probe(dev);
}
diff --git a/drivers/net/phy/altr_tse_pcs.c b/drivers/net/phy/altr_tse_pcs.c new file mode 100644 index 0000000..4423538 --- /dev/null +++ b/drivers/net/phy/altr_tse_pcs.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2018 Intel Corporation <www.intel.com> */
+#include <asm/io.h> +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <net.h> +#include <linux/compat.h> +#include <phy.h> +#include <timer.h> +#include <wait_bit.h> +#include <linux/ethtool.h>
+#include <asm/omap_common.h> +#include <asm/omap_musb.h>
+#include "altr_tse_pcs.h"
+static int tse_pcs_reset(phys_addr_t base, struct tse_pcs *pcs) {
- int ret;
- u16 val;
- phys_addr_t reg = base + TSE_PCS_CONTROL_REG;
- val = readw(reg);
- val |= TSE_PCS_SW_RST_MASK;
- writew(val, reg);
- ret = wait_for_bit_le16(®, TSE_PCS_SW_RST_MASK, false,
TSE_PCS_SW_RESET_TIMEOUT, false);
- if (ret) {
debug("%s: PCS could not get out of sw reset\n", __func__);
return -ETIMEDOUT;
- }
- return 0;
+}
+int tse_pcs_init(phys_addr_t base, struct tse_pcs *pcs) {
- int ret = 0;
- writew(TSE_PCS_USE_SGMII_ENA, base + TSE_PCS_IF_MODE_REG);
- writew(TSE_PCS_SGMII_LINK_TIMER_0, base +
TSE_PCS_LINK_TIMER_0_REG);
- writew(TSE_PCS_SGMII_LINK_TIMER_1, base +
TSE_PCS_LINK_TIMER_1_REG);
- ret = tse_pcs_reset(base, pcs);
- if (ret == 0)
writew(SGMII_ADAPTER_ENABLE,
pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
- return ret;
+}
+static void pcs_link_timer_callback(struct tse_pcs *pcs) {
- u16 val = 0;
- phys_addr_t tse_pcs_base = pcs->tse_pcs_base;
- phys_addr_t sgmii_adapter_base = pcs->sgmii_adapter_base;
- val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
- val &= TSE_PCS_STATUS_LINK_MASK;
- if (val != 0) {
printf("Adapter: Link is established\n");
writew(SGMII_ADAPTER_ENABLE,
sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
- } else {
printf("Adapter: Link fail to establish\n");
- }
+}
+static void auto_nego_timer_callback(struct tse_pcs *pcs) {
- u16 val = 0;
- u16 speed = 0;
- u16 duplex = 0;
- phys_addr_t tse_pcs_base = pcs->tse_pcs_base;
- phys_addr_t sgmii_adapter_base = pcs->sgmii_adapter_base;
- val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
- val &= TSE_PCS_STATUS_AN_COMPLETED_MASK;
- if (val != 0) {
printf("Adapter: Auto Negotiation is completed\n");
val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG);
speed = val & TSE_PCS_PARTNER_SPEED_MASK;
duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK;
if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL) {
if (speed == TSE_PCS_PARTNER_SPEED_10)
printf("Adapter: Link Partner is Up - 10/Full\n");
else if (speed == TSE_PCS_PARTNER_SPEED_100)
printf("Adapter: Link Partner is Up -
100/Full\n");
else if (speed == TSE_PCS_PARTNER_SPEED_1000)
printf("Adapter: Link Partner is Up -
1000/Full\n");
} else if (duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
printf("Adapter does not support Half Duplex\n");
else
printf("Adapter: Invalid Partner Speed and Duplex\n");
if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL &&
(speed == TSE_PCS_PARTNER_SPEED_10 ||
speed == TSE_PCS_PARTNER_SPEED_100 ||
speed == TSE_PCS_PARTNER_SPEED_1000))
writew(SGMII_ADAPTER_ENABLE,
sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
- } else {
printf("Auto-negotioation failed\n");
- }
+}
+void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
unsigned int speed)
+{
- phys_addr_t tse_pcs_base = pcs->tse_pcs_base;
- phys_addr_t sgmii_adapter_base = pcs->sgmii_adapter_base;
- u32 val, start;
- writew(SGMII_ADAPTER_ENABLE,
sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
- pcs->autoneg = phy_dev->autoneg;
- if (pcs->autoneg == AUTONEG_ENABLE) {
val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
val |= TSE_PCS_CONTROL_AN_EN_MASK;
writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
val |= TSE_PCS_USE_SGMII_AN_MASK;
writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
tse_pcs_reset(tse_pcs_base, pcs);
- } else if (pcs->autoneg == AUTONEG_DISABLE) {
val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
val &= ~TSE_PCS_CONTROL_AN_EN_MASK;
writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
val &= ~TSE_PCS_USE_SGMII_AN_MASK;
writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
val &= ~TSE_PCS_SGMII_SPEED_MASK;
switch (speed) {
case 1000:
val |= TSE_PCS_SGMII_SPEED_1000;
break;
case 100:
val |= TSE_PCS_SGMII_SPEED_100;
break;
case 10:
val |= TSE_PCS_SGMII_SPEED_10;
break;
default:
return;
}
writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
tse_pcs_reset(tse_pcs_base, pcs);
- }
- start = get_timer(0);
- while (1) {
if (get_timer(start) >= AUTONEGO_LINK_TIMER) {
if (pcs->autoneg == AUTONEG_ENABLE)
auto_nego_timer_callback(pcs);
else if (pcs->autoneg == AUTONEG_DISABLE)
pcs_link_timer_callback(pcs);
return;
}
udelay(100);
- }
+} diff --git a/drivers/net/phy/altr_tse_pcs.h b/drivers/net/phy/altr_tse_pcs.h new file mode 100644 index 0000000..0e8d4f4 --- /dev/null +++ b/drivers/net/phy/altr_tse_pcs.h @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2018 Intel Corporation <www.intel.com> */
+#ifndef __TSE_PCS_H__ +#define __TSE_PCS_H__
+#define TSE_PCS_CONTROL_AN_EN_MASK BIT(12) +#define TSE_PCS_CONTROL_REG 0x00 +#define TSE_PCS_CONTROL_RESTART_AN_MASK BIT(9) +#define TSE_PCS_IF_MODE_REG 0x28 +#define TSE_PCS_LINK_TIMER_0_REG 0x24 +#define TSE_PCS_LINK_TIMER_1_REG 0x26 +#define TSE_PCS_SIZE 0x40 +#define TSE_PCS_STATUS_AN_COMPLETED_MASK BIT(5) +#define TSE_PCS_STATUS_LINK_MASK BIT(2) +#define TSE_PCS_STATUS_REG 0x02 +#define TSE_PCS_SGMII_SPEED_1000 BIT(3) +#define TSE_PCS_SGMII_SPEED_100 BIT(2) +#define TSE_PCS_SGMII_SPEED_10 0x0 +#define TSE_PCS_SGMII_SPEED_MASK GENMASK(3, 2) +#define TSE_PCS_SW_RST_MASK BIT(15) +#define TSE_PCS_PARTNER_ABILITY_REG 0x0A +#define TSE_PCS_PARTNER_DUPLEX_FULL BIT(12) +#define TSE_PCS_PARTNER_DUPLEX_HALF 0x0000 +#define TSE_PCS_PARTNER_DUPLEX_MASK BIT(12) +#define TSE_PCS_PARTNER_SPEED_MASK GENMASK(11, 10) +#define TSE_PCS_PARTNER_SPEED_1000 BIT(11) +#define TSE_PCS_PARTNER_SPEED_100 BIT(10) +#define TSE_PCS_PARTNER_SPEED_10 0x0000 +#define TSE_PCS_SGMII_LINK_TIMER_0 0x0D40 +#define TSE_PCS_SGMII_LINK_TIMER_1 0x0003 +#define TSE_PCS_SW_RESET_TIMEOUT 100 +#define TSE_PCS_USE_SGMII_AN_MASK BIT(1) +#define TSE_PCS_USE_SGMII_ENA BIT(0)
+#define SGMII_ADAPTER_CTRL_REG 0x00 +#define SGMII_ADAPTER_DISABLE 0x0001 +#define SGMII_ADAPTER_ENABLE 0x0000
+#define AUTONEGO_LINK_TIMER 20
+struct tse_pcs {
- struct device *dev;
- phys_addr_t tse_pcs_base;
- phys_addr_t sgmii_adapter_base;
- struct timer_list aneg_link_timer;
- int autoneg;
+};
+int tse_pcs_init(phys_addr_t base, struct tse_pcs *pcs); void +tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
unsigned int speed);
+#endif /* __TSE_PCS_H__ */
1.7.1