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.hershber...@ni.com> > Cc: Grygorii Strashko <grygorii.stras...@ti.com>; Neil Armstrong > <narmstr...@baylibre.com>; Mario Six <mario....@gdsys.cc>; Florian Fainelli > <f.faine...@gmail.com>; Priyanka Jain <priyanka.j...@nxp.com>; Ooi, Joyce > <joyce....@intel.com>; See, Chin Liang <chin.liang....@intel.com>; Ong, Hean > Loong <hean.loong....@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....@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot