diff options
author | David S. Miller <davem@davemloft.net> | 2022-01-29 17:49:21 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2022-01-29 17:49:21 +0000 |
commit | ff58831fa02deb42fd731f830d8d9ec545573c7c (patch) | |
tree | dab150a236619d781a34fbfc46a896fdb1b2d15e | |
parent | 0a78117213c4bb85dfebf89b924226883597bc60 (diff) | |
parent | e461bd6f43f4e568f7436a8b6bc21c4ce6914c36 (diff) |
Merge branch 'Cadence-ZyncMP-SGMII'
Robert Hancock says:
====================
Cadence MACB/GEM support for ZynqMP SGMII
Changes to allow SGMII mode to work properly in the GEM driver on the
Xilinx ZynqMP platform.
Changes since v3:
-more code formatting and error handling fixes
Changes since v2:
-fixed missing includes in DT binding example
-fixed phy_init and phy_power_on error handling/cleanup, moved
phy_power_on to open rather than probe
Changes since v1:
-changed order of controller reset and PHY init as per suggestion
-switched device reset to be optional
-updated bindings doc patch for switch to YAML
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/devicetree/bindings/net/cdns,macb.yaml | 56 | ||||
-rw-r--r-- | arch/arm64/boot/dts/xilinx/zynqmp.dtsi | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/cadence/macb.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/cadence/macb_main.c | 63 |
4 files changed, 128 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/net/cdns,macb.yaml b/Documentation/devicetree/bindings/net/cdns,macb.yaml index 8dd06db34169..6cd3d853dcba 100644 --- a/Documentation/devicetree/bindings/net/cdns,macb.yaml +++ b/Documentation/devicetree/bindings/net/cdns,macb.yaml @@ -81,6 +81,25 @@ properties: phy-handle: true + phys: + maxItems: 1 + + phy-names: + const: sgmii-phy + description: + Required with ZynqMP SoC when in SGMII mode. + Should reference PS-GTR generic PHY device for this controller + instance. See ZynqMP example. + + resets: + maxItems: 1 + description: + Recommended with ZynqMP, specify reset control for this + controller instance with zynqmp-reset driver. + + reset-names: + maxItems: 1 + fixed-link: true iommus: @@ -157,3 +176,40 @@ examples: reset-gpios = <&pioE 6 1>; }; }; + + - | + #include <dt-bindings/clock/xlnx-zynqmp-clk.h> + #include <dt-bindings/power/xlnx-zynqmp-power.h> + #include <dt-bindings/reset/xlnx-zynqmp-resets.h> + #include <dt-bindings/phy/phy.h> + + bus { + #address-cells = <2>; + #size-cells = <2>; + gem1: ethernet@ff0c0000 { + compatible = "cdns,zynqmp-gem", "cdns,gem"; + interrupt-parent = <&gic>; + interrupts = <0 59 4>, <0 59 4>; + reg = <0x0 0xff0c0000 0x0 0x1000>; + clocks = <&zynqmp_clk LPD_LSBUS>, <&zynqmp_clk GEM1_REF>, + <&zynqmp_clk GEM1_TX>, <&zynqmp_clk GEM1_RX>, + <&zynqmp_clk GEM_TSU>; + clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk"; + #address-cells = <1>; + #size-cells = <0>; + #stream-id-cells = <1>; + iommus = <&smmu 0x875>; + power-domains = <&zynqmp_firmware PD_ETH_1>; + resets = <&zynqmp_reset ZYNQMP_RESET_GEM1>; + reset-names = "gem1_rst"; + status = "okay"; + phy-mode = "sgmii"; + phy-names = "sgmii-phy"; + phys = <&psgtr 1 PHY_TYPE_SGMII 1 1>; + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index 74e66443e4ce..9bec3ba20c69 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -512,6 +512,8 @@ #stream-id-cells = <1>; iommus = <&smmu 0x874>; power-domains = <&zynqmp_firmware PD_ETH_0>; + resets = <&zynqmp_reset ZYNQMP_RESET_GEM0>; + reset-names = "gem0_rst"; }; gem1: ethernet@ff0c0000 { @@ -526,6 +528,8 @@ #stream-id-cells = <1>; iommus = <&smmu 0x875>; power-domains = <&zynqmp_firmware PD_ETH_1>; + resets = <&zynqmp_reset ZYNQMP_RESET_GEM1>; + reset-names = "gem1_rst"; }; gem2: ethernet@ff0d0000 { @@ -540,6 +544,8 @@ #stream-id-cells = <1>; iommus = <&smmu 0x876>; power-domains = <&zynqmp_firmware PD_ETH_2>; + resets = <&zynqmp_reset ZYNQMP_RESET_GEM2>; + reset-names = "gem2_rst"; }; gem3: ethernet@ff0e0000 { @@ -554,6 +560,8 @@ #stream-id-cells = <1>; iommus = <&smmu 0x877>; power-domains = <&zynqmp_firmware PD_ETH_3>; + resets = <&zynqmp_reset ZYNQMP_RESET_GEM3>; + reset-names = "gem3_rst"; }; gpio: gpio@ff0a0000 { diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 9ddbee7de72b..f0a7d8396a4a 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -12,6 +12,7 @@ #include <linux/ptp_clock_kernel.h> #include <linux/net_tstamp.h> #include <linux/interrupt.h> +#include <linux/phy/phy.h> #if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) || defined(CONFIG_MACB_USE_HWSTAMP) #define MACB_EXT_DESC @@ -1291,6 +1292,9 @@ struct macb { u32 wol; struct macb_ptp_info *ptp_info; /* macb-ptp interface */ + + struct phy *sgmii_phy; /* for ZynqMP SGMII mode */ + #ifdef MACB_EXT_DESC uint8_t hw_dma_cap; #endif diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index a363da928e8b..1ce20bf52f72 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -34,7 +34,9 @@ #include <linux/udp.h> #include <linux/tcp.h> #include <linux/iopoll.h> +#include <linux/phy/phy.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include "macb.h" /* This structure is only used for MACB on SiFive FU540 devices */ @@ -2739,10 +2741,14 @@ static int macb_open(struct net_device *dev) macb_init_hw(bp); - err = macb_phylink_connect(bp); + err = phy_power_on(bp->sgmii_phy); if (err) goto reset_hw; + err = macb_phylink_connect(bp); + if (err) + goto phy_off; + netif_tx_start_all_queues(dev); if (bp->ptp_info) @@ -2750,6 +2756,9 @@ static int macb_open(struct net_device *dev) return 0; +phy_off: + phy_power_off(bp->sgmii_phy); + reset_hw: macb_reset_hw(bp); for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) @@ -2775,6 +2784,8 @@ static int macb_close(struct net_device *dev) phylink_stop(bp->phylink); phylink_disconnect_phy(bp->phylink); + phy_power_off(bp->sgmii_phy); + spin_lock_irqsave(&bp->lock, flags); macb_reset_hw(bp); netif_carrier_off(dev); @@ -4544,13 +4555,55 @@ static const struct macb_config np4_config = { .usrio = &macb_default_usrio, }; +static int zynqmp_init(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(dev); + int ret; + + if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) { + /* Ensure PS-GTR PHY device used in SGMII mode is ready */ + bp->sgmii_phy = devm_phy_get(&pdev->dev, "sgmii-phy"); + + if (IS_ERR(bp->sgmii_phy)) { + ret = PTR_ERR(bp->sgmii_phy); + dev_err_probe(&pdev->dev, ret, + "failed to get PS-GTR PHY\n"); + return ret; + } + + ret = phy_init(bp->sgmii_phy); + if (ret) { + dev_err(&pdev->dev, "failed to init PS-GTR PHY: %d\n", + ret); + return ret; + } + } + + /* Fully reset GEM controller at hardware level using zynqmp-reset driver, + * if mapped in device tree. + */ + ret = device_reset_optional(&pdev->dev); + if (ret) { + dev_err_probe(&pdev->dev, ret, "failed to reset controller"); + phy_exit(bp->sgmii_phy); + return ret; + } + + ret = macb_init(pdev); + if (ret) + phy_exit(bp->sgmii_phy); + + return ret; +} + static const struct macb_config zynqmp_config = { .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO | MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH, .dma_burst_length = 16, .clk_init = macb_clk_init, - .init = macb_init, + .init = zynqmp_init, .jumbo_max_len = 10240, .usrio = &macb_default_usrio, }; @@ -4767,7 +4820,7 @@ static int macb_probe(struct platform_device *pdev) err = macb_mii_init(bp); if (err) - goto err_out_free_netdev; + goto err_out_phy_exit; netif_carrier_off(dev); @@ -4792,6 +4845,9 @@ err_out_unregister_mdio: mdiobus_unregister(bp->mii_bus); mdiobus_free(bp->mii_bus); +err_out_phy_exit: + phy_exit(bp->sgmii_phy); + err_out_free_netdev: free_netdev(dev); @@ -4813,6 +4869,7 @@ static int macb_remove(struct platform_device *pdev) if (dev) { bp = netdev_priv(dev); + phy_exit(bp->sgmii_phy); mdiobus_unregister(bp->mii_bus); mdiobus_free(bp->mii_bus); |