Message ID | 1465236962-12131-2-git-send-email-isubramanian@apm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 06/06/16 20:15, Iyappan Subramanian wrote: > This patch fixes MAC configuration to support 10/100GbE for SGMII and > link_state call back. It also sets pdata->mdio_driver flag based on > ethernet mdio subnode and prepare for MDIO driver support. > > In summary, following are the changes, > > - Added set_speed function pointer in mac_ops This can be a seperate patch, or would it break the driver? In the end, the decision how to split up the patches is up to Dave. I prefer to have more small patches which do incrementally add new stuff to the driver, taking into account that every single patch does not break it. > - Changed link_state to call the set_speed > - Add 10/100 support for SGMII based 1G > - Fixed mac_init for 1G > > - Call mac_ops rx_enable/disable and tx_enable/disable function pointers For me, this is a seperate patch which does a cleanup of the driver. You just use the mac_ops for these function (enable/disable and init) and in a second patch you add the set_speed and delete the init call. > - Add acpi_phy_find_device to find PHY using phy-handle reference object > - Changing phy_start and phy_stop calls based on phy_dev object existence > - Calling phy_connect based on pdata->mdio_driver flag > > Signed-off-by: Iyappan Subramanian <isubramanian@apm.com> > Tested-by: Fushen Chen <fchen@apm.com> > Tested-by: Toan Le <toanle@apm.com> > Tested-by: Matthias Brugger <mbrugger@suse.com> > --- > drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 190 +++++++++++++--------- > drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 5 + > drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 41 +++-- > drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 2 + > drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 106 +++++++++++- > drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h | 8 + > drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 4 + > 7 files changed, 259 insertions(+), 97 deletions(-) > > diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c > index 2f5638f..5d6d14b 100644 > --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c > +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c > @@ -512,14 +512,11 @@ static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata) > #endif > } > > -static void xgene_gmac_init(struct xgene_enet_pdata *pdata) > +static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) > { > struct device *dev = &pdata->pdev->dev; > - u32 value, mc2; > - u32 intf_ctl, rgmii; > - u32 icm0, icm2; > - > - xgene_gmac_reset(pdata); > + u32 icm0, icm2, mc2; > + u32 intf_ctl, rgmii, value; > > xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); > xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); > @@ -564,7 +561,18 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) > mc2 |= FULL_DUPLEX2 | PAD_CRC; > xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); > xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); > + xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); > + xgene_enet_configure_clock(pdata); > + > + xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); > + xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); > +} > > +static void xgene_gmac_init(struct xgene_enet_pdata *pdata) > +{ > + u32 value; > + > + xgene_gmac_set_speed(pdata); > xgene_gmac_set_mac_addr(pdata); > > /* Adjust MDC clock frequency */ > @@ -579,15 +587,10 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) > > /* Rtype should be copied from FP */ > xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0); > - xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); > - xgene_enet_configure_clock(pdata); > > /* Rx-Tx traffic resume */ > xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); > > - xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); > - xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); > - Is this the part you refer to with "Fixed mac_init for 1G"? What does it fix? Does this fix something which might be worth getting backported to older kernel versions? > xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value); > value &= ~TX_DV_GATE_EN0; > value &= ~RX_DV_GATE_EN0; > @@ -671,25 +674,12 @@ bool xgene_ring_mgr_init(struct xgene_enet_pdata *p) > > static int xgene_enet_reset(struct xgene_enet_pdata *pdata) > { > - u32 val; > - > if (!xgene_ring_mgr_init(pdata)) > return -ENODEV; > > - if (!IS_ERR(pdata->clk)) { > - clk_prepare_enable(pdata->clk); > - clk_disable_unprepare(pdata->clk); > - clk_prepare_enable(pdata->clk); > - xgene_enet_ecc_init(pdata); > - } > + xgene_enet_ecc_init(pdata); > xgene_enet_config_ring_if_assoc(pdata); > > - /* Enable auto-incr for scanning */ > - xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val); > - val |= SCAN_AUTO_INCR; > - MGMT_CLOCK_SEL_SET(&val, 1); > - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); > - > return 0; > } > > @@ -724,29 +714,49 @@ static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, > static void xgene_enet_adjust_link(struct net_device *ndev) > { > struct xgene_enet_pdata *pdata = netdev_priv(ndev); > + const struct xgene_mac_ops *mac_ops = pdata->mac_ops; > struct phy_device *phydev = pdata->phy_dev; > > if (phydev->link) { > if (pdata->phy_speed != phydev->speed) { > pdata->phy_speed = phydev->speed; > - xgene_gmac_init(pdata); > - xgene_gmac_rx_enable(pdata); > - xgene_gmac_tx_enable(pdata); > + mac_ops->set_speed(pdata); > + mac_ops->rx_enable(pdata); > + mac_ops->tx_enable(pdata); > phy_print_status(phydev); > } > } else { > - xgene_gmac_rx_disable(pdata); > - xgene_gmac_tx_disable(pdata); > + mac_ops->rx_disable(pdata); > + mac_ops->tx_disable(pdata); > pdata->phy_speed = SPEED_UNKNOWN; > phy_print_status(phydev); > } > } > > -static int xgene_enet_phy_connect(struct net_device *ndev) > +#ifdef CONFIG_ACPI > +static struct acpi_device *acpi_phy_find_device(struct device *dev) > +{ > + struct acpi_reference_args args; > + struct fwnode_handle *fw_node; > + int status; > + > + fw_node = acpi_fwnode_handle(ACPI_COMPANION(dev)); > + status = acpi_node_get_property_reference(fw_node, "phy-handle", 0, > + &args); > + if (ACPI_FAILURE(status)) { > + dev_dbg(dev, "No matching phy in ACPI table\n"); > + return NULL; > + } > + > + return args.adev; > +} > +#endif > + > +int xgene_enet_phy_connect(struct net_device *ndev) > { > struct xgene_enet_pdata *pdata = netdev_priv(ndev); > struct device_node *phy_np; > - struct phy_device *phy_dev; > + struct phy_device *phy_dev = NULL; > struct device *dev = &pdata->pdev->dev; > > if (dev->of_node) { > @@ -756,23 +766,25 @@ static int xgene_enet_phy_connect(struct net_device *ndev) > return -ENODEV; > } > > - phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, > - 0, pdata->phy_mode); > - if (!phy_dev) { > - netdev_err(ndev, "Could not connect to PHY\n"); > - return -ENODEV; > - } > - > - pdata->phy_dev = phy_dev; > + pdata->phy_dev = of_phy_find_device(phy_np); > } else { > - phy_dev = pdata->phy_dev; > +#ifdef CONFIG_ACPI > + if (pdata->mdio_driver) { > + struct acpi_device *adev; > > - if (!phy_dev || > - phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, > - pdata->phy_mode)) { > - netdev_err(ndev, "Could not connect to PHY\n"); > - return -ENODEV; > + adev = acpi_phy_find_device(dev); > + if (adev) > + pdata->phy_dev = adev->driver_data; > } > +#endif > + } > + > + phy_dev = pdata->phy_dev; > + if (!phy_dev || > + phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, > + pdata->phy_mode)) { > + netdev_err(ndev, "Could not connect to PHY\n"); > + return -ENODEV; > } > > pdata->phy_speed = SPEED_UNKNOWN; > @@ -788,12 +800,9 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, > struct mii_bus *mdio) > { > struct device *dev = &pdata->pdev->dev; > - struct net_device *ndev = pdata->ndev; > - struct phy_device *phy; > - struct device_node *child_np; > struct device_node *mdio_np = NULL; > - int ret; > - u32 phy_id; > + struct device_node *child_np; > + u32 phyid; > > if (dev->of_node) { > for_each_child_of_node(dev->of_node, child_np) { > @@ -805,38 +814,50 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, > } > > if (!mdio_np) { > - netdev_dbg(ndev, "No mdio node in the dts\n"); > - return -ENXIO; > + mdiobus_free(mdio); > + return 0; > } > > + pdata->mdio_driver = false; > + > return of_mdiobus_register(mdio, mdio_np); > - } > + } else { > +#ifdef CONFIG_ACPI > + struct phy_device *phy; > + int ret; > > - /* Mask out all PHYs from auto probing. */ > - mdio->phy_mask = ~0; > + if (pdata->mdio_driver) { > + mdiobus_free(mdio); > + return 0; > + } > > - /* Register the MDIO bus */ > - ret = mdiobus_register(mdio); > - if (ret) > - return ret; > + /* Mask out all PHYs from auto probing. */ > + mdio->phy_mask = ~0; > > - ret = device_property_read_u32(dev, "phy-channel", &phy_id); > - if (ret) > - ret = device_property_read_u32(dev, "phy-addr", &phy_id); > - if (ret) > - return -EINVAL; > + /* Register the MDIO bus */ > + ret = mdiobus_register(mdio); > + if (ret) > + return ret; > > - phy = get_phy_device(mdio, phy_id, false); > - if (IS_ERR(phy)) > - return -EIO; > + ret = device_property_read_u32(dev, "phy-channel", &phyid); > + if (ret) > + ret = device_property_read_u32(dev, "phy-addr", &phyid); > + if (ret) > + return -EINVAL; > > - ret = phy_device_register(phy); > - if (ret) > - phy_device_free(phy); > - else > - pdata->phy_dev = phy; > + phy = get_phy_device(mdio, phyid, false); > + if (IS_ERR(phy)) > + return -EIO; > > - return ret; > + ret = phy_device_register(phy); > + if (ret) > + phy_device_free(phy); > + else > + pdata->phy_dev = phy; > + > + return ret; > +#endif > + } > } > > int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) > @@ -861,7 +882,13 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) > ret = xgene_mdiobus_register(pdata, mdio_bus); > if (ret) { > netdev_err(ndev, "Failed to register MDIO bus\n"); > + if (mdio_bus->state == MDIOBUS_REGISTERED) > + mdiobus_unregister(pdata->mdio_bus); > mdiobus_free(mdio_bus); > + if (pdata->mdio_driver) { > + ret = xgene_enet_phy_connect(ndev); > + return 0; > + } > return ret; > } > pdata->mdio_bus = mdio_bus; > @@ -873,14 +900,22 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) > return ret; > } > > +void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata) > +{ > + if (pdata->phy_dev) > + phy_disconnect(pdata->phy_dev); > +} > + > void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) > { > if (pdata->phy_dev) > phy_disconnect(pdata->phy_dev); > > - mdiobus_unregister(pdata->mdio_bus); > - mdiobus_free(pdata->mdio_bus); > - pdata->mdio_bus = NULL; > + if (!pdata->mdio_driver) { > + mdiobus_unregister(pdata->mdio_bus); > + mdiobus_free(pdata->mdio_bus); > + pdata->mdio_bus = NULL; > + } > } > > const struct xgene_mac_ops xgene_gmac_ops = { > @@ -890,6 +925,7 @@ const struct xgene_mac_ops xgene_gmac_ops = { > .tx_enable = xgene_gmac_tx_enable, > .rx_disable = xgene_gmac_rx_disable, > .tx_disable = xgene_gmac_tx_disable, > + .set_speed = xgene_gmac_set_speed, > .set_mac_addr = xgene_gmac_set_mac_addr, > }; > > diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h > index 45220be..5540db9 100644 > --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h > +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h > @@ -104,6 +104,7 @@ enum xgene_enet_rm { > #define RECOMBBUF BIT(27) > > #define MAC_OFFSET 0x30 > +#define PORT_OFFSET 0x4 > > #define BLOCK_ETH_CSR_OFFSET 0x2000 > #define BLOCK_ETH_CLE_CSR_OFFSET 0x6000 > @@ -160,7 +161,9 @@ enum xgene_enet_rm { > #define CFG_CLE_DSTQID0(val) (val & GENMASK(11, 0)) > #define CFG_CLE_FPSEL0(val) ((val << 16) & GENMASK(19, 16)) > #define ICM_CONFIG0_REG_0_ADDR 0x0400 > +#define ICM_CONFIG0_REG_1_ADDR 0x0408 > #define ICM_CONFIG2_REG_0_ADDR 0x0410 > +#define ICM_CONFIG2_REG_1_ADDR 0x0414 > #define RX_DV_GATE_REG_0_ADDR 0x05fc > #define TX_DV_GATE_EN0 BIT(2) > #define RX_DV_GATE_EN0 BIT(1) > @@ -347,6 +350,8 @@ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, > int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); > void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); > bool xgene_ring_mgr_init(struct xgene_enet_pdata *p); > +int xgene_enet_phy_connect(struct net_device *ndev); > +void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata); > > extern const struct xgene_mac_ops xgene_gmac_ops; > extern const struct xgene_port_ops xgene_gport_ops; > diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c > index d208b17..d451e5d 100644 > --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c > +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c > @@ -727,11 +727,12 @@ static int xgene_enet_open(struct net_device *ndev) > ret = xgene_enet_register_irq(ndev); > if (ret) > return ret; > - > - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) > + if (pdata->phy_dev) { > phy_start(pdata->phy_dev); > - else > + } else { > schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); > + netif_carrier_off(ndev); > + } > > netif_start_queue(ndev); > > @@ -746,7 +747,7 @@ static int xgene_enet_close(struct net_device *ndev) > > netif_stop_queue(ndev); > > - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) > + if (pdata->phy_dev) > phy_stop(pdata->phy_dev); > else > cancel_delayed_work_sync(&pdata->link_work); > @@ -1291,6 +1292,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) > struct resource *res; > void __iomem *base_addr; > u32 offset; > + const char *ph; > int ret = 0; > > pdev = pdata->pdev; > @@ -1368,13 +1370,18 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) > if (ret) > return ret; > > + ret = device_property_read_string(dev, "phy-handle", &ph); > + if (!ret) > + pdata->mdio_driver = true; > + > pdata->clk = devm_clk_get(&pdev->dev, NULL); > if (IS_ERR(pdata->clk)) { > /* Firmware may have set up the clock already. */ > dev_info(dev, "clocks have been setup already\n"); > } > > - if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) > + if ((pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) && > + (pdata->enet_id == XGENE_ENET1)) > base_addr = pdata->base_addr - (pdata->port_id * MAC_OFFSET); > else > base_addr = pdata->base_addr; > @@ -1577,7 +1584,7 @@ static int xgene_enet_probe(struct platform_device *pdev) > struct net_device *ndev; > struct xgene_enet_pdata *pdata; > struct device *dev = &pdev->dev; > - const struct xgene_mac_ops *mac_ops; > + void (*link_state)(struct work_struct *); > const struct of_device_id *of_id; > int ret; > > @@ -1603,15 +1610,18 @@ static int xgene_enet_probe(struct platform_device *pdev) > if (of_id) { > pdata->enet_id = (enum xgene_enet_id)of_id->data; > } > -#ifdef CONFIG_ACPI > else { > +#ifdef CONFIG_ACPI > const struct acpi_device_id *acpi_id; > + enum xgene_enet_id enet_id; > > acpi_id = acpi_match_device(xgene_enet_acpi_match, &pdev->dev); > - if (acpi_id) > - pdata->enet_id = (enum xgene_enet_id) acpi_id->driver_data; > - } > + if (acpi_id) { > + enet_id = (enum xgene_enet_id)acpi_id->driver_data; > + pdata->enet_id = enet_id; > + } > #endif > + } > if (!pdata->enet_id) { > free_netdev(ndev); > return -ENODEV; > @@ -1645,13 +1655,18 @@ static int xgene_enet_probe(struct platform_device *pdev) > if (ret) > goto err_netdev; > > - mac_ops = pdata->mac_ops; > + link_state = pdata->mac_ops->link_state; > if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { > ret = xgene_enet_mdio_config(pdata); > if (ret) > goto err_netdev; > + } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { > + if (pdata->mdio_driver) > + ret = xgene_enet_phy_connect(ndev); > + else > + INIT_DELAYED_WORK(&pdata->link_work, link_state); > } else { > - INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state); > + INIT_DELAYED_WORK(&pdata->link_work, link_state); > } > > xgene_enet_napi_add(pdata); > @@ -1679,6 +1694,8 @@ static int xgene_enet_remove(struct platform_device *pdev) > xgene_enet_napi_del(pdata); > if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) > xgene_enet_mdio_remove(pdata); > + else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) > + xgene_enet_phy_disconnect(pdata); > unregister_netdev(ndev); > xgene_enet_delete_desc_rings(pdata); > pdata->port_ops->shutdown(pdata); > diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h > index 092fbec..0fe1a96 100644 > --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h > +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h > @@ -140,6 +140,7 @@ struct xgene_mac_ops { > void (*rx_enable)(struct xgene_enet_pdata *pdata); > void (*tx_disable)(struct xgene_enet_pdata *pdata); > void (*rx_disable)(struct xgene_enet_pdata *pdata); > + void (*set_speed)(struct xgene_enet_pdata *pdata); > void (*set_mac_addr)(struct xgene_enet_pdata *pdata); > void (*set_mss)(struct xgene_enet_pdata *pdata); > void (*link_state)(struct work_struct *work); > @@ -211,6 +212,7 @@ struct xgene_enet_pdata { > u32 mss; > u8 tx_delay; > u8 rx_delay; > + bool mdio_driver; > }; > > struct xgene_indirect_ctl { > diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c > index 7847551..a7a6c05 100644 > --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c > +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c > @@ -28,6 +28,12 @@ static void xgene_enet_wr_csr(struct xgene_enet_pdata *p, u32 offset, u32 val) > iowrite32(val, p->eth_csr_addr + offset); > } > > +static void xgene_enet_wr_clkrst_csr(struct xgene_enet_pdata *p, u32 offset, > + u32 val) > +{ > + iowrite32(val, p->base_addr + offset); > +} > + > static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p, > u32 offset, u32 val) > { > @@ -93,6 +99,11 @@ static u32 xgene_enet_rd_diag_csr(struct xgene_enet_pdata *p, u32 offset) > return ioread32(p->eth_diag_csr_addr + offset); > } > > +static u32 xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *p, u32 offset) > +{ > + return ioread32(p->mcx_mac_csr_addr + offset); > +} > + > static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) > { > u32 rd_data; > @@ -229,21 +240,97 @@ static u32 xgene_enet_link_status(struct xgene_enet_pdata *p) > > data = xgene_mii_phy_read(p, INT_PHY_ADDR, > SGMII_BASE_PAGE_ABILITY_ADDR >> 2); > + if (LINK_SPEED(data) == PHY_SPEED_1000) > + p->phy_speed = SPEED_1000; > + else if (LINK_SPEED(data) == PHY_SPEED_100) > + p->phy_speed = SPEED_100; > + else > + p->phy_speed = SPEED_10; > > return data & LINK_UP; > } > > +static void xgene_sgmac_set_speed(struct xgene_enet_pdata *p) > +{ > + u32 icm0_addr, icm2_addr, debug_addr; > + u32 icm0, icm2, intf_ctl; > + u32 mc2, value; > + > + if (p->phy_speed != SPEED_UNKNOWN) { > + value = xgene_mii_phy_read(p, INT_PHY_ADDR, > + SGMII_BASE_PAGE_ABILITY_ADDR >> 2); > + if (!(value & LINK_UP)) { > + xgene_mii_phy_write(p, INT_PHY_ADDR, > + SGMII_TBI_CONTROL_ADDR >> 2, > + 0x8000); > + xgene_mii_phy_write(p, INT_PHY_ADDR, > + SGMII_TBI_CONTROL_ADDR >> 2, 0x0); > + } > + } > + > + if (p->enet_id == XGENE_ENET1) { > + icm0_addr = (!p->port_id) ? > + ICM_CONFIG0_REG_0_ADDR : ICM_CONFIG0_REG_1_ADDR; > + icm2_addr = (!p->port_id) ? > + ICM_CONFIG2_REG_0_ADDR : ICM_CONFIG2_REG_1_ADDR; > + debug_addr = DEBUG_REG_ADDR; > + } else { > + icm0_addr = XG_MCX_ICM_CONFIG0_REG_0_ADDR; > + icm2_addr = XG_MCX_ICM_CONFIG2_REG_0_ADDR; > + debug_addr = XG_DEBUG_REG_ADDR; > + } > + > + icm0 = xgene_enet_rd_mcx_csr(p, icm0_addr); > + icm2 = xgene_enet_rd_mcx_csr(p, icm2_addr); > + mc2 = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); > + intf_ctl = xgene_enet_rd_mac(p, INTERFACE_CONTROL_ADDR); > + > + switch (p->phy_speed) { > + case SPEED_10: > + ENET_INTERFACE_MODE2_SET(&mc2, 1); > + intf_ctl &= ~(ENET_LHD_MODE | ENET_GHD_MODE); > + CFG_MACMODE_SET(&icm0, 0); > + CFG_WAITASYNCRD_SET(&icm2, 500); > + break; > + case SPEED_100: > + ENET_INTERFACE_MODE2_SET(&mc2, 1); > + intf_ctl &= ~ENET_GHD_MODE; > + intf_ctl |= ENET_LHD_MODE; > + CFG_MACMODE_SET(&icm0, 1); > + CFG_WAITASYNCRD_SET(&icm2, 80); > + break; > + default: > + ENET_INTERFACE_MODE2_SET(&mc2, 2); > + intf_ctl &= ~ENET_LHD_MODE; > + intf_ctl |= ENET_GHD_MODE; > + CFG_MACMODE_SET(&icm0, 2); > + CFG_WAITASYNCRD_SET(&icm2, 16); > + value = xgene_enet_rd_csr(p, debug_addr); > + value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; > + xgene_enet_wr_csr(p, debug_addr, value); > + break; > + } > + > + mc2 |= FULL_DUPLEX2 | PAD_CRC; > + xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, mc2); > + xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, intf_ctl); > + xgene_enet_wr_mcx_csr(p, icm0_addr, icm0); > + xgene_enet_wr_mcx_csr(p, icm2_addr, icm2); > +} > + > static void xgene_sgmac_init(struct xgene_enet_pdata *p) > { > u32 data, loop = 10; > - u32 offset = p->port_id * 4; > + u32 offset = 0; > u32 enet_spare_cfg_reg, rsif_config_reg; > u32 cfg_bypass_reg, rx_dv_gate_reg; > > xgene_sgmac_reset(p); > > /* Enable auto-negotiation */ > - xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x1000); > + xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, > + 0x8000); Please use a define like SGMII_TBI_CONTROL_RESET or something like this. > + xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x9000); Same here SGMII_CONTROL_RESET | SMGII_CONTROL_AUTO_NEG > xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); > > while (loop--) { > @@ -256,16 +343,14 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) > if (!(data & AUTO_NEG_COMPLETE) || !(data & LINK_STATUS)) > netdev_err(p->ndev, "Auto-negotiation failed\n"); > > - data = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); > - ENET_INTERFACE_MODE2_SET(&data, 2); > - xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, data | FULL_DUPLEX2); > - xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, ENET_GHD_MODE); > + xgene_sgmac_set_speed(p); Why don't we use the mac_ops->set_speed approach here? > > if (p->enet_id == XGENE_ENET1) { > enet_spare_cfg_reg = ENET_SPARE_CFG_REG_ADDR; > rsif_config_reg = RSIF_CONFIG_REG_ADDR; > cfg_bypass_reg = CFG_BYPASS_ADDR; > rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR; > + offset = p->port_id * PORT_OFFSET; > } else { > enet_spare_cfg_reg = XG_ENET_SPARE_CFG_REG_ADDR; > rsif_config_reg = XG_RSIF_CONFIG_REG_ADDR; > @@ -334,6 +419,9 @@ static int xgene_enet_reset(struct xgene_enet_pdata *p) > if (!xgene_ring_mgr_init(p)) > return -ENODEV; > > + if (p->enet_id == XGENE_ENET2) > + xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN); > + > if (!IS_ERR(p->clk)) { > clk_prepare_enable(p->clk); > clk_disable_unprepare(p->clk); > @@ -386,10 +474,11 @@ static void xgene_enet_link_state(struct work_struct *work) > if (link) { > if (!netif_carrier_ok(ndev)) { > netif_carrier_on(ndev); > - xgene_sgmac_init(p); > + xgene_sgmac_set_speed(p); > xgene_sgmac_rx_enable(p); > xgene_sgmac_tx_enable(p); Same here. > - netdev_info(ndev, "Link is Up - 1Gbps\n"); > + netdev_info(ndev, "Link is Up - %dMbps\n", > + p->phy_speed); > } > poll_interval = PHY_POLL_LINK_ON; > } else { > @@ -412,6 +501,7 @@ const struct xgene_mac_ops xgene_sgmac_ops = { > .tx_enable = xgene_sgmac_tx_enable, > .rx_disable = xgene_sgmac_rx_disable, > .tx_disable = xgene_sgmac_tx_disable, > + .set_speed = xgene_sgmac_set_speed, > .set_mac_addr = xgene_sgmac_set_mac_addr, > .link_state = xgene_enet_link_state > }; > diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h > index 002df5a..3d0ba37 100644 > --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h > +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h > @@ -24,6 +24,7 @@ > #define PHY_ADDR(src) (((src)<<8) & GENMASK(12, 8)) > #define REG_ADDR(src) ((src) & GENMASK(4, 0)) > #define PHY_CONTROL(src) ((src) & GENMASK(15, 0)) > +#define LINK_SPEED(src) (((src) & GENMASK(11, 10)) >> 10) > #define INT_PHY_ADDR 0x1e > #define SGMII_TBI_CONTROL_ADDR 0x44 > #define SGMII_CONTROL_ADDR 0x00 > @@ -34,6 +35,13 @@ > #define LINK_UP BIT(15) > #define MPA_IDLE_WITH_QMI_EMPTY BIT(12) > #define SG_RX_DV_GATE_REG_0_ADDR 0x05fc > +#define SGMII_EN 0x1 > + > +enum xgene_phy_speed { > + PHY_SPEED_10, > + PHY_SPEED_100, > + PHY_SPEED_1000 > +}; > > extern const struct xgene_mac_ops xgene_sgmac_ops; > extern const struct xgene_port_ops xgene_sgport_ops; > diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h > index 0a2dca8..aba4c19 100644 > --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h > +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h > @@ -65,9 +65,13 @@ > #define XG_CFG_LINK_AGGR_RESUME_0_ADDR 0x0214 > #define XG_LINK_STATUS_ADDR 0x0228 > #define XG_TSIF_MSS_REG0_ADDR 0x02a4 > +#define XG_DEBUG_REG_ADDR 0x0400 > #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c > #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 > #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 > +#define XG_MCX_ECM_CONFIG0_REG_0_ADDR 0x0070 This define is not used in this patch and as far as I can see not even in this series. You can delete this. > +#define XG_MCX_ICM_CONFIG0_REG_0_ADDR 0x00e0 > +#define XG_MCX_ICM_CONFIG2_REG_0_ADDR 0x00e8 > > extern const struct xgene_mac_ops xgene_xgmac_ops; > extern const struct xgene_port_ops xgene_xgport_ops; > Regards, Matthias
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 2f5638f..5d6d14b 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -512,14 +512,11 @@ static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata) #endif } -static void xgene_gmac_init(struct xgene_enet_pdata *pdata) +static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) { struct device *dev = &pdata->pdev->dev; - u32 value, mc2; - u32 intf_ctl, rgmii; - u32 icm0, icm2; - - xgene_gmac_reset(pdata); + u32 icm0, icm2, mc2; + u32 intf_ctl, rgmii, value; xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); @@ -564,7 +561,18 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) mc2 |= FULL_DUPLEX2 | PAD_CRC; xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); + xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); + xgene_enet_configure_clock(pdata); + + xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); + xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); +} +static void xgene_gmac_init(struct xgene_enet_pdata *pdata) +{ + u32 value; + + xgene_gmac_set_speed(pdata); xgene_gmac_set_mac_addr(pdata); /* Adjust MDC clock frequency */ @@ -579,15 +587,10 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) /* Rtype should be copied from FP */ xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0); - xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); - xgene_enet_configure_clock(pdata); /* Rx-Tx traffic resume */ xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); - xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); - xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); - xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value); value &= ~TX_DV_GATE_EN0; value &= ~RX_DV_GATE_EN0; @@ -671,25 +674,12 @@ bool xgene_ring_mgr_init(struct xgene_enet_pdata *p) static int xgene_enet_reset(struct xgene_enet_pdata *pdata) { - u32 val; - if (!xgene_ring_mgr_init(pdata)) return -ENODEV; - if (!IS_ERR(pdata->clk)) { - clk_prepare_enable(pdata->clk); - clk_disable_unprepare(pdata->clk); - clk_prepare_enable(pdata->clk); - xgene_enet_ecc_init(pdata); - } + xgene_enet_ecc_init(pdata); xgene_enet_config_ring_if_assoc(pdata); - /* Enable auto-incr for scanning */ - xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val); - val |= SCAN_AUTO_INCR; - MGMT_CLOCK_SEL_SET(&val, 1); - xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); - return 0; } @@ -724,29 +714,49 @@ static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, static void xgene_enet_adjust_link(struct net_device *ndev) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); + const struct xgene_mac_ops *mac_ops = pdata->mac_ops; struct phy_device *phydev = pdata->phy_dev; if (phydev->link) { if (pdata->phy_speed != phydev->speed) { pdata->phy_speed = phydev->speed; - xgene_gmac_init(pdata); - xgene_gmac_rx_enable(pdata); - xgene_gmac_tx_enable(pdata); + mac_ops->set_speed(pdata); + mac_ops->rx_enable(pdata); + mac_ops->tx_enable(pdata); phy_print_status(phydev); } } else { - xgene_gmac_rx_disable(pdata); - xgene_gmac_tx_disable(pdata); + mac_ops->rx_disable(pdata); + mac_ops->tx_disable(pdata); pdata->phy_speed = SPEED_UNKNOWN; phy_print_status(phydev); } } -static int xgene_enet_phy_connect(struct net_device *ndev) +#ifdef CONFIG_ACPI +static struct acpi_device *acpi_phy_find_device(struct device *dev) +{ + struct acpi_reference_args args; + struct fwnode_handle *fw_node; + int status; + + fw_node = acpi_fwnode_handle(ACPI_COMPANION(dev)); + status = acpi_node_get_property_reference(fw_node, "phy-handle", 0, + &args); + if (ACPI_FAILURE(status)) { + dev_dbg(dev, "No matching phy in ACPI table\n"); + return NULL; + } + + return args.adev; +} +#endif + +int xgene_enet_phy_connect(struct net_device *ndev) { struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct device_node *phy_np; - struct phy_device *phy_dev; + struct phy_device *phy_dev = NULL; struct device *dev = &pdata->pdev->dev; if (dev->of_node) { @@ -756,23 +766,25 @@ static int xgene_enet_phy_connect(struct net_device *ndev) return -ENODEV; } - phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, - 0, pdata->phy_mode); - if (!phy_dev) { - netdev_err(ndev, "Could not connect to PHY\n"); - return -ENODEV; - } - - pdata->phy_dev = phy_dev; + pdata->phy_dev = of_phy_find_device(phy_np); } else { - phy_dev = pdata->phy_dev; +#ifdef CONFIG_ACPI + if (pdata->mdio_driver) { + struct acpi_device *adev; - if (!phy_dev || - phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, - pdata->phy_mode)) { - netdev_err(ndev, "Could not connect to PHY\n"); - return -ENODEV; + adev = acpi_phy_find_device(dev); + if (adev) + pdata->phy_dev = adev->driver_data; } +#endif + } + + phy_dev = pdata->phy_dev; + if (!phy_dev || + phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link, + pdata->phy_mode)) { + netdev_err(ndev, "Could not connect to PHY\n"); + return -ENODEV; } pdata->phy_speed = SPEED_UNKNOWN; @@ -788,12 +800,9 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, struct mii_bus *mdio) { struct device *dev = &pdata->pdev->dev; - struct net_device *ndev = pdata->ndev; - struct phy_device *phy; - struct device_node *child_np; struct device_node *mdio_np = NULL; - int ret; - u32 phy_id; + struct device_node *child_np; + u32 phyid; if (dev->of_node) { for_each_child_of_node(dev->of_node, child_np) { @@ -805,38 +814,50 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, } if (!mdio_np) { - netdev_dbg(ndev, "No mdio node in the dts\n"); - return -ENXIO; + mdiobus_free(mdio); + return 0; } + pdata->mdio_driver = false; + return of_mdiobus_register(mdio, mdio_np); - } + } else { +#ifdef CONFIG_ACPI + struct phy_device *phy; + int ret; - /* Mask out all PHYs from auto probing. */ - mdio->phy_mask = ~0; + if (pdata->mdio_driver) { + mdiobus_free(mdio); + return 0; + } - /* Register the MDIO bus */ - ret = mdiobus_register(mdio); - if (ret) - return ret; + /* Mask out all PHYs from auto probing. */ + mdio->phy_mask = ~0; - ret = device_property_read_u32(dev, "phy-channel", &phy_id); - if (ret) - ret = device_property_read_u32(dev, "phy-addr", &phy_id); - if (ret) - return -EINVAL; + /* Register the MDIO bus */ + ret = mdiobus_register(mdio); + if (ret) + return ret; - phy = get_phy_device(mdio, phy_id, false); - if (IS_ERR(phy)) - return -EIO; + ret = device_property_read_u32(dev, "phy-channel", &phyid); + if (ret) + ret = device_property_read_u32(dev, "phy-addr", &phyid); + if (ret) + return -EINVAL; - ret = phy_device_register(phy); - if (ret) - phy_device_free(phy); - else - pdata->phy_dev = phy; + phy = get_phy_device(mdio, phyid, false); + if (IS_ERR(phy)) + return -EIO; - return ret; + ret = phy_device_register(phy); + if (ret) + phy_device_free(phy); + else + pdata->phy_dev = phy; + + return ret; +#endif + } } int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) @@ -861,7 +882,13 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) ret = xgene_mdiobus_register(pdata, mdio_bus); if (ret) { netdev_err(ndev, "Failed to register MDIO bus\n"); + if (mdio_bus->state == MDIOBUS_REGISTERED) + mdiobus_unregister(pdata->mdio_bus); mdiobus_free(mdio_bus); + if (pdata->mdio_driver) { + ret = xgene_enet_phy_connect(ndev); + return 0; + } return ret; } pdata->mdio_bus = mdio_bus; @@ -873,14 +900,22 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) return ret; } +void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata) +{ + if (pdata->phy_dev) + phy_disconnect(pdata->phy_dev); +} + void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) { if (pdata->phy_dev) phy_disconnect(pdata->phy_dev); - mdiobus_unregister(pdata->mdio_bus); - mdiobus_free(pdata->mdio_bus); - pdata->mdio_bus = NULL; + if (!pdata->mdio_driver) { + mdiobus_unregister(pdata->mdio_bus); + mdiobus_free(pdata->mdio_bus); + pdata->mdio_bus = NULL; + } } const struct xgene_mac_ops xgene_gmac_ops = { @@ -890,6 +925,7 @@ const struct xgene_mac_ops xgene_gmac_ops = { .tx_enable = xgene_gmac_tx_enable, .rx_disable = xgene_gmac_rx_disable, .tx_disable = xgene_gmac_tx_disable, + .set_speed = xgene_gmac_set_speed, .set_mac_addr = xgene_gmac_set_mac_addr, }; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 45220be..5540db9 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -104,6 +104,7 @@ enum xgene_enet_rm { #define RECOMBBUF BIT(27) #define MAC_OFFSET 0x30 +#define PORT_OFFSET 0x4 #define BLOCK_ETH_CSR_OFFSET 0x2000 #define BLOCK_ETH_CLE_CSR_OFFSET 0x6000 @@ -160,7 +161,9 @@ enum xgene_enet_rm { #define CFG_CLE_DSTQID0(val) (val & GENMASK(11, 0)) #define CFG_CLE_FPSEL0(val) ((val << 16) & GENMASK(19, 16)) #define ICM_CONFIG0_REG_0_ADDR 0x0400 +#define ICM_CONFIG0_REG_1_ADDR 0x0408 #define ICM_CONFIG2_REG_0_ADDR 0x0410 +#define ICM_CONFIG2_REG_1_ADDR 0x0414 #define RX_DV_GATE_REG_0_ADDR 0x05fc #define TX_DV_GATE_EN0 BIT(2) #define RX_DV_GATE_EN0 BIT(1) @@ -347,6 +350,8 @@ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); bool xgene_ring_mgr_init(struct xgene_enet_pdata *p); +int xgene_enet_phy_connect(struct net_device *ndev); +void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata); extern const struct xgene_mac_ops xgene_gmac_ops; extern const struct xgene_port_ops xgene_gport_ops; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index d208b17..d451e5d 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -727,11 +727,12 @@ static int xgene_enet_open(struct net_device *ndev) ret = xgene_enet_register_irq(ndev); if (ret) return ret; - - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (pdata->phy_dev) { phy_start(pdata->phy_dev); - else + } else { schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); + netif_carrier_off(ndev); + } netif_start_queue(ndev); @@ -746,7 +747,7 @@ static int xgene_enet_close(struct net_device *ndev) netif_stop_queue(ndev); - if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) + if (pdata->phy_dev) phy_stop(pdata->phy_dev); else cancel_delayed_work_sync(&pdata->link_work); @@ -1291,6 +1292,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) struct resource *res; void __iomem *base_addr; u32 offset; + const char *ph; int ret = 0; pdev = pdata->pdev; @@ -1368,13 +1370,18 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) if (ret) return ret; + ret = device_property_read_string(dev, "phy-handle", &ph); + if (!ret) + pdata->mdio_driver = true; + pdata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pdata->clk)) { /* Firmware may have set up the clock already. */ dev_info(dev, "clocks have been setup already\n"); } - if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) + if ((pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) && + (pdata->enet_id == XGENE_ENET1)) base_addr = pdata->base_addr - (pdata->port_id * MAC_OFFSET); else base_addr = pdata->base_addr; @@ -1577,7 +1584,7 @@ static int xgene_enet_probe(struct platform_device *pdev) struct net_device *ndev; struct xgene_enet_pdata *pdata; struct device *dev = &pdev->dev; - const struct xgene_mac_ops *mac_ops; + void (*link_state)(struct work_struct *); const struct of_device_id *of_id; int ret; @@ -1603,15 +1610,18 @@ static int xgene_enet_probe(struct platform_device *pdev) if (of_id) { pdata->enet_id = (enum xgene_enet_id)of_id->data; } -#ifdef CONFIG_ACPI else { +#ifdef CONFIG_ACPI const struct acpi_device_id *acpi_id; + enum xgene_enet_id enet_id; acpi_id = acpi_match_device(xgene_enet_acpi_match, &pdev->dev); - if (acpi_id) - pdata->enet_id = (enum xgene_enet_id) acpi_id->driver_data; - } + if (acpi_id) { + enet_id = (enum xgene_enet_id)acpi_id->driver_data; + pdata->enet_id = enet_id; + } #endif + } if (!pdata->enet_id) { free_netdev(ndev); return -ENODEV; @@ -1645,13 +1655,18 @@ static int xgene_enet_probe(struct platform_device *pdev) if (ret) goto err_netdev; - mac_ops = pdata->mac_ops; + link_state = pdata->mac_ops->link_state; if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ret = xgene_enet_mdio_config(pdata); if (ret) goto err_netdev; + } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { + if (pdata->mdio_driver) + ret = xgene_enet_phy_connect(ndev); + else + INIT_DELAYED_WORK(&pdata->link_work, link_state); } else { - INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state); + INIT_DELAYED_WORK(&pdata->link_work, link_state); } xgene_enet_napi_add(pdata); @@ -1679,6 +1694,8 @@ static int xgene_enet_remove(struct platform_device *pdev) xgene_enet_napi_del(pdata); if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) xgene_enet_mdio_remove(pdata); + else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) + xgene_enet_phy_disconnect(pdata); unregister_netdev(ndev); xgene_enet_delete_desc_rings(pdata); pdata->port_ops->shutdown(pdata); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 092fbec..0fe1a96 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -140,6 +140,7 @@ struct xgene_mac_ops { void (*rx_enable)(struct xgene_enet_pdata *pdata); void (*tx_disable)(struct xgene_enet_pdata *pdata); void (*rx_disable)(struct xgene_enet_pdata *pdata); + void (*set_speed)(struct xgene_enet_pdata *pdata); void (*set_mac_addr)(struct xgene_enet_pdata *pdata); void (*set_mss)(struct xgene_enet_pdata *pdata); void (*link_state)(struct work_struct *work); @@ -211,6 +212,7 @@ struct xgene_enet_pdata { u32 mss; u8 tx_delay; u8 rx_delay; + bool mdio_driver; }; struct xgene_indirect_ctl { diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index 7847551..a7a6c05 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c @@ -28,6 +28,12 @@ static void xgene_enet_wr_csr(struct xgene_enet_pdata *p, u32 offset, u32 val) iowrite32(val, p->eth_csr_addr + offset); } +static void xgene_enet_wr_clkrst_csr(struct xgene_enet_pdata *p, u32 offset, + u32 val) +{ + iowrite32(val, p->base_addr + offset); +} + static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p, u32 offset, u32 val) { @@ -93,6 +99,11 @@ static u32 xgene_enet_rd_diag_csr(struct xgene_enet_pdata *p, u32 offset) return ioread32(p->eth_diag_csr_addr + offset); } +static u32 xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *p, u32 offset) +{ + return ioread32(p->mcx_mac_csr_addr + offset); +} + static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) { u32 rd_data; @@ -229,21 +240,97 @@ static u32 xgene_enet_link_status(struct xgene_enet_pdata *p) data = xgene_mii_phy_read(p, INT_PHY_ADDR, SGMII_BASE_PAGE_ABILITY_ADDR >> 2); + if (LINK_SPEED(data) == PHY_SPEED_1000) + p->phy_speed = SPEED_1000; + else if (LINK_SPEED(data) == PHY_SPEED_100) + p->phy_speed = SPEED_100; + else + p->phy_speed = SPEED_10; return data & LINK_UP; } +static void xgene_sgmac_set_speed(struct xgene_enet_pdata *p) +{ + u32 icm0_addr, icm2_addr, debug_addr; + u32 icm0, icm2, intf_ctl; + u32 mc2, value; + + if (p->phy_speed != SPEED_UNKNOWN) { + value = xgene_mii_phy_read(p, INT_PHY_ADDR, + SGMII_BASE_PAGE_ABILITY_ADDR >> 2); + if (!(value & LINK_UP)) { + xgene_mii_phy_write(p, INT_PHY_ADDR, + SGMII_TBI_CONTROL_ADDR >> 2, + 0x8000); + xgene_mii_phy_write(p, INT_PHY_ADDR, + SGMII_TBI_CONTROL_ADDR >> 2, 0x0); + } + } + + if (p->enet_id == XGENE_ENET1) { + icm0_addr = (!p->port_id) ? + ICM_CONFIG0_REG_0_ADDR : ICM_CONFIG0_REG_1_ADDR; + icm2_addr = (!p->port_id) ? + ICM_CONFIG2_REG_0_ADDR : ICM_CONFIG2_REG_1_ADDR; + debug_addr = DEBUG_REG_ADDR; + } else { + icm0_addr = XG_MCX_ICM_CONFIG0_REG_0_ADDR; + icm2_addr = XG_MCX_ICM_CONFIG2_REG_0_ADDR; + debug_addr = XG_DEBUG_REG_ADDR; + } + + icm0 = xgene_enet_rd_mcx_csr(p, icm0_addr); + icm2 = xgene_enet_rd_mcx_csr(p, icm2_addr); + mc2 = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); + intf_ctl = xgene_enet_rd_mac(p, INTERFACE_CONTROL_ADDR); + + switch (p->phy_speed) { + case SPEED_10: + ENET_INTERFACE_MODE2_SET(&mc2, 1); + intf_ctl &= ~(ENET_LHD_MODE | ENET_GHD_MODE); + CFG_MACMODE_SET(&icm0, 0); + CFG_WAITASYNCRD_SET(&icm2, 500); + break; + case SPEED_100: + ENET_INTERFACE_MODE2_SET(&mc2, 1); + intf_ctl &= ~ENET_GHD_MODE; + intf_ctl |= ENET_LHD_MODE; + CFG_MACMODE_SET(&icm0, 1); + CFG_WAITASYNCRD_SET(&icm2, 80); + break; + default: + ENET_INTERFACE_MODE2_SET(&mc2, 2); + intf_ctl &= ~ENET_LHD_MODE; + intf_ctl |= ENET_GHD_MODE; + CFG_MACMODE_SET(&icm0, 2); + CFG_WAITASYNCRD_SET(&icm2, 16); + value = xgene_enet_rd_csr(p, debug_addr); + value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; + xgene_enet_wr_csr(p, debug_addr, value); + break; + } + + mc2 |= FULL_DUPLEX2 | PAD_CRC; + xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, mc2); + xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, intf_ctl); + xgene_enet_wr_mcx_csr(p, icm0_addr, icm0); + xgene_enet_wr_mcx_csr(p, icm2_addr, icm2); +} + static void xgene_sgmac_init(struct xgene_enet_pdata *p) { u32 data, loop = 10; - u32 offset = p->port_id * 4; + u32 offset = 0; u32 enet_spare_cfg_reg, rsif_config_reg; u32 cfg_bypass_reg, rx_dv_gate_reg; xgene_sgmac_reset(p); /* Enable auto-negotiation */ - xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x1000); + xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, + 0x8000); + xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x9000); xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); while (loop--) { @@ -256,16 +343,14 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) if (!(data & AUTO_NEG_COMPLETE) || !(data & LINK_STATUS)) netdev_err(p->ndev, "Auto-negotiation failed\n"); - data = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); - ENET_INTERFACE_MODE2_SET(&data, 2); - xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, data | FULL_DUPLEX2); - xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, ENET_GHD_MODE); + xgene_sgmac_set_speed(p); if (p->enet_id == XGENE_ENET1) { enet_spare_cfg_reg = ENET_SPARE_CFG_REG_ADDR; rsif_config_reg = RSIF_CONFIG_REG_ADDR; cfg_bypass_reg = CFG_BYPASS_ADDR; rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR; + offset = p->port_id * PORT_OFFSET; } else { enet_spare_cfg_reg = XG_ENET_SPARE_CFG_REG_ADDR; rsif_config_reg = XG_RSIF_CONFIG_REG_ADDR; @@ -334,6 +419,9 @@ static int xgene_enet_reset(struct xgene_enet_pdata *p) if (!xgene_ring_mgr_init(p)) return -ENODEV; + if (p->enet_id == XGENE_ENET2) + xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN); + if (!IS_ERR(p->clk)) { clk_prepare_enable(p->clk); clk_disable_unprepare(p->clk); @@ -386,10 +474,11 @@ static void xgene_enet_link_state(struct work_struct *work) if (link) { if (!netif_carrier_ok(ndev)) { netif_carrier_on(ndev); - xgene_sgmac_init(p); + xgene_sgmac_set_speed(p); xgene_sgmac_rx_enable(p); xgene_sgmac_tx_enable(p); - netdev_info(ndev, "Link is Up - 1Gbps\n"); + netdev_info(ndev, "Link is Up - %dMbps\n", + p->phy_speed); } poll_interval = PHY_POLL_LINK_ON; } else { @@ -412,6 +501,7 @@ const struct xgene_mac_ops xgene_sgmac_ops = { .tx_enable = xgene_sgmac_tx_enable, .rx_disable = xgene_sgmac_rx_disable, .tx_disable = xgene_sgmac_tx_disable, + .set_speed = xgene_sgmac_set_speed, .set_mac_addr = xgene_sgmac_set_mac_addr, .link_state = xgene_enet_link_state }; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h index 002df5a..3d0ba37 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h @@ -24,6 +24,7 @@ #define PHY_ADDR(src) (((src)<<8) & GENMASK(12, 8)) #define REG_ADDR(src) ((src) & GENMASK(4, 0)) #define PHY_CONTROL(src) ((src) & GENMASK(15, 0)) +#define LINK_SPEED(src) (((src) & GENMASK(11, 10)) >> 10) #define INT_PHY_ADDR 0x1e #define SGMII_TBI_CONTROL_ADDR 0x44 #define SGMII_CONTROL_ADDR 0x00 @@ -34,6 +35,13 @@ #define LINK_UP BIT(15) #define MPA_IDLE_WITH_QMI_EMPTY BIT(12) #define SG_RX_DV_GATE_REG_0_ADDR 0x05fc +#define SGMII_EN 0x1 + +enum xgene_phy_speed { + PHY_SPEED_10, + PHY_SPEED_100, + PHY_SPEED_1000 +}; extern const struct xgene_mac_ops xgene_sgmac_ops; extern const struct xgene_port_ops xgene_sgport_ops; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h index 0a2dca8..aba4c19 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h @@ -65,9 +65,13 @@ #define XG_CFG_LINK_AGGR_RESUME_0_ADDR 0x0214 #define XG_LINK_STATUS_ADDR 0x0228 #define XG_TSIF_MSS_REG0_ADDR 0x02a4 +#define XG_DEBUG_REG_ADDR 0x0400 #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 +#define XG_MCX_ECM_CONFIG0_REG_0_ADDR 0x0070 +#define XG_MCX_ICM_CONFIG0_REG_0_ADDR 0x00e0 +#define XG_MCX_ICM_CONFIG2_REG_0_ADDR 0x00e8 extern const struct xgene_mac_ops xgene_xgmac_ops; extern const struct xgene_port_ops xgene_xgport_ops;