diff options
20 files changed, 1291 insertions, 283 deletions
diff --git a/Documentation/devicetree/bindings/net/apm-xgene-mdio.txt b/Documentation/devicetree/bindings/net/apm-xgene-mdio.txt new file mode 100644 index 000000000000..78722d74cea8 --- /dev/null +++ b/Documentation/devicetree/bindings/net/apm-xgene-mdio.txt | |||
@@ -0,0 +1,37 @@ | |||
1 | APM X-Gene SoC MDIO node | ||
2 | |||
3 | MDIO node is defined to describe on-chip MDIO controller. | ||
4 | |||
5 | Required properties: | ||
6 | - compatible: Must be "apm,xgene-mdio-rgmii" or "apm,xgene-mdio-xfi" | ||
7 | - #address-cells: Must be <1>. | ||
8 | - #size-cells: Must be <0>. | ||
9 | - reg: Address and length of the register set | ||
10 | - clocks: Reference to the clock entry | ||
11 | |||
12 | For the phys on the mdio bus, there must be a node with the following fields: | ||
13 | - compatible: PHY identifier. Please refer ./phy.txt for the format. | ||
14 | - reg: The ID number for the phy. | ||
15 | |||
16 | Example: | ||
17 | |||
18 | mdio: mdio@17020000 { | ||
19 | compatible = "apm,xgene-mdio-rgmii"; | ||
20 | #address-cells = <1>; | ||
21 | #size-cells = <0>; | ||
22 | reg = <0x0 0x17020000 0x0 0xd100>; | ||
23 | clocks = <&menetclk 0>; | ||
24 | }; | ||
25 | |||
26 | /* Board-specific peripheral configurations */ | ||
27 | &mdio { | ||
28 | menetphy: phy@3 { | ||
29 | reg = <0x3>; | ||
30 | }; | ||
31 | sgenet0phy: phy@4 { | ||
32 | reg = <0x4>; | ||
33 | }; | ||
34 | sgenet1phy: phy@5 { | ||
35 | reg = <0x5>; | ||
36 | }; | ||
37 | }; | ||
diff --git a/MAINTAINERS b/MAINTAINERS index dc3481d7c80d..a9bdba0484d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -839,7 +839,9 @@ M: Iyappan Subramanian <isubramanian@apm.com> | |||
839 | M: Keyur Chudgar <kchudgar@apm.com> | 839 | M: Keyur Chudgar <kchudgar@apm.com> |
840 | S: Supported | 840 | S: Supported |
841 | F: drivers/net/ethernet/apm/xgene/ | 841 | F: drivers/net/ethernet/apm/xgene/ |
842 | F: drivers/net/phy/mdio-xgene.c | ||
842 | F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt | 843 | F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt |
844 | F: Documentation/devicetree/bindings/net/apm-xgene-mdio.txt | ||
843 | 845 | ||
844 | APTINA CAMERA SENSOR PLL | 846 | APTINA CAMERA SENSOR PLL |
845 | M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> | 847 | M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> |
diff --git a/arch/arm64/boot/dts/apm/apm-merlin.dts b/arch/arm64/boot/dts/apm/apm-merlin.dts index 387c6a8d0da9..b0f64414c1b0 100644 --- a/arch/arm64/boot/dts/apm/apm-merlin.dts +++ b/arch/arm64/boot/dts/apm/apm-merlin.dts | |||
@@ -83,3 +83,9 @@ | |||
83 | status = "ok"; | 83 | status = "ok"; |
84 | }; | 84 | }; |
85 | }; | 85 | }; |
86 | |||
87 | &mdio { | ||
88 | sgenet0phy: phy@0 { | ||
89 | reg = <0x0>; | ||
90 | }; | ||
91 | }; | ||
diff --git a/arch/arm64/boot/dts/apm/apm-mustang.dts b/arch/arm64/boot/dts/apm/apm-mustang.dts index 44db32ec5e9c..b7fb5d9295c2 100644 --- a/arch/arm64/boot/dts/apm/apm-mustang.dts +++ b/arch/arm64/boot/dts/apm/apm-mustang.dts | |||
@@ -79,3 +79,15 @@ | |||
79 | &mmc0 { | 79 | &mmc0 { |
80 | status = "ok"; | 80 | status = "ok"; |
81 | }; | 81 | }; |
82 | |||
83 | &mdio { | ||
84 | menet0phy: phy@3 { | ||
85 | reg = <0x3>; | ||
86 | }; | ||
87 | sgenet0phy: phy@4 { | ||
88 | reg = <0x4>; | ||
89 | }; | ||
90 | sgenet1phy: phy@5 { | ||
91 | reg = <0x5>; | ||
92 | }; | ||
93 | }; | ||
diff --git a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi index c569f761d090..2e1e5daa1dc7 100644 --- a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi +++ b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi | |||
@@ -625,10 +625,18 @@ | |||
625 | apm,irq-start = <8>; | 625 | apm,irq-start = <8>; |
626 | }; | 626 | }; |
627 | 627 | ||
628 | mdio: mdio@1f610000 { | ||
629 | compatible = "apm,xgene-mdio-xfi"; | ||
630 | #address-cells = <1>; | ||
631 | #size-cells = <0>; | ||
632 | reg = <0x0 0x1f610000 0x0 0xd100>; | ||
633 | clocks = <&xge0clk 0>; | ||
634 | }; | ||
635 | |||
628 | sgenet0: ethernet@1f610000 { | 636 | sgenet0: ethernet@1f610000 { |
629 | compatible = "apm,xgene2-sgenet"; | 637 | compatible = "apm,xgene2-sgenet"; |
630 | status = "disabled"; | 638 | status = "disabled"; |
631 | reg = <0x0 0x1f610000 0x0 0x10000>, | 639 | reg = <0x0 0x1f610000 0x0 0xd100>, |
632 | <0x0 0x1f600000 0x0 0Xd100>, | 640 | <0x0 0x1f600000 0x0 0Xd100>, |
633 | <0x0 0x20000000 0x0 0X20000>; | 641 | <0x0 0x20000000 0x0 0X20000>; |
634 | interrupts = <0 96 4>, | 642 | interrupts = <0 96 4>, |
@@ -637,6 +645,7 @@ | |||
637 | clocks = <&xge0clk 0>; | 645 | clocks = <&xge0clk 0>; |
638 | local-mac-address = [00 01 73 00 00 01]; | 646 | local-mac-address = [00 01 73 00 00 01]; |
639 | phy-connection-type = "sgmii"; | 647 | phy-connection-type = "sgmii"; |
648 | phy-handle = <&sgenet0phy>; | ||
640 | }; | 649 | }; |
641 | 650 | ||
642 | xgenet1: ethernet@1f620000 { | 651 | xgenet1: ethernet@1f620000 { |
diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi index 5147d7698924..6bf7cbe2e72d 100644 --- a/arch/arm64/boot/dts/apm/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi | |||
@@ -237,20 +237,11 @@ | |||
237 | clocks = <&socplldiv2 0>; | 237 | clocks = <&socplldiv2 0>; |
238 | reg = <0x0 0x1f21c000 0x0 0x1000>; | 238 | reg = <0x0 0x1f21c000 0x0 0x1000>; |
239 | reg-names = "csr-reg"; | 239 | reg-names = "csr-reg"; |
240 | csr-mask = <0x3>; | 240 | csr-mask = <0xa>; |
241 | enable-mask = <0xf>; | ||
241 | clock-output-names = "sge0clk"; | 242 | clock-output-names = "sge0clk"; |
242 | }; | 243 | }; |
243 | 244 | ||
244 | sge1clk: sge1clk@1f21c000 { | ||
245 | compatible = "apm,xgene-device-clock"; | ||
246 | #clock-cells = <1>; | ||
247 | clocks = <&socplldiv2 0>; | ||
248 | reg = <0x0 0x1f21c000 0x0 0x1000>; | ||
249 | reg-names = "csr-reg"; | ||
250 | csr-mask = <0xc>; | ||
251 | clock-output-names = "sge1clk"; | ||
252 | }; | ||
253 | |||
254 | xge0clk: xge0clk@1f61c000 { | 245 | xge0clk: xge0clk@1f61c000 { |
255 | compatible = "apm,xgene-device-clock"; | 246 | compatible = "apm,xgene-device-clock"; |
256 | #clock-cells = <1>; | 247 | #clock-cells = <1>; |
@@ -921,6 +912,14 @@ | |||
921 | clocks = <&rtcclk 0>; | 912 | clocks = <&rtcclk 0>; |
922 | }; | 913 | }; |
923 | 914 | ||
915 | mdio: mdio@17020000 { | ||
916 | compatible = "apm,xgene-mdio-rgmii"; | ||
917 | #address-cells = <1>; | ||
918 | #size-cells = <0>; | ||
919 | reg = <0x0 0x17020000 0x0 0xd100>; | ||
920 | clocks = <&menetclk 0>; | ||
921 | }; | ||
922 | |||
924 | menet: ethernet@17020000 { | 923 | menet: ethernet@17020000 { |
925 | compatible = "apm,xgene-enet"; | 924 | compatible = "apm,xgene-enet"; |
926 | status = "disabled"; | 925 | status = "disabled"; |
@@ -934,7 +933,7 @@ | |||
934 | /* mac address will be overwritten by the bootloader */ | 933 | /* mac address will be overwritten by the bootloader */ |
935 | local-mac-address = [00 00 00 00 00 00]; | 934 | local-mac-address = [00 00 00 00 00 00]; |
936 | phy-connection-type = "rgmii"; | 935 | phy-connection-type = "rgmii"; |
937 | phy-handle = <&menetphy>; | 936 | phy-handle = <&menet0phy>,<&menetphy>; |
938 | mdio { | 937 | mdio { |
939 | compatible = "apm,xgene-mdio"; | 938 | compatible = "apm,xgene-mdio"; |
940 | #address-cells = <1>; | 939 | #address-cells = <1>; |
@@ -960,6 +959,7 @@ | |||
960 | clocks = <&sge0clk 0>; | 959 | clocks = <&sge0clk 0>; |
961 | local-mac-address = [00 00 00 00 00 00]; | 960 | local-mac-address = [00 00 00 00 00 00]; |
962 | phy-connection-type = "sgmii"; | 961 | phy-connection-type = "sgmii"; |
962 | phy-handle = <&sgenet0phy>; | ||
963 | }; | 963 | }; |
964 | 964 | ||
965 | sgenet1: ethernet@1f210030 { | 965 | sgenet1: ethernet@1f210030 { |
@@ -973,9 +973,9 @@ | |||
973 | <0x0 0xAD 0x4>; | 973 | <0x0 0xAD 0x4>; |
974 | port-id = <1>; | 974 | port-id = <1>; |
975 | dma-coherent; | 975 | dma-coherent; |
976 | clocks = <&sge1clk 0>; | ||
977 | local-mac-address = [00 00 00 00 00 00]; | 976 | local-mac-address = [00 00 00 00 00 00]; |
978 | phy-connection-type = "sgmii"; | 977 | phy-connection-type = "sgmii"; |
978 | phy-handle = <&sgenet1phy>; | ||
979 | }; | 979 | }; |
980 | 980 | ||
981 | xgenet: ethernet@1f610000 { | 981 | xgenet: ethernet@1f610000 { |
diff --git a/drivers/net/ethernet/apm/xgene/Kconfig b/drivers/net/ethernet/apm/xgene/Kconfig index 19e38afbc5ee..300e3b5c54e0 100644 --- a/drivers/net/ethernet/apm/xgene/Kconfig +++ b/drivers/net/ethernet/apm/xgene/Kconfig | |||
@@ -3,6 +3,7 @@ config NET_XGENE | |||
3 | depends on HAS_DMA | 3 | depends on HAS_DMA |
4 | depends on ARCH_XGENE || COMPILE_TEST | 4 | depends on ARCH_XGENE || COMPILE_TEST |
5 | select PHYLIB | 5 | select PHYLIB |
6 | select MDIO_XGENE | ||
6 | help | 7 | help |
7 | This is the Ethernet driver for the on-chip ethernet interface on the | 8 | This is the Ethernet driver for the on-chip ethernet interface on the |
8 | APM X-Gene SoC. | 9 | APM X-Gene SoC. |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c index 416d6ebfc2ce..22a7b26ca1d6 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c | |||
@@ -65,8 +65,15 @@ static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) | |||
65 | 65 | ||
66 | return phy_ethtool_gset(phydev, cmd); | 66 | return phy_ethtool_gset(phydev, cmd); |
67 | } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { | 67 | } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { |
68 | cmd->supported = SUPPORTED_1000baseT_Full | | 68 | if (pdata->mdio_driver) { |
69 | SUPPORTED_Autoneg | SUPPORTED_MII; | 69 | if (!phydev) |
70 | return -ENODEV; | ||
71 | |||
72 | return phy_ethtool_gset(phydev, cmd); | ||
73 | } | ||
74 | |||
75 | cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | | ||
76 | SUPPORTED_MII; | ||
70 | cmd->advertising = cmd->supported; | 77 | cmd->advertising = cmd->supported; |
71 | ethtool_cmd_speed_set(cmd, SPEED_1000); | 78 | ethtool_cmd_speed_set(cmd, SPEED_1000); |
72 | cmd->duplex = DUPLEX_FULL; | 79 | cmd->duplex = DUPLEX_FULL; |
@@ -92,12 +99,21 @@ static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) | |||
92 | struct phy_device *phydev = pdata->phy_dev; | 99 | struct phy_device *phydev = pdata->phy_dev; |
93 | 100 | ||
94 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { | 101 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { |
95 | if (phydev == NULL) | 102 | if (!phydev) |
96 | return -ENODEV; | 103 | return -ENODEV; |
97 | 104 | ||
98 | return phy_ethtool_sset(phydev, cmd); | 105 | return phy_ethtool_sset(phydev, cmd); |
99 | } | 106 | } |
100 | 107 | ||
108 | if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { | ||
109 | if (pdata->mdio_driver) { | ||
110 | if (!phydev) | ||
111 | return -ENODEV; | ||
112 | |||
113 | return phy_ethtool_sset(phydev, cmd); | ||
114 | } | ||
115 | } | ||
116 | |||
101 | return -EINVAL; | 117 | return -EINVAL; |
102 | } | 118 | } |
103 | 119 | ||
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 2f5638f7f864..8a2a221a9838 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | |||
@@ -381,59 +381,6 @@ static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata, | |||
381 | rd_addr); | 381 | rd_addr); |
382 | } | 382 | } |
383 | 383 | ||
384 | static int xgene_mii_phy_write(struct xgene_enet_pdata *pdata, int phy_id, | ||
385 | u32 reg, u16 data) | ||
386 | { | ||
387 | u32 addr = 0, wr_data = 0; | ||
388 | u32 done; | ||
389 | u8 wait = 10; | ||
390 | |||
391 | PHY_ADDR_SET(&addr, phy_id); | ||
392 | REG_ADDR_SET(&addr, reg); | ||
393 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr); | ||
394 | |||
395 | PHY_CONTROL_SET(&wr_data, data); | ||
396 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONTROL_ADDR, wr_data); | ||
397 | do { | ||
398 | usleep_range(5, 10); | ||
399 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done); | ||
400 | } while ((done & BUSY_MASK) && wait--); | ||
401 | |||
402 | if (done & BUSY_MASK) { | ||
403 | netdev_err(pdata->ndev, "MII_MGMT write failed\n"); | ||
404 | return -EBUSY; | ||
405 | } | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata, | ||
411 | u8 phy_id, u32 reg) | ||
412 | { | ||
413 | u32 addr = 0; | ||
414 | u32 data, done; | ||
415 | u8 wait = 10; | ||
416 | |||
417 | PHY_ADDR_SET(&addr, phy_id); | ||
418 | REG_ADDR_SET(&addr, reg); | ||
419 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr); | ||
420 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); | ||
421 | do { | ||
422 | usleep_range(5, 10); | ||
423 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done); | ||
424 | } while ((done & BUSY_MASK) && wait--); | ||
425 | |||
426 | if (done & BUSY_MASK) { | ||
427 | netdev_err(pdata->ndev, "MII_MGMT read failed\n"); | ||
428 | return -EBUSY; | ||
429 | } | ||
430 | |||
431 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_STATUS_ADDR, &data); | ||
432 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, 0); | ||
433 | |||
434 | return data; | ||
435 | } | ||
436 | |||
437 | static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) | 384 | static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) |
438 | { | 385 | { |
439 | u32 addr0, addr1; | 386 | u32 addr0, addr1; |
@@ -512,14 +459,11 @@ static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata) | |||
512 | #endif | 459 | #endif |
513 | } | 460 | } |
514 | 461 | ||
515 | static void xgene_gmac_init(struct xgene_enet_pdata *pdata) | 462 | static void xgene_gmac_set_speed(struct xgene_enet_pdata *pdata) |
516 | { | 463 | { |
517 | struct device *dev = &pdata->pdev->dev; | 464 | struct device *dev = &pdata->pdev->dev; |
518 | u32 value, mc2; | 465 | u32 icm0, icm2, mc2; |
519 | u32 intf_ctl, rgmii; | 466 | u32 intf_ctl, rgmii, value; |
520 | u32 icm0, icm2; | ||
521 | |||
522 | xgene_gmac_reset(pdata); | ||
523 | 467 | ||
524 | xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); | 468 | xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); |
525 | xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); | 469 | xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); |
@@ -564,7 +508,21 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) | |||
564 | mc2 |= FULL_DUPLEX2 | PAD_CRC; | 508 | mc2 |= FULL_DUPLEX2 | PAD_CRC; |
565 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); | 509 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); |
566 | xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); | 510 | xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); |
511 | xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); | ||
512 | xgene_enet_configure_clock(pdata); | ||
513 | |||
514 | xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); | ||
515 | xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); | ||
516 | } | ||
517 | |||
518 | static void xgene_gmac_init(struct xgene_enet_pdata *pdata) | ||
519 | { | ||
520 | u32 value; | ||
567 | 521 | ||
522 | if (!pdata->mdio_driver) | ||
523 | xgene_gmac_reset(pdata); | ||
524 | |||
525 | xgene_gmac_set_speed(pdata); | ||
568 | xgene_gmac_set_mac_addr(pdata); | 526 | xgene_gmac_set_mac_addr(pdata); |
569 | 527 | ||
570 | /* Adjust MDC clock frequency */ | 528 | /* Adjust MDC clock frequency */ |
@@ -579,15 +537,10 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata) | |||
579 | 537 | ||
580 | /* Rtype should be copied from FP */ | 538 | /* Rtype should be copied from FP */ |
581 | xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0); | 539 | xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0); |
582 | xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); | ||
583 | xgene_enet_configure_clock(pdata); | ||
584 | 540 | ||
585 | /* Rx-Tx traffic resume */ | 541 | /* Rx-Tx traffic resume */ |
586 | xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); | 542 | xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); |
587 | 543 | ||
588 | xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); | ||
589 | xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); | ||
590 | |||
591 | xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value); | 544 | xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value); |
592 | value &= ~TX_DV_GATE_EN0; | 545 | value &= ~TX_DV_GATE_EN0; |
593 | value &= ~RX_DV_GATE_EN0; | 546 | value &= ~RX_DV_GATE_EN0; |
@@ -671,92 +624,154 @@ bool xgene_ring_mgr_init(struct xgene_enet_pdata *p) | |||
671 | 624 | ||
672 | static int xgene_enet_reset(struct xgene_enet_pdata *pdata) | 625 | static int xgene_enet_reset(struct xgene_enet_pdata *pdata) |
673 | { | 626 | { |
674 | u32 val; | 627 | struct device *dev = &pdata->pdev->dev; |
675 | 628 | ||
676 | if (!xgene_ring_mgr_init(pdata)) | 629 | if (!xgene_ring_mgr_init(pdata)) |
677 | return -ENODEV; | 630 | return -ENODEV; |
678 | 631 | ||
679 | if (!IS_ERR(pdata->clk)) { | 632 | if (pdata->mdio_driver) { |
633 | xgene_enet_config_ring_if_assoc(pdata); | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | if (dev->of_node) { | ||
680 | clk_prepare_enable(pdata->clk); | 638 | clk_prepare_enable(pdata->clk); |
639 | udelay(5); | ||
681 | clk_disable_unprepare(pdata->clk); | 640 | clk_disable_unprepare(pdata->clk); |
641 | udelay(5); | ||
682 | clk_prepare_enable(pdata->clk); | 642 | clk_prepare_enable(pdata->clk); |
683 | xgene_enet_ecc_init(pdata); | 643 | udelay(5); |
644 | } else { | ||
645 | #ifdef CONFIG_ACPI | ||
646 | if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), "_RST")) { | ||
647 | acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev), | ||
648 | "_RST", NULL, NULL); | ||
649 | } else if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), | ||
650 | "_INI")) { | ||
651 | acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev), | ||
652 | "_INI", NULL, NULL); | ||
653 | } | ||
654 | #endif | ||
684 | } | 655 | } |
685 | xgene_enet_config_ring_if_assoc(pdata); | ||
686 | 656 | ||
687 | /* Enable auto-incr for scanning */ | 657 | xgene_enet_ecc_init(pdata); |
688 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val); | 658 | xgene_enet_config_ring_if_assoc(pdata); |
689 | val |= SCAN_AUTO_INCR; | ||
690 | MGMT_CLOCK_SEL_SET(&val, 1); | ||
691 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); | ||
692 | 659 | ||
693 | return 0; | 660 | return 0; |
694 | } | 661 | } |
695 | 662 | ||
696 | static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) | 663 | static void xgene_enet_clear(struct xgene_enet_pdata *pdata, |
664 | struct xgene_enet_desc_ring *ring) | ||
697 | { | 665 | { |
698 | if (!IS_ERR(pdata->clk)) | 666 | u32 addr, val, data; |
699 | clk_disable_unprepare(pdata->clk); | ||
700 | } | ||
701 | 667 | ||
702 | static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | 668 | val = xgene_enet_ring_bufnum(ring->id); |
703 | { | ||
704 | struct xgene_enet_pdata *pdata = bus->priv; | ||
705 | u32 val; | ||
706 | 669 | ||
707 | val = xgene_mii_phy_read(pdata, mii_id, regnum); | 670 | if (xgene_enet_is_bufpool(ring->id)) { |
708 | netdev_dbg(pdata->ndev, "mdio_rd: bus=%d reg=%d val=%x\n", | 671 | addr = ENET_CFGSSQMIFPRESET_ADDR; |
709 | mii_id, regnum, val); | 672 | data = BIT(val - 0x20); |
673 | } else { | ||
674 | addr = ENET_CFGSSQMIWQRESET_ADDR; | ||
675 | data = BIT(val); | ||
676 | } | ||
710 | 677 | ||
711 | return val; | 678 | xgene_enet_wr_ring_if(pdata, addr, data); |
712 | } | 679 | } |
713 | 680 | ||
714 | static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, | 681 | static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) |
715 | u16 val) | ||
716 | { | 682 | { |
717 | struct xgene_enet_pdata *pdata = bus->priv; | 683 | struct device *dev = &pdata->pdev->dev; |
684 | struct xgene_enet_desc_ring *ring; | ||
685 | u32 pb, val; | ||
686 | int i; | ||
687 | |||
688 | pb = 0; | ||
689 | for (i = 0; i < pdata->rxq_cnt; i++) { | ||
690 | ring = pdata->rx_ring[i]->buf_pool; | ||
691 | |||
692 | val = xgene_enet_ring_bufnum(ring->id); | ||
693 | pb |= BIT(val - 0x20); | ||
694 | } | ||
695 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb); | ||
696 | |||
697 | pb = 0; | ||
698 | for (i = 0; i < pdata->txq_cnt; i++) { | ||
699 | ring = pdata->tx_ring[i]; | ||
700 | |||
701 | val = xgene_enet_ring_bufnum(ring->id); | ||
702 | pb |= BIT(val); | ||
703 | } | ||
704 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); | ||
718 | 705 | ||
719 | netdev_dbg(pdata->ndev, "mdio_wr: bus=%d reg=%d val=%x\n", | 706 | if (dev->of_node) { |
720 | mii_id, regnum, val); | 707 | if (!IS_ERR(pdata->clk)) |
721 | return xgene_mii_phy_write(pdata, mii_id, regnum, val); | 708 | clk_disable_unprepare(pdata->clk); |
709 | } | ||
722 | } | 710 | } |
723 | 711 | ||
724 | static void xgene_enet_adjust_link(struct net_device *ndev) | 712 | static void xgene_enet_adjust_link(struct net_device *ndev) |
725 | { | 713 | { |
726 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | 714 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); |
715 | const struct xgene_mac_ops *mac_ops = pdata->mac_ops; | ||
727 | struct phy_device *phydev = pdata->phy_dev; | 716 | struct phy_device *phydev = pdata->phy_dev; |
728 | 717 | ||
729 | if (phydev->link) { | 718 | if (phydev->link) { |
730 | if (pdata->phy_speed != phydev->speed) { | 719 | if (pdata->phy_speed != phydev->speed) { |
731 | pdata->phy_speed = phydev->speed; | 720 | pdata->phy_speed = phydev->speed; |
732 | xgene_gmac_init(pdata); | 721 | mac_ops->set_speed(pdata); |
733 | xgene_gmac_rx_enable(pdata); | 722 | mac_ops->rx_enable(pdata); |
734 | xgene_gmac_tx_enable(pdata); | 723 | mac_ops->tx_enable(pdata); |
735 | phy_print_status(phydev); | 724 | phy_print_status(phydev); |
736 | } | 725 | } |
737 | } else { | 726 | } else { |
738 | xgene_gmac_rx_disable(pdata); | 727 | mac_ops->rx_disable(pdata); |
739 | xgene_gmac_tx_disable(pdata); | 728 | mac_ops->tx_disable(pdata); |
740 | pdata->phy_speed = SPEED_UNKNOWN; | 729 | pdata->phy_speed = SPEED_UNKNOWN; |
741 | phy_print_status(phydev); | 730 | phy_print_status(phydev); |
742 | } | 731 | } |
743 | } | 732 | } |
744 | 733 | ||
745 | static int xgene_enet_phy_connect(struct net_device *ndev) | 734 | #ifdef CONFIG_ACPI |
735 | static struct acpi_device *acpi_phy_find_device(struct device *dev) | ||
736 | { | ||
737 | struct acpi_reference_args args; | ||
738 | struct fwnode_handle *fw_node; | ||
739 | int status; | ||
740 | |||
741 | fw_node = acpi_fwnode_handle(ACPI_COMPANION(dev)); | ||
742 | status = acpi_node_get_property_reference(fw_node, "phy-handle", 0, | ||
743 | &args); | ||
744 | if (ACPI_FAILURE(status)) { | ||
745 | dev_dbg(dev, "No matching phy in ACPI table\n"); | ||
746 | return NULL; | ||
747 | } | ||
748 | |||
749 | return args.adev; | ||
750 | } | ||
751 | #endif | ||
752 | |||
753 | int xgene_enet_phy_connect(struct net_device *ndev) | ||
746 | { | 754 | { |
747 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | 755 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); |
748 | struct device_node *phy_np; | 756 | struct device_node *np; |
749 | struct phy_device *phy_dev; | 757 | struct phy_device *phy_dev; |
750 | struct device *dev = &pdata->pdev->dev; | 758 | struct device *dev = &pdata->pdev->dev; |
759 | struct acpi_device *adev; | ||
760 | int i; | ||
751 | 761 | ||
752 | if (dev->of_node) { | 762 | if (dev->of_node) { |
753 | phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); | 763 | for (i = 0 ; i < 2; i++) { |
754 | if (!phy_np) { | 764 | np = of_parse_phandle(dev->of_node, "phy-handle", i); |
765 | if (np) | ||
766 | break; | ||
767 | } | ||
768 | |||
769 | if (!np) { | ||
755 | netdev_dbg(ndev, "No phy-handle found in DT\n"); | 770 | netdev_dbg(ndev, "No phy-handle found in DT\n"); |
756 | return -ENODEV; | 771 | return -ENODEV; |
757 | } | 772 | } |
758 | 773 | ||
759 | phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, | 774 | phy_dev = of_phy_connect(ndev, np, &xgene_enet_adjust_link, |
760 | 0, pdata->phy_mode); | 775 | 0, pdata->phy_mode); |
761 | if (!phy_dev) { | 776 | if (!phy_dev) { |
762 | netdev_err(ndev, "Could not connect to PHY\n"); | 777 | netdev_err(ndev, "Could not connect to PHY\n"); |
@@ -765,6 +780,11 @@ static int xgene_enet_phy_connect(struct net_device *ndev) | |||
765 | 780 | ||
766 | pdata->phy_dev = phy_dev; | 781 | pdata->phy_dev = phy_dev; |
767 | } else { | 782 | } else { |
783 | #ifdef CONFIG_ACPI | ||
784 | adev = acpi_phy_find_device(dev); | ||
785 | if (adev) | ||
786 | pdata->phy_dev = adev->driver_data; | ||
787 | |||
768 | phy_dev = pdata->phy_dev; | 788 | phy_dev = pdata->phy_dev; |
769 | 789 | ||
770 | if (!phy_dev || | 790 | if (!phy_dev || |
@@ -773,6 +793,7 @@ static int xgene_enet_phy_connect(struct net_device *ndev) | |||
773 | netdev_err(ndev, "Could not connect to PHY\n"); | 793 | netdev_err(ndev, "Could not connect to PHY\n"); |
774 | return -ENODEV; | 794 | return -ENODEV; |
775 | } | 795 | } |
796 | #endif | ||
776 | } | 797 | } |
777 | 798 | ||
778 | pdata->phy_speed = SPEED_UNKNOWN; | 799 | pdata->phy_speed = SPEED_UNKNOWN; |
@@ -792,8 +813,8 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, | |||
792 | struct phy_device *phy; | 813 | struct phy_device *phy; |
793 | struct device_node *child_np; | 814 | struct device_node *child_np; |
794 | struct device_node *mdio_np = NULL; | 815 | struct device_node *mdio_np = NULL; |
816 | u32 phy_addr; | ||
795 | int ret; | 817 | int ret; |
796 | u32 phy_id; | ||
797 | 818 | ||
798 | if (dev->of_node) { | 819 | if (dev->of_node) { |
799 | for_each_child_of_node(dev->of_node, child_np) { | 820 | for_each_child_of_node(dev->of_node, child_np) { |
@@ -820,21 +841,17 @@ static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata, | |||
820 | if (ret) | 841 | if (ret) |
821 | return ret; | 842 | return ret; |
822 | 843 | ||
823 | ret = device_property_read_u32(dev, "phy-channel", &phy_id); | 844 | ret = device_property_read_u32(dev, "phy-channel", &phy_addr); |
824 | if (ret) | 845 | if (ret) |
825 | ret = device_property_read_u32(dev, "phy-addr", &phy_id); | 846 | ret = device_property_read_u32(dev, "phy-addr", &phy_addr); |
826 | if (ret) | 847 | if (ret) |
827 | return -EINVAL; | 848 | return -EINVAL; |
828 | 849 | ||
829 | phy = get_phy_device(mdio, phy_id, false); | 850 | phy = xgene_enet_phy_register(mdio, phy_addr); |
830 | if (IS_ERR(phy)) | 851 | if (!phy) |
831 | return -EIO; | 852 | return -EIO; |
832 | 853 | ||
833 | ret = phy_device_register(phy); | 854 | pdata->phy_dev = phy; |
834 | if (ret) | ||
835 | phy_device_free(phy); | ||
836 | else | ||
837 | pdata->phy_dev = phy; | ||
838 | 855 | ||
839 | return ret; | 856 | return ret; |
840 | } | 857 | } |
@@ -850,13 +867,13 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) | |||
850 | return -ENOMEM; | 867 | return -ENOMEM; |
851 | 868 | ||
852 | mdio_bus->name = "APM X-Gene MDIO bus"; | 869 | mdio_bus->name = "APM X-Gene MDIO bus"; |
853 | mdio_bus->read = xgene_enet_mdio_read; | 870 | mdio_bus->read = xgene_mdio_rgmii_read; |
854 | mdio_bus->write = xgene_enet_mdio_write; | 871 | mdio_bus->write = xgene_mdio_rgmii_write; |
855 | snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "xgene-mii", | 872 | snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "xgene-mii", |
856 | ndev->name); | 873 | ndev->name); |
857 | 874 | ||
858 | mdio_bus->priv = pdata; | 875 | mdio_bus->priv = (void __force *)pdata->mcx_mac_addr; |
859 | mdio_bus->parent = &ndev->dev; | 876 | mdio_bus->parent = &pdata->pdev->dev; |
860 | 877 | ||
861 | ret = xgene_mdiobus_register(pdata, mdio_bus); | 878 | ret = xgene_mdiobus_register(pdata, mdio_bus); |
862 | if (ret) { | 879 | if (ret) { |
@@ -873,6 +890,12 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) | |||
873 | return ret; | 890 | return ret; |
874 | } | 891 | } |
875 | 892 | ||
893 | void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata) | ||
894 | { | ||
895 | if (pdata->phy_dev) | ||
896 | phy_disconnect(pdata->phy_dev); | ||
897 | } | ||
898 | |||
876 | void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) | 899 | void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) |
877 | { | 900 | { |
878 | if (pdata->phy_dev) | 901 | if (pdata->phy_dev) |
@@ -890,11 +913,13 @@ const struct xgene_mac_ops xgene_gmac_ops = { | |||
890 | .tx_enable = xgene_gmac_tx_enable, | 913 | .tx_enable = xgene_gmac_tx_enable, |
891 | .rx_disable = xgene_gmac_rx_disable, | 914 | .rx_disable = xgene_gmac_rx_disable, |
892 | .tx_disable = xgene_gmac_tx_disable, | 915 | .tx_disable = xgene_gmac_tx_disable, |
916 | .set_speed = xgene_gmac_set_speed, | ||
893 | .set_mac_addr = xgene_gmac_set_mac_addr, | 917 | .set_mac_addr = xgene_gmac_set_mac_addr, |
894 | }; | 918 | }; |
895 | 919 | ||
896 | const struct xgene_port_ops xgene_gport_ops = { | 920 | const struct xgene_port_ops xgene_gport_ops = { |
897 | .reset = xgene_enet_reset, | 921 | .reset = xgene_enet_reset, |
922 | .clear = xgene_enet_clear, | ||
898 | .cle_bypass = xgene_enet_cle_bypass, | 923 | .cle_bypass = xgene_enet_cle_bypass, |
899 | .shutdown = xgene_gport_shutdown, | 924 | .shutdown = xgene_gport_shutdown, |
900 | }; | 925 | }; |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 45220be3122f..179a44dceb29 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | |||
@@ -104,6 +104,8 @@ enum xgene_enet_rm { | |||
104 | #define RECOMBBUF BIT(27) | 104 | #define RECOMBBUF BIT(27) |
105 | 105 | ||
106 | #define MAC_OFFSET 0x30 | 106 | #define MAC_OFFSET 0x30 |
107 | #define OFFSET_4 0x04 | ||
108 | #define OFFSET_8 0x08 | ||
107 | 109 | ||
108 | #define BLOCK_ETH_CSR_OFFSET 0x2000 | 110 | #define BLOCK_ETH_CSR_OFFSET 0x2000 |
109 | #define BLOCK_ETH_CLE_CSR_OFFSET 0x6000 | 111 | #define BLOCK_ETH_CLE_CSR_OFFSET 0x6000 |
@@ -165,6 +167,8 @@ enum xgene_enet_rm { | |||
165 | #define TX_DV_GATE_EN0 BIT(2) | 167 | #define TX_DV_GATE_EN0 BIT(2) |
166 | #define RX_DV_GATE_EN0 BIT(1) | 168 | #define RX_DV_GATE_EN0 BIT(1) |
167 | #define RESUME_RX0 BIT(0) | 169 | #define RESUME_RX0 BIT(0) |
170 | #define ENET_CFGSSQMIFPRESET_ADDR 0x14 | ||
171 | #define ENET_CFGSSQMIWQRESET_ADDR 0x1c | ||
168 | #define ENET_CFGSSQMIWQASSOC_ADDR 0xe0 | 172 | #define ENET_CFGSSQMIWQASSOC_ADDR 0xe0 |
169 | #define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc | 173 | #define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc |
170 | #define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0 | 174 | #define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0 |
@@ -297,11 +301,6 @@ enum xgene_enet_ring_bufnum { | |||
297 | RING_BUFNUM_INVALID | 301 | RING_BUFNUM_INVALID |
298 | }; | 302 | }; |
299 | 303 | ||
300 | enum xgene_enet_cmd { | ||
301 | XGENE_ENET_WR_CMD = BIT(31), | ||
302 | XGENE_ENET_RD_CMD = BIT(30) | ||
303 | }; | ||
304 | |||
305 | enum xgene_enet_err_code { | 304 | enum xgene_enet_err_code { |
306 | HBF_READ_DATA = 3, | 305 | HBF_READ_DATA = 3, |
307 | HBF_LL_READ = 4, | 306 | HBF_LL_READ = 4, |
@@ -347,6 +346,8 @@ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, | |||
347 | int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); | 346 | int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); |
348 | void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); | 347 | void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); |
349 | bool xgene_ring_mgr_init(struct xgene_enet_pdata *p); | 348 | bool xgene_ring_mgr_init(struct xgene_enet_pdata *p); |
349 | int xgene_enet_phy_connect(struct net_device *ndev); | ||
350 | void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata); | ||
350 | 351 | ||
351 | extern const struct xgene_mac_ops xgene_gmac_ops; | 352 | extern const struct xgene_mac_ops xgene_gmac_ops; |
352 | extern const struct xgene_port_ops xgene_gport_ops; | 353 | 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 d208b172f4d7..d1d6b5eeb613 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c | |||
@@ -102,25 +102,13 @@ static u8 xgene_enet_hdr_len(const void *data) | |||
102 | 102 | ||
103 | static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool) | 103 | static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool) |
104 | { | 104 | { |
105 | struct xgene_enet_pdata *pdata = netdev_priv(buf_pool->ndev); | 105 | int i; |
106 | struct xgene_enet_raw_desc16 *raw_desc; | ||
107 | u32 slots = buf_pool->slots - 1; | ||
108 | u32 tail = buf_pool->tail; | ||
109 | u32 userinfo; | ||
110 | int i, len; | ||
111 | |||
112 | len = pdata->ring_ops->len(buf_pool); | ||
113 | for (i = 0; i < len; i++) { | ||
114 | tail = (tail - 1) & slots; | ||
115 | raw_desc = &buf_pool->raw_desc16[tail]; | ||
116 | 106 | ||
117 | /* Hardware stores descriptor in little endian format */ | 107 | /* Free up the buffers held by hardware */ |
118 | userinfo = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); | 108 | for (i = 0; i < buf_pool->slots; i++) { |
119 | dev_kfree_skb_any(buf_pool->rx_skb[userinfo]); | 109 | if (buf_pool->rx_skb[i]) |
110 | dev_kfree_skb_any(buf_pool->rx_skb[i]); | ||
120 | } | 111 | } |
121 | |||
122 | pdata->ring_ops->wr_cmd(buf_pool, -len); | ||
123 | buf_pool->tail = tail; | ||
124 | } | 112 | } |
125 | 113 | ||
126 | static irqreturn_t xgene_enet_rx_irq(const int irq, void *data) | 114 | static irqreturn_t xgene_enet_rx_irq(const int irq, void *data) |
@@ -481,6 +469,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, | |||
481 | XGENE_ENET_MAX_MTU, DMA_FROM_DEVICE); | 469 | XGENE_ENET_MAX_MTU, DMA_FROM_DEVICE); |
482 | skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); | 470 | skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); |
483 | skb = buf_pool->rx_skb[skb_index]; | 471 | skb = buf_pool->rx_skb[skb_index]; |
472 | buf_pool->rx_skb[skb_index] = NULL; | ||
484 | 473 | ||
485 | /* checking for error */ | 474 | /* checking for error */ |
486 | status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) || | 475 | status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) || |
@@ -619,6 +608,30 @@ static void xgene_enet_timeout(struct net_device *ndev) | |||
619 | } | 608 | } |
620 | } | 609 | } |
621 | 610 | ||
611 | static void xgene_enet_set_irq_name(struct net_device *ndev) | ||
612 | { | ||
613 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
614 | struct xgene_enet_desc_ring *ring; | ||
615 | int i; | ||
616 | |||
617 | for (i = 0; i < pdata->rxq_cnt; i++) { | ||
618 | ring = pdata->rx_ring[i]; | ||
619 | if (!pdata->cq_cnt) { | ||
620 | snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-rx-txc", | ||
621 | ndev->name); | ||
622 | } else { | ||
623 | snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-rx-%d", | ||
624 | ndev->name, i); | ||
625 | } | ||
626 | } | ||
627 | |||
628 | for (i = 0; i < pdata->cq_cnt; i++) { | ||
629 | ring = pdata->tx_ring[i]->cp_ring; | ||
630 | snprintf(ring->irq_name, IRQ_ID_SIZE, "%s-txc-%d", | ||
631 | ndev->name, i); | ||
632 | } | ||
633 | } | ||
634 | |||
622 | static int xgene_enet_register_irq(struct net_device *ndev) | 635 | static int xgene_enet_register_irq(struct net_device *ndev) |
623 | { | 636 | { |
624 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | 637 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); |
@@ -626,6 +639,7 @@ static int xgene_enet_register_irq(struct net_device *ndev) | |||
626 | struct xgene_enet_desc_ring *ring; | 639 | struct xgene_enet_desc_ring *ring; |
627 | int ret = 0, i; | 640 | int ret = 0, i; |
628 | 641 | ||
642 | xgene_enet_set_irq_name(ndev); | ||
629 | for (i = 0; i < pdata->rxq_cnt; i++) { | 643 | for (i = 0; i < pdata->rxq_cnt; i++) { |
630 | ring = pdata->rx_ring[i]; | 644 | ring = pdata->rx_ring[i]; |
631 | irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY); | 645 | irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY); |
@@ -720,20 +734,21 @@ static int xgene_enet_open(struct net_device *ndev) | |||
720 | if (ret) | 734 | if (ret) |
721 | return ret; | 735 | return ret; |
722 | 736 | ||
723 | mac_ops->tx_enable(pdata); | ||
724 | mac_ops->rx_enable(pdata); | ||
725 | |||
726 | xgene_enet_napi_enable(pdata); | 737 | xgene_enet_napi_enable(pdata); |
727 | ret = xgene_enet_register_irq(ndev); | 738 | ret = xgene_enet_register_irq(ndev); |
728 | if (ret) | 739 | if (ret) |
729 | return ret; | 740 | return ret; |
730 | 741 | ||
731 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) | 742 | if (pdata->phy_dev) { |
732 | phy_start(pdata->phy_dev); | 743 | phy_start(pdata->phy_dev); |
733 | else | 744 | } else { |
734 | schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); | 745 | schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); |
746 | netif_carrier_off(ndev); | ||
747 | } | ||
735 | 748 | ||
736 | netif_start_queue(ndev); | 749 | mac_ops->tx_enable(pdata); |
750 | mac_ops->rx_enable(pdata); | ||
751 | netif_tx_start_all_queues(ndev); | ||
737 | 752 | ||
738 | return ret; | 753 | return ret; |
739 | } | 754 | } |
@@ -744,16 +759,15 @@ static int xgene_enet_close(struct net_device *ndev) | |||
744 | const struct xgene_mac_ops *mac_ops = pdata->mac_ops; | 759 | const struct xgene_mac_ops *mac_ops = pdata->mac_ops; |
745 | int i; | 760 | int i; |
746 | 761 | ||
747 | netif_stop_queue(ndev); | 762 | netif_tx_stop_all_queues(ndev); |
763 | mac_ops->tx_disable(pdata); | ||
764 | mac_ops->rx_disable(pdata); | ||
748 | 765 | ||
749 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) | 766 | if (pdata->phy_dev) |
750 | phy_stop(pdata->phy_dev); | 767 | phy_stop(pdata->phy_dev); |
751 | else | 768 | else |
752 | cancel_delayed_work_sync(&pdata->link_work); | 769 | cancel_delayed_work_sync(&pdata->link_work); |
753 | 770 | ||
754 | mac_ops->tx_disable(pdata); | ||
755 | mac_ops->rx_disable(pdata); | ||
756 | |||
757 | xgene_enet_free_irq(ndev); | 771 | xgene_enet_free_irq(ndev); |
758 | xgene_enet_napi_disable(pdata); | 772 | xgene_enet_napi_disable(pdata); |
759 | for (i = 0; i < pdata->rxq_cnt; i++) | 773 | for (i = 0; i < pdata->rxq_cnt; i++) |
@@ -761,7 +775,6 @@ static int xgene_enet_close(struct net_device *ndev) | |||
761 | 775 | ||
762 | return 0; | 776 | return 0; |
763 | } | 777 | } |
764 | |||
765 | static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring) | 778 | static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring) |
766 | { | 779 | { |
767 | struct xgene_enet_pdata *pdata; | 780 | struct xgene_enet_pdata *pdata; |
@@ -771,7 +784,7 @@ static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring) | |||
771 | dev = ndev_to_dev(ring->ndev); | 784 | dev = ndev_to_dev(ring->ndev); |
772 | 785 | ||
773 | pdata->ring_ops->clear(ring); | 786 | pdata->ring_ops->clear(ring); |
774 | dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma); | 787 | dmam_free_coherent(dev, ring->size, ring->desc_addr, ring->dma); |
775 | } | 788 | } |
776 | 789 | ||
777 | static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata) | 790 | static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata) |
@@ -784,6 +797,9 @@ static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata) | |||
784 | ring = pdata->tx_ring[i]; | 797 | ring = pdata->tx_ring[i]; |
785 | if (ring) { | 798 | if (ring) { |
786 | xgene_enet_delete_ring(ring); | 799 | xgene_enet_delete_ring(ring); |
800 | pdata->port_ops->clear(pdata, ring); | ||
801 | if (pdata->cq_cnt) | ||
802 | xgene_enet_delete_ring(ring->cp_ring); | ||
787 | pdata->tx_ring[i] = NULL; | 803 | pdata->tx_ring[i] = NULL; |
788 | } | 804 | } |
789 | } | 805 | } |
@@ -794,6 +810,7 @@ static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata) | |||
794 | buf_pool = ring->buf_pool; | 810 | buf_pool = ring->buf_pool; |
795 | xgene_enet_delete_bufpool(buf_pool); | 811 | xgene_enet_delete_bufpool(buf_pool); |
796 | xgene_enet_delete_ring(buf_pool); | 812 | xgene_enet_delete_ring(buf_pool); |
813 | pdata->port_ops->clear(pdata, buf_pool); | ||
797 | xgene_enet_delete_ring(ring); | 814 | xgene_enet_delete_ring(ring); |
798 | pdata->rx_ring[i] = NULL; | 815 | pdata->rx_ring[i] = NULL; |
799 | } | 816 | } |
@@ -842,7 +859,7 @@ static void xgene_enet_free_desc_ring(struct xgene_enet_desc_ring *ring) | |||
842 | 859 | ||
843 | if (ring->desc_addr) { | 860 | if (ring->desc_addr) { |
844 | pdata->ring_ops->clear(ring); | 861 | pdata->ring_ops->clear(ring); |
845 | dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma); | 862 | dmam_free_coherent(dev, ring->size, ring->desc_addr, ring->dma); |
846 | } | 863 | } |
847 | devm_kfree(dev, ring); | 864 | devm_kfree(dev, ring); |
848 | } | 865 | } |
@@ -900,9 +917,10 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( | |||
900 | struct net_device *ndev, u32 ring_num, | 917 | struct net_device *ndev, u32 ring_num, |
901 | enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id) | 918 | enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id) |
902 | { | 919 | { |
903 | struct xgene_enet_desc_ring *ring; | ||
904 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | 920 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); |
905 | struct device *dev = ndev_to_dev(ndev); | 921 | struct device *dev = ndev_to_dev(ndev); |
922 | struct xgene_enet_desc_ring *ring; | ||
923 | void *irq_mbox_addr; | ||
906 | int size; | 924 | int size; |
907 | 925 | ||
908 | size = xgene_enet_get_ring_size(dev, cfgsize); | 926 | size = xgene_enet_get_ring_size(dev, cfgsize); |
@@ -919,8 +937,8 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( | |||
919 | ring->cfgsize = cfgsize; | 937 | ring->cfgsize = cfgsize; |
920 | ring->id = ring_id; | 938 | ring->id = ring_id; |
921 | 939 | ||
922 | ring->desc_addr = dma_zalloc_coherent(dev, size, &ring->dma, | 940 | ring->desc_addr = dmam_alloc_coherent(dev, size, &ring->dma, |
923 | GFP_KERNEL); | 941 | GFP_KERNEL | __GFP_ZERO); |
924 | if (!ring->desc_addr) { | 942 | if (!ring->desc_addr) { |
925 | devm_kfree(dev, ring); | 943 | devm_kfree(dev, ring); |
926 | return NULL; | 944 | return NULL; |
@@ -928,14 +946,16 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( | |||
928 | ring->size = size; | 946 | ring->size = size; |
929 | 947 | ||
930 | if (is_irq_mbox_required(pdata, ring)) { | 948 | if (is_irq_mbox_required(pdata, ring)) { |
931 | ring->irq_mbox_addr = dma_zalloc_coherent(dev, INTR_MBOX_SIZE, | 949 | irq_mbox_addr = dmam_alloc_coherent(dev, INTR_MBOX_SIZE, |
932 | &ring->irq_mbox_dma, GFP_KERNEL); | 950 | &ring->irq_mbox_dma, |
933 | if (!ring->irq_mbox_addr) { | 951 | GFP_KERNEL | __GFP_ZERO); |
934 | dma_free_coherent(dev, size, ring->desc_addr, | 952 | if (!irq_mbox_addr) { |
935 | ring->dma); | 953 | dmam_free_coherent(dev, size, ring->desc_addr, |
954 | ring->dma); | ||
936 | devm_kfree(dev, ring); | 955 | devm_kfree(dev, ring); |
937 | return NULL; | 956 | return NULL; |
938 | } | 957 | } |
958 | ring->irq_mbox_addr = irq_mbox_addr; | ||
939 | } | 959 | } |
940 | 960 | ||
941 | ring->cmd_base = xgene_enet_ring_cmd_base(pdata, ring); | 961 | ring->cmd_base = xgene_enet_ring_cmd_base(pdata, ring); |
@@ -996,6 +1016,7 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) | |||
996 | u8 eth_bufnum = pdata->eth_bufnum; | 1016 | u8 eth_bufnum = pdata->eth_bufnum; |
997 | u8 bp_bufnum = pdata->bp_bufnum; | 1017 | u8 bp_bufnum = pdata->bp_bufnum; |
998 | u16 ring_num = pdata->ring_num; | 1018 | u16 ring_num = pdata->ring_num; |
1019 | __le64 *exp_bufs; | ||
999 | u16 ring_id; | 1020 | u16 ring_id; |
1000 | int i, ret, size; | 1021 | int i, ret, size; |
1001 | 1022 | ||
@@ -1027,13 +1048,6 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) | |||
1027 | rx_ring->nbufpool = NUM_BUFPOOL; | 1048 | rx_ring->nbufpool = NUM_BUFPOOL; |
1028 | rx_ring->buf_pool = buf_pool; | 1049 | rx_ring->buf_pool = buf_pool; |
1029 | rx_ring->irq = pdata->irqs[i]; | 1050 | rx_ring->irq = pdata->irqs[i]; |
1030 | if (!pdata->cq_cnt) { | ||
1031 | snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx-txc", | ||
1032 | ndev->name); | ||
1033 | } else { | ||
1034 | snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx%d", | ||
1035 | ndev->name, i); | ||
1036 | } | ||
1037 | buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots, | 1051 | buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots, |
1038 | sizeof(struct sk_buff *), | 1052 | sizeof(struct sk_buff *), |
1039 | GFP_KERNEL); | 1053 | GFP_KERNEL); |
@@ -1060,13 +1074,13 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) | |||
1060 | } | 1074 | } |
1061 | 1075 | ||
1062 | size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS; | 1076 | size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS; |
1063 | tx_ring->exp_bufs = dma_zalloc_coherent(dev, size, | 1077 | exp_bufs = dmam_alloc_coherent(dev, size, &dma_exp_bufs, |
1064 | &dma_exp_bufs, | 1078 | GFP_KERNEL | __GFP_ZERO); |
1065 | GFP_KERNEL); | 1079 | if (!exp_bufs) { |
1066 | if (!tx_ring->exp_bufs) { | ||
1067 | ret = -ENOMEM; | 1080 | ret = -ENOMEM; |
1068 | goto err; | 1081 | goto err; |
1069 | } | 1082 | } |
1083 | tx_ring->exp_bufs = exp_bufs; | ||
1070 | 1084 | ||
1071 | pdata->tx_ring[i] = tx_ring; | 1085 | pdata->tx_ring[i] = tx_ring; |
1072 | 1086 | ||
@@ -1086,8 +1100,6 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) | |||
1086 | 1100 | ||
1087 | cp_ring->irq = pdata->irqs[pdata->rxq_cnt + i]; | 1101 | cp_ring->irq = pdata->irqs[pdata->rxq_cnt + i]; |
1088 | cp_ring->index = i; | 1102 | cp_ring->index = i; |
1089 | snprintf(cp_ring->irq_name, IRQ_ID_SIZE, "%s-txc%d", | ||
1090 | ndev->name, i); | ||
1091 | } | 1103 | } |
1092 | 1104 | ||
1093 | cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots, | 1105 | cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots, |
@@ -1283,6 +1295,23 @@ static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata) | |||
1283 | return 0; | 1295 | return 0; |
1284 | } | 1296 | } |
1285 | 1297 | ||
1298 | static int xgene_enet_check_phy_handle(struct xgene_enet_pdata *pdata) | ||
1299 | { | ||
1300 | int ret; | ||
1301 | |||
1302 | if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) | ||
1303 | return 0; | ||
1304 | |||
1305 | if (!IS_ENABLED(CONFIG_MDIO_XGENE)) | ||
1306 | return 0; | ||
1307 | |||
1308 | ret = xgene_enet_phy_connect(pdata->ndev); | ||
1309 | if (!ret) | ||
1310 | pdata->mdio_driver = true; | ||
1311 | |||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1286 | static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | 1315 | static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) |
1287 | { | 1316 | { |
1288 | struct platform_device *pdev; | 1317 | struct platform_device *pdev; |
@@ -1368,6 +1397,10 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | |||
1368 | if (ret) | 1397 | if (ret) |
1369 | return ret; | 1398 | return ret; |
1370 | 1399 | ||
1400 | ret = xgene_enet_check_phy_handle(pdata); | ||
1401 | if (ret) | ||
1402 | return ret; | ||
1403 | |||
1371 | pdata->clk = devm_clk_get(&pdev->dev, NULL); | 1404 | pdata->clk = devm_clk_get(&pdev->dev, NULL); |
1372 | if (IS_ERR(pdata->clk)) { | 1405 | if (IS_ERR(pdata->clk)) { |
1373 | /* Firmware may have set up the clock already. */ | 1406 | /* Firmware may have set up the clock already. */ |
@@ -1447,6 +1480,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) | |||
1447 | pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); | 1480 | pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); |
1448 | } | 1481 | } |
1449 | 1482 | ||
1483 | pdata->phy_speed = SPEED_UNKNOWN; | ||
1450 | pdata->mac_ops->init(pdata); | 1484 | pdata->mac_ops->init(pdata); |
1451 | 1485 | ||
1452 | return ret; | 1486 | return ret; |
@@ -1556,28 +1590,12 @@ static void xgene_enet_napi_add(struct xgene_enet_pdata *pdata) | |||
1556 | } | 1590 | } |
1557 | } | 1591 | } |
1558 | 1592 | ||
1559 | static void xgene_enet_napi_del(struct xgene_enet_pdata *pdata) | ||
1560 | { | ||
1561 | struct napi_struct *napi; | ||
1562 | int i; | ||
1563 | |||
1564 | for (i = 0; i < pdata->rxq_cnt; i++) { | ||
1565 | napi = &pdata->rx_ring[i]->napi; | ||
1566 | netif_napi_del(napi); | ||
1567 | } | ||
1568 | |||
1569 | for (i = 0; i < pdata->cq_cnt; i++) { | ||
1570 | napi = &pdata->tx_ring[i]->cp_ring->napi; | ||
1571 | netif_napi_del(napi); | ||
1572 | } | ||
1573 | } | ||
1574 | |||
1575 | static int xgene_enet_probe(struct platform_device *pdev) | 1593 | static int xgene_enet_probe(struct platform_device *pdev) |
1576 | { | 1594 | { |
1577 | struct net_device *ndev; | 1595 | struct net_device *ndev; |
1578 | struct xgene_enet_pdata *pdata; | 1596 | struct xgene_enet_pdata *pdata; |
1579 | struct device *dev = &pdev->dev; | 1597 | struct device *dev = &pdev->dev; |
1580 | const struct xgene_mac_ops *mac_ops; | 1598 | void (*link_state)(struct work_struct *); |
1581 | const struct of_device_id *of_id; | 1599 | const struct of_device_id *of_id; |
1582 | int ret; | 1600 | int ret; |
1583 | 1601 | ||
@@ -1635,27 +1653,31 @@ static int xgene_enet_probe(struct platform_device *pdev) | |||
1635 | goto err; | 1653 | goto err; |
1636 | } | 1654 | } |
1637 | 1655 | ||
1638 | ret = register_netdev(ndev); | ||
1639 | if (ret) { | ||
1640 | netdev_err(ndev, "Failed to register netdev\n"); | ||
1641 | goto err; | ||
1642 | } | ||
1643 | |||
1644 | ret = xgene_enet_init_hw(pdata); | 1656 | ret = xgene_enet_init_hw(pdata); |
1645 | if (ret) | 1657 | if (ret) |
1646 | goto err_netdev; | 1658 | goto err_netdev; |
1647 | 1659 | ||
1648 | mac_ops = pdata->mac_ops; | 1660 | link_state = pdata->mac_ops->link_state; |
1649 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { | 1661 | if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { |
1650 | ret = xgene_enet_mdio_config(pdata); | 1662 | INIT_DELAYED_WORK(&pdata->link_work, link_state); |
1651 | if (ret) | 1663 | } else if (!pdata->mdio_driver) { |
1652 | goto err_netdev; | 1664 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) |
1653 | } else { | 1665 | ret = xgene_enet_mdio_config(pdata); |
1654 | INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state); | 1666 | else |
1667 | INIT_DELAYED_WORK(&pdata->link_work, link_state); | ||
1655 | } | 1668 | } |
1669 | if (ret) | ||
1670 | goto err; | ||
1656 | 1671 | ||
1657 | xgene_enet_napi_add(pdata); | 1672 | xgene_enet_napi_add(pdata); |
1673 | ret = register_netdev(ndev); | ||
1674 | if (ret) { | ||
1675 | netdev_err(ndev, "Failed to register netdev\n"); | ||
1676 | goto err; | ||
1677 | } | ||
1678 | |||
1658 | return 0; | 1679 | return 0; |
1680 | |||
1659 | err_netdev: | 1681 | err_netdev: |
1660 | unregister_netdev(ndev); | 1682 | unregister_netdev(ndev); |
1661 | err: | 1683 | err: |
@@ -1673,20 +1695,38 @@ static int xgene_enet_remove(struct platform_device *pdev) | |||
1673 | mac_ops = pdata->mac_ops; | 1695 | mac_ops = pdata->mac_ops; |
1674 | ndev = pdata->ndev; | 1696 | ndev = pdata->ndev; |
1675 | 1697 | ||
1676 | mac_ops->rx_disable(pdata); | 1698 | rtnl_lock(); |
1677 | mac_ops->tx_disable(pdata); | 1699 | if (netif_running(ndev)) |
1700 | dev_close(ndev); | ||
1701 | rtnl_unlock(); | ||
1678 | 1702 | ||
1679 | xgene_enet_napi_del(pdata); | 1703 | if (pdata->mdio_driver) |
1680 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) | 1704 | xgene_enet_phy_disconnect(pdata); |
1705 | else if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) | ||
1681 | xgene_enet_mdio_remove(pdata); | 1706 | xgene_enet_mdio_remove(pdata); |
1707 | |||
1682 | unregister_netdev(ndev); | 1708 | unregister_netdev(ndev); |
1683 | xgene_enet_delete_desc_rings(pdata); | ||
1684 | pdata->port_ops->shutdown(pdata); | 1709 | pdata->port_ops->shutdown(pdata); |
1710 | xgene_enet_delete_desc_rings(pdata); | ||
1685 | free_netdev(ndev); | 1711 | free_netdev(ndev); |
1686 | 1712 | ||
1687 | return 0; | 1713 | return 0; |
1688 | } | 1714 | } |
1689 | 1715 | ||
1716 | static void xgene_enet_shutdown(struct platform_device *pdev) | ||
1717 | { | ||
1718 | struct xgene_enet_pdata *pdata; | ||
1719 | |||
1720 | pdata = platform_get_drvdata(pdev); | ||
1721 | if (!pdata) | ||
1722 | return; | ||
1723 | |||
1724 | if (!pdata->ndev) | ||
1725 | return; | ||
1726 | |||
1727 | xgene_enet_remove(pdev); | ||
1728 | } | ||
1729 | |||
1690 | #ifdef CONFIG_ACPI | 1730 | #ifdef CONFIG_ACPI |
1691 | static const struct acpi_device_id xgene_enet_acpi_match[] = { | 1731 | static const struct acpi_device_id xgene_enet_acpi_match[] = { |
1692 | { "APMC0D05", XGENE_ENET1}, | 1732 | { "APMC0D05", XGENE_ENET1}, |
@@ -1721,6 +1761,7 @@ static struct platform_driver xgene_enet_driver = { | |||
1721 | }, | 1761 | }, |
1722 | .probe = xgene_enet_probe, | 1762 | .probe = xgene_enet_probe, |
1723 | .remove = xgene_enet_remove, | 1763 | .remove = xgene_enet_remove, |
1764 | .shutdown = xgene_enet_shutdown, | ||
1724 | }; | 1765 | }; |
1725 | 1766 | ||
1726 | module_platform_driver(xgene_enet_driver); | 1767 | module_platform_driver(xgene_enet_driver); |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 092fbeccaa20..217546e5714a 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h | |||
@@ -38,6 +38,7 @@ | |||
38 | #include "xgene_enet_hw.h" | 38 | #include "xgene_enet_hw.h" |
39 | #include "xgene_enet_cle.h" | 39 | #include "xgene_enet_cle.h" |
40 | #include "xgene_enet_ring2.h" | 40 | #include "xgene_enet_ring2.h" |
41 | #include "../../../phy/mdio-xgene.h" | ||
41 | 42 | ||
42 | #define XGENE_DRV_VERSION "v1.0" | 43 | #define XGENE_DRV_VERSION "v1.0" |
43 | #define XGENE_ENET_MAX_MTU 1536 | 44 | #define XGENE_ENET_MAX_MTU 1536 |
@@ -140,6 +141,7 @@ struct xgene_mac_ops { | |||
140 | void (*rx_enable)(struct xgene_enet_pdata *pdata); | 141 | void (*rx_enable)(struct xgene_enet_pdata *pdata); |
141 | void (*tx_disable)(struct xgene_enet_pdata *pdata); | 142 | void (*tx_disable)(struct xgene_enet_pdata *pdata); |
142 | void (*rx_disable)(struct xgene_enet_pdata *pdata); | 143 | void (*rx_disable)(struct xgene_enet_pdata *pdata); |
144 | void (*set_speed)(struct xgene_enet_pdata *pdata); | ||
143 | void (*set_mac_addr)(struct xgene_enet_pdata *pdata); | 145 | void (*set_mac_addr)(struct xgene_enet_pdata *pdata); |
144 | void (*set_mss)(struct xgene_enet_pdata *pdata); | 146 | void (*set_mss)(struct xgene_enet_pdata *pdata); |
145 | void (*link_state)(struct work_struct *work); | 147 | void (*link_state)(struct work_struct *work); |
@@ -147,6 +149,8 @@ struct xgene_mac_ops { | |||
147 | 149 | ||
148 | struct xgene_port_ops { | 150 | struct xgene_port_ops { |
149 | int (*reset)(struct xgene_enet_pdata *pdata); | 151 | int (*reset)(struct xgene_enet_pdata *pdata); |
152 | void (*clear)(struct xgene_enet_pdata *pdata, | ||
153 | struct xgene_enet_desc_ring *ring); | ||
150 | void (*cle_bypass)(struct xgene_enet_pdata *pdata, | 154 | void (*cle_bypass)(struct xgene_enet_pdata *pdata, |
151 | u32 dst_ring_num, u16 bufpool_id); | 155 | u32 dst_ring_num, u16 bufpool_id); |
152 | void (*shutdown)(struct xgene_enet_pdata *pdata); | 156 | void (*shutdown)(struct xgene_enet_pdata *pdata); |
@@ -211,6 +215,7 @@ struct xgene_enet_pdata { | |||
211 | u32 mss; | 215 | u32 mss; |
212 | u8 tx_delay; | 216 | u8 tx_delay; |
213 | u8 rx_delay; | 217 | u8 rx_delay; |
218 | bool mdio_driver; | ||
214 | }; | 219 | }; |
215 | 220 | ||
216 | struct xgene_indirect_ctl { | 221 | struct xgene_indirect_ctl { |
@@ -220,34 +225,6 @@ struct xgene_indirect_ctl { | |||
220 | void __iomem *cmd_done; | 225 | void __iomem *cmd_done; |
221 | }; | 226 | }; |
222 | 227 | ||
223 | /* Set the specified value into a bit-field defined by its starting position | ||
224 | * and length within a single u64. | ||
225 | */ | ||
226 | static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) | ||
227 | { | ||
228 | return (val & ((1ULL << len) - 1)) << pos; | ||
229 | } | ||
230 | |||
231 | #define SET_VAL(field, val) \ | ||
232 | xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) | ||
233 | |||
234 | #define SET_BIT(field) \ | ||
235 | xgene_enet_set_field_value(field ## _POS, 1, 1) | ||
236 | |||
237 | /* Get the value from a bit-field defined by its starting position | ||
238 | * and length within the specified u64. | ||
239 | */ | ||
240 | static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) | ||
241 | { | ||
242 | return (src >> pos) & ((1ULL << len) - 1); | ||
243 | } | ||
244 | |||
245 | #define GET_VAL(field, src) \ | ||
246 | xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) | ||
247 | |||
248 | #define GET_BIT(field, src) \ | ||
249 | xgene_enet_get_field_value(field ## _POS, 1, src) | ||
250 | |||
251 | static inline struct device *ndev_to_dev(struct net_device *ndev) | 228 | static inline struct device *ndev_to_dev(struct net_device *ndev) |
252 | { | 229 | { |
253 | return ndev->dev.parent; | 230 | return ndev->dev.parent; |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c index 78475512b683..d12e9cbae820 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) | |||
28 | iowrite32(val, p->eth_csr_addr + offset); | 28 | iowrite32(val, p->eth_csr_addr + offset); |
29 | } | 29 | } |
30 | 30 | ||
31 | static void xgene_enet_wr_clkrst_csr(struct xgene_enet_pdata *p, u32 offset, | ||
32 | u32 val) | ||
33 | { | ||
34 | iowrite32(val, p->base_addr + offset); | ||
35 | } | ||
36 | |||
31 | static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p, | 37 | static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p, |
32 | u32 offset, u32 val) | 38 | u32 offset, u32 val) |
33 | { | 39 | { |
@@ -93,6 +99,11 @@ static u32 xgene_enet_rd_diag_csr(struct xgene_enet_pdata *p, u32 offset) | |||
93 | return ioread32(p->eth_diag_csr_addr + offset); | 99 | return ioread32(p->eth_diag_csr_addr + offset); |
94 | } | 100 | } |
95 | 101 | ||
102 | static u32 xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *p, u32 offset) | ||
103 | { | ||
104 | return ioread32(p->mcx_mac_csr_addr + offset); | ||
105 | } | ||
106 | |||
96 | static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) | 107 | static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) |
97 | { | 108 | { |
98 | u32 rd_data; | 109 | u32 rd_data; |
@@ -132,9 +143,17 @@ static u32 xgene_enet_rd_mac(struct xgene_enet_pdata *p, u32 rd_addr) | |||
132 | static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) | 143 | static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) |
133 | { | 144 | { |
134 | struct net_device *ndev = p->ndev; | 145 | struct net_device *ndev = p->ndev; |
135 | u32 data; | 146 | u32 data, shutdown; |
136 | int i = 0; | 147 | int i = 0; |
137 | 148 | ||
149 | shutdown = xgene_enet_rd_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR); | ||
150 | data = xgene_enet_rd_diag_csr(p, ENET_BLOCK_MEM_RDY_ADDR); | ||
151 | |||
152 | if (!shutdown && data == ~0U) { | ||
153 | netdev_dbg(ndev, "+ ecc_init done, skipping\n"); | ||
154 | return 0; | ||
155 | } | ||
156 | |||
138 | xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0); | 157 | xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0); |
139 | do { | 158 | do { |
140 | usleep_range(100, 110); | 159 | usleep_range(100, 110); |
@@ -230,21 +249,105 @@ static u32 xgene_enet_link_status(struct xgene_enet_pdata *p) | |||
230 | data = xgene_mii_phy_read(p, INT_PHY_ADDR, | 249 | data = xgene_mii_phy_read(p, INT_PHY_ADDR, |
231 | SGMII_BASE_PAGE_ABILITY_ADDR >> 2); | 250 | SGMII_BASE_PAGE_ABILITY_ADDR >> 2); |
232 | 251 | ||
252 | if (LINK_SPEED(data) == PHY_SPEED_1000) | ||
253 | p->phy_speed = SPEED_1000; | ||
254 | else if (LINK_SPEED(data) == PHY_SPEED_100) | ||
255 | p->phy_speed = SPEED_100; | ||
256 | else | ||
257 | p->phy_speed = SPEED_10; | ||
258 | |||
233 | return data & LINK_UP; | 259 | return data & LINK_UP; |
234 | } | 260 | } |
235 | 261 | ||
236 | static void xgene_sgmac_init(struct xgene_enet_pdata *p) | 262 | static void xgene_sgmii_configure(struct xgene_enet_pdata *p) |
237 | { | 263 | { |
238 | u32 data, loop = 10; | 264 | xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, |
239 | u32 offset = p->port_id * 4; | 265 | 0x8000); |
240 | u32 enet_spare_cfg_reg, rsif_config_reg; | 266 | xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x9000); |
241 | u32 cfg_bypass_reg, rx_dv_gate_reg; | 267 | xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); |
242 | 268 | } | |
243 | xgene_sgmac_reset(p); | ||
244 | 269 | ||
245 | /* Enable auto-negotiation */ | 270 | static void xgene_sgmii_tbi_control_reset(struct xgene_enet_pdata *p) |
246 | xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x1000); | 271 | { |
272 | xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, | ||
273 | 0x8000); | ||
247 | xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); | 274 | xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); |
275 | } | ||
276 | |||
277 | static void xgene_sgmii_reset(struct xgene_enet_pdata *p) | ||
278 | { | ||
279 | u32 value; | ||
280 | |||
281 | if (p->phy_speed == SPEED_UNKNOWN) | ||
282 | return; | ||
283 | |||
284 | value = xgene_mii_phy_read(p, INT_PHY_ADDR, | ||
285 | SGMII_BASE_PAGE_ABILITY_ADDR >> 2); | ||
286 | if (!(value & LINK_UP)) | ||
287 | xgene_sgmii_tbi_control_reset(p); | ||
288 | } | ||
289 | |||
290 | static void xgene_sgmac_set_speed(struct xgene_enet_pdata *p) | ||
291 | { | ||
292 | u32 icm0_addr, icm2_addr, debug_addr; | ||
293 | u32 icm0, icm2, intf_ctl; | ||
294 | u32 mc2, value; | ||
295 | |||
296 | xgene_sgmii_reset(p); | ||
297 | |||
298 | if (p->enet_id == XGENE_ENET1) { | ||
299 | icm0_addr = ICM_CONFIG0_REG_0_ADDR + p->port_id * OFFSET_8; | ||
300 | icm2_addr = ICM_CONFIG2_REG_0_ADDR + p->port_id * OFFSET_4; | ||
301 | debug_addr = DEBUG_REG_ADDR; | ||
302 | } else { | ||
303 | icm0_addr = XG_MCX_ICM_CONFIG0_REG_0_ADDR; | ||
304 | icm2_addr = XG_MCX_ICM_CONFIG2_REG_0_ADDR; | ||
305 | debug_addr = XG_DEBUG_REG_ADDR; | ||
306 | } | ||
307 | |||
308 | icm0 = xgene_enet_rd_mcx_csr(p, icm0_addr); | ||
309 | icm2 = xgene_enet_rd_mcx_csr(p, icm2_addr); | ||
310 | mc2 = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); | ||
311 | intf_ctl = xgene_enet_rd_mac(p, INTERFACE_CONTROL_ADDR); | ||
312 | |||
313 | switch (p->phy_speed) { | ||
314 | case SPEED_10: | ||
315 | ENET_INTERFACE_MODE2_SET(&mc2, 1); | ||
316 | intf_ctl &= ~(ENET_LHD_MODE | ENET_GHD_MODE); | ||
317 | CFG_MACMODE_SET(&icm0, 0); | ||
318 | CFG_WAITASYNCRD_SET(&icm2, 500); | ||
319 | break; | ||
320 | case SPEED_100: | ||
321 | ENET_INTERFACE_MODE2_SET(&mc2, 1); | ||
322 | intf_ctl &= ~ENET_GHD_MODE; | ||
323 | intf_ctl |= ENET_LHD_MODE; | ||
324 | CFG_MACMODE_SET(&icm0, 1); | ||
325 | CFG_WAITASYNCRD_SET(&icm2, 80); | ||
326 | break; | ||
327 | default: | ||
328 | ENET_INTERFACE_MODE2_SET(&mc2, 2); | ||
329 | intf_ctl &= ~ENET_LHD_MODE; | ||
330 | intf_ctl |= ENET_GHD_MODE; | ||
331 | CFG_MACMODE_SET(&icm0, 2); | ||
332 | CFG_WAITASYNCRD_SET(&icm2, 16); | ||
333 | value = xgene_enet_rd_csr(p, debug_addr); | ||
334 | value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; | ||
335 | xgene_enet_wr_csr(p, debug_addr, value); | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | mc2 |= FULL_DUPLEX2 | PAD_CRC; | ||
340 | xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, mc2); | ||
341 | xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, intf_ctl); | ||
342 | xgene_enet_wr_mcx_csr(p, icm0_addr, icm0); | ||
343 | xgene_enet_wr_mcx_csr(p, icm2_addr, icm2); | ||
344 | } | ||
345 | |||
346 | static void xgene_sgmii_enable_autoneg(struct xgene_enet_pdata *p) | ||
347 | { | ||
348 | u32 data, loop = 10; | ||
349 | |||
350 | xgene_sgmii_configure(p); | ||
248 | 351 | ||
249 | while (loop--) { | 352 | while (loop--) { |
250 | data = xgene_mii_phy_read(p, INT_PHY_ADDR, | 353 | data = xgene_mii_phy_read(p, INT_PHY_ADDR, |
@@ -255,17 +358,27 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) | |||
255 | } | 358 | } |
256 | if (!(data & AUTO_NEG_COMPLETE) || !(data & LINK_STATUS)) | 359 | if (!(data & AUTO_NEG_COMPLETE) || !(data & LINK_STATUS)) |
257 | netdev_err(p->ndev, "Auto-negotiation failed\n"); | 360 | netdev_err(p->ndev, "Auto-negotiation failed\n"); |
361 | } | ||
362 | |||
363 | static void xgene_sgmac_init(struct xgene_enet_pdata *p) | ||
364 | { | ||
365 | u32 enet_spare_cfg_reg, rsif_config_reg; | ||
366 | u32 cfg_bypass_reg, rx_dv_gate_reg; | ||
367 | u32 data, offset; | ||
258 | 368 | ||
259 | data = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); | 369 | if (!(p->enet_id == XGENE_ENET2 && p->mdio_driver)) |
260 | ENET_INTERFACE_MODE2_SET(&data, 2); | 370 | xgene_sgmac_reset(p); |
261 | xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, data | FULL_DUPLEX2); | 371 | |
262 | xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, ENET_GHD_MODE); | 372 | xgene_sgmii_enable_autoneg(p); |
373 | xgene_sgmac_set_speed(p); | ||
374 | xgene_sgmac_set_mac_addr(p); | ||
263 | 375 | ||
264 | if (p->enet_id == XGENE_ENET1) { | 376 | if (p->enet_id == XGENE_ENET1) { |
265 | enet_spare_cfg_reg = ENET_SPARE_CFG_REG_ADDR; | 377 | enet_spare_cfg_reg = ENET_SPARE_CFG_REG_ADDR; |
266 | rsif_config_reg = RSIF_CONFIG_REG_ADDR; | 378 | rsif_config_reg = RSIF_CONFIG_REG_ADDR; |
267 | cfg_bypass_reg = CFG_BYPASS_ADDR; | 379 | cfg_bypass_reg = CFG_BYPASS_ADDR; |
268 | rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR; | 380 | offset = p->port_id * OFFSET_4; |
381 | rx_dv_gate_reg = SG_RX_DV_GATE_REG_0_ADDR + offset; | ||
269 | } else { | 382 | } else { |
270 | enet_spare_cfg_reg = XG_ENET_SPARE_CFG_REG_ADDR; | 383 | enet_spare_cfg_reg = XG_ENET_SPARE_CFG_REG_ADDR; |
271 | rsif_config_reg = XG_RSIF_CONFIG_REG_ADDR; | 384 | rsif_config_reg = XG_RSIF_CONFIG_REG_ADDR; |
@@ -277,8 +390,6 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) | |||
277 | data |= MPA_IDLE_WITH_QMI_EMPTY; | 390 | data |= MPA_IDLE_WITH_QMI_EMPTY; |
278 | xgene_enet_wr_csr(p, enet_spare_cfg_reg, data); | 391 | xgene_enet_wr_csr(p, enet_spare_cfg_reg, data); |
279 | 392 | ||
280 | xgene_sgmac_set_mac_addr(p); | ||
281 | |||
282 | /* Adjust MDC clock frequency */ | 393 | /* Adjust MDC clock frequency */ |
283 | data = xgene_enet_rd_mac(p, MII_MGMT_CONFIG_ADDR); | 394 | data = xgene_enet_rd_mac(p, MII_MGMT_CONFIG_ADDR); |
284 | MGMT_CLOCK_SEL_SET(&data, 7); | 395 | MGMT_CLOCK_SEL_SET(&data, 7); |
@@ -292,7 +403,7 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p) | |||
292 | /* Bypass traffic gating */ | 403 | /* Bypass traffic gating */ |
293 | xgene_enet_wr_csr(p, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x84); | 404 | xgene_enet_wr_csr(p, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x84); |
294 | xgene_enet_wr_csr(p, cfg_bypass_reg, RESUME_TX); | 405 | xgene_enet_wr_csr(p, cfg_bypass_reg, RESUME_TX); |
295 | xgene_enet_wr_mcx_csr(p, rx_dv_gate_reg + offset, RESUME_RX0); | 406 | xgene_enet_wr_mcx_csr(p, rx_dv_gate_reg, RESUME_RX0); |
296 | } | 407 | } |
297 | 408 | ||
298 | static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set) | 409 | static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set) |
@@ -331,17 +442,43 @@ static void xgene_sgmac_tx_disable(struct xgene_enet_pdata *p) | |||
331 | 442 | ||
332 | static int xgene_enet_reset(struct xgene_enet_pdata *p) | 443 | static int xgene_enet_reset(struct xgene_enet_pdata *p) |
333 | { | 444 | { |
445 | struct device *dev = &p->pdev->dev; | ||
446 | |||
334 | if (!xgene_ring_mgr_init(p)) | 447 | if (!xgene_ring_mgr_init(p)) |
335 | return -ENODEV; | 448 | return -ENODEV; |
336 | 449 | ||
337 | if (!IS_ERR(p->clk)) { | 450 | if (p->mdio_driver && p->enet_id == XGENE_ENET2) { |
338 | clk_prepare_enable(p->clk); | 451 | xgene_enet_config_ring_if_assoc(p); |
339 | clk_disable_unprepare(p->clk); | 452 | return 0; |
340 | clk_prepare_enable(p->clk); | ||
341 | } | 453 | } |
342 | 454 | ||
343 | xgene_enet_ecc_init(p); | 455 | if (p->enet_id == XGENE_ENET2) |
344 | xgene_enet_config_ring_if_assoc(p); | 456 | xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN); |
457 | |||
458 | if (dev->of_node) { | ||
459 | if (!IS_ERR(p->clk)) { | ||
460 | clk_prepare_enable(p->clk); | ||
461 | udelay(5); | ||
462 | clk_disable_unprepare(p->clk); | ||
463 | udelay(5); | ||
464 | clk_prepare_enable(p->clk); | ||
465 | udelay(5); | ||
466 | } | ||
467 | } else { | ||
468 | #ifdef CONFIG_ACPI | ||
469 | if (acpi_has_method(ACPI_HANDLE(&p->pdev->dev), "_RST")) | ||
470 | acpi_evaluate_object(ACPI_HANDLE(&p->pdev->dev), | ||
471 | "_RST", NULL, NULL); | ||
472 | else if (acpi_has_method(ACPI_HANDLE(&p->pdev->dev), "_INI")) | ||
473 | acpi_evaluate_object(ACPI_HANDLE(&p->pdev->dev), | ||
474 | "_INI", NULL, NULL); | ||
475 | #endif | ||
476 | } | ||
477 | |||
478 | if (!p->port_id) { | ||
479 | xgene_enet_ecc_init(p); | ||
480 | xgene_enet_config_ring_if_assoc(p); | ||
481 | } | ||
345 | 482 | ||
346 | return 0; | 483 | return 0; |
347 | } | 484 | } |
@@ -369,10 +506,53 @@ static void xgene_enet_cle_bypass(struct xgene_enet_pdata *p, | |||
369 | xgene_enet_wr_csr(p, cle_bypass_reg1 + offset, data); | 506 | xgene_enet_wr_csr(p, cle_bypass_reg1 + offset, data); |
370 | } | 507 | } |
371 | 508 | ||
509 | static void xgene_enet_clear(struct xgene_enet_pdata *pdata, | ||
510 | struct xgene_enet_desc_ring *ring) | ||
511 | { | ||
512 | u32 addr, val, data; | ||
513 | |||
514 | val = xgene_enet_ring_bufnum(ring->id); | ||
515 | |||
516 | if (xgene_enet_is_bufpool(ring->id)) { | ||
517 | addr = ENET_CFGSSQMIFPRESET_ADDR; | ||
518 | data = BIT(val - 0x20); | ||
519 | } else { | ||
520 | addr = ENET_CFGSSQMIWQRESET_ADDR; | ||
521 | data = BIT(val); | ||
522 | } | ||
523 | |||
524 | xgene_enet_wr_ring_if(pdata, addr, data); | ||
525 | } | ||
526 | |||
372 | static void xgene_enet_shutdown(struct xgene_enet_pdata *p) | 527 | static void xgene_enet_shutdown(struct xgene_enet_pdata *p) |
373 | { | 528 | { |
374 | if (!IS_ERR(p->clk)) | 529 | struct device *dev = &p->pdev->dev; |
375 | clk_disable_unprepare(p->clk); | 530 | struct xgene_enet_desc_ring *ring; |
531 | u32 pb, val; | ||
532 | int i; | ||
533 | |||
534 | pb = 0; | ||
535 | for (i = 0; i < p->rxq_cnt; i++) { | ||
536 | ring = p->rx_ring[i]->buf_pool; | ||
537 | |||
538 | val = xgene_enet_ring_bufnum(ring->id); | ||
539 | pb |= BIT(val - 0x20); | ||
540 | } | ||
541 | xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPRESET_ADDR, pb); | ||
542 | |||
543 | pb = 0; | ||
544 | for (i = 0; i < p->txq_cnt; i++) { | ||
545 | ring = p->tx_ring[i]; | ||
546 | |||
547 | val = xgene_enet_ring_bufnum(ring->id); | ||
548 | pb |= BIT(val); | ||
549 | } | ||
550 | xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb); | ||
551 | |||
552 | if (dev->of_node) { | ||
553 | if (!IS_ERR(p->clk)) | ||
554 | clk_disable_unprepare(p->clk); | ||
555 | } | ||
376 | } | 556 | } |
377 | 557 | ||
378 | static void xgene_enet_link_state(struct work_struct *work) | 558 | static void xgene_enet_link_state(struct work_struct *work) |
@@ -386,10 +566,11 @@ static void xgene_enet_link_state(struct work_struct *work) | |||
386 | if (link) { | 566 | if (link) { |
387 | if (!netif_carrier_ok(ndev)) { | 567 | if (!netif_carrier_ok(ndev)) { |
388 | netif_carrier_on(ndev); | 568 | netif_carrier_on(ndev); |
389 | xgene_sgmac_init(p); | 569 | xgene_sgmac_set_speed(p); |
390 | xgene_sgmac_rx_enable(p); | 570 | xgene_sgmac_rx_enable(p); |
391 | xgene_sgmac_tx_enable(p); | 571 | xgene_sgmac_tx_enable(p); |
392 | netdev_info(ndev, "Link is Up - 1Gbps\n"); | 572 | netdev_info(ndev, "Link is Up - %dMbps\n", |
573 | p->phy_speed); | ||
393 | } | 574 | } |
394 | poll_interval = PHY_POLL_LINK_ON; | 575 | poll_interval = PHY_POLL_LINK_ON; |
395 | } else { | 576 | } else { |
@@ -412,12 +593,14 @@ const struct xgene_mac_ops xgene_sgmac_ops = { | |||
412 | .tx_enable = xgene_sgmac_tx_enable, | 593 | .tx_enable = xgene_sgmac_tx_enable, |
413 | .rx_disable = xgene_sgmac_rx_disable, | 594 | .rx_disable = xgene_sgmac_rx_disable, |
414 | .tx_disable = xgene_sgmac_tx_disable, | 595 | .tx_disable = xgene_sgmac_tx_disable, |
596 | .set_speed = xgene_sgmac_set_speed, | ||
415 | .set_mac_addr = xgene_sgmac_set_mac_addr, | 597 | .set_mac_addr = xgene_sgmac_set_mac_addr, |
416 | .link_state = xgene_enet_link_state | 598 | .link_state = xgene_enet_link_state |
417 | }; | 599 | }; |
418 | 600 | ||
419 | const struct xgene_port_ops xgene_sgport_ops = { | 601 | const struct xgene_port_ops xgene_sgport_ops = { |
420 | .reset = xgene_enet_reset, | 602 | .reset = xgene_enet_reset, |
603 | .clear = xgene_enet_clear, | ||
421 | .cle_bypass = xgene_enet_cle_bypass, | 604 | .cle_bypass = xgene_enet_cle_bypass, |
422 | .shutdown = xgene_enet_shutdown | 605 | .shutdown = xgene_enet_shutdown |
423 | }; | 606 | }; |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h index 002df5a6756e..3d0ba374491b 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 @@ | |||
24 | #define PHY_ADDR(src) (((src)<<8) & GENMASK(12, 8)) | 24 | #define PHY_ADDR(src) (((src)<<8) & GENMASK(12, 8)) |
25 | #define REG_ADDR(src) ((src) & GENMASK(4, 0)) | 25 | #define REG_ADDR(src) ((src) & GENMASK(4, 0)) |
26 | #define PHY_CONTROL(src) ((src) & GENMASK(15, 0)) | 26 | #define PHY_CONTROL(src) ((src) & GENMASK(15, 0)) |
27 | #define LINK_SPEED(src) (((src) & GENMASK(11, 10)) >> 10) | ||
27 | #define INT_PHY_ADDR 0x1e | 28 | #define INT_PHY_ADDR 0x1e |
28 | #define SGMII_TBI_CONTROL_ADDR 0x44 | 29 | #define SGMII_TBI_CONTROL_ADDR 0x44 |
29 | #define SGMII_CONTROL_ADDR 0x00 | 30 | #define SGMII_CONTROL_ADDR 0x00 |
@@ -34,6 +35,13 @@ | |||
34 | #define LINK_UP BIT(15) | 35 | #define LINK_UP BIT(15) |
35 | #define MPA_IDLE_WITH_QMI_EMPTY BIT(12) | 36 | #define MPA_IDLE_WITH_QMI_EMPTY BIT(12) |
36 | #define SG_RX_DV_GATE_REG_0_ADDR 0x05fc | 37 | #define SG_RX_DV_GATE_REG_0_ADDR 0x05fc |
38 | #define SGMII_EN 0x1 | ||
39 | |||
40 | enum xgene_phy_speed { | ||
41 | PHY_SPEED_10, | ||
42 | PHY_SPEED_100, | ||
43 | PHY_SPEED_1000 | ||
44 | }; | ||
37 | 45 | ||
38 | extern const struct xgene_mac_ops xgene_sgmac_ops; | 46 | extern const struct xgene_mac_ops xgene_sgmac_ops; |
39 | extern const struct xgene_port_ops xgene_sgport_ops; | 47 | extern const struct xgene_port_ops xgene_sgport_ops; |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index ba030dc1940b..9c6ad0dce00f 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | |||
@@ -258,13 +258,29 @@ static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) | |||
258 | 258 | ||
259 | static int xgene_enet_reset(struct xgene_enet_pdata *pdata) | 259 | static int xgene_enet_reset(struct xgene_enet_pdata *pdata) |
260 | { | 260 | { |
261 | struct device *dev = &pdata->pdev->dev; | ||
262 | |||
261 | if (!xgene_ring_mgr_init(pdata)) | 263 | if (!xgene_ring_mgr_init(pdata)) |
262 | return -ENODEV; | 264 | return -ENODEV; |
263 | 265 | ||
264 | if (!IS_ERR(pdata->clk)) { | 266 | if (dev->of_node) { |
265 | clk_prepare_enable(pdata->clk); | 267 | clk_prepare_enable(pdata->clk); |
268 | udelay(5); | ||
266 | clk_disable_unprepare(pdata->clk); | 269 | clk_disable_unprepare(pdata->clk); |
270 | udelay(5); | ||
267 | clk_prepare_enable(pdata->clk); | 271 | clk_prepare_enable(pdata->clk); |
272 | udelay(5); | ||
273 | } else { | ||
274 | #ifdef CONFIG_ACPI | ||
275 | if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), "_RST")) { | ||
276 | acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev), | ||
277 | "_RST", NULL, NULL); | ||
278 | } else if (acpi_has_method(ACPI_HANDLE(&pdata->pdev->dev), | ||
279 | "_INI")) { | ||
280 | acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev), | ||
281 | "_INI", NULL, NULL); | ||
282 | } | ||
283 | #endif | ||
268 | } | 284 | } |
269 | 285 | ||
270 | xgene_enet_ecc_init(pdata); | 286 | xgene_enet_ecc_init(pdata); |
@@ -292,8 +308,51 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, | |||
292 | 308 | ||
293 | static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) | 309 | static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) |
294 | { | 310 | { |
295 | if (!IS_ERR(pdata->clk)) | 311 | struct device *dev = &pdata->pdev->dev; |
296 | clk_disable_unprepare(pdata->clk); | 312 | struct xgene_enet_desc_ring *ring; |
313 | u32 pb, val; | ||
314 | int i; | ||
315 | |||
316 | pb = 0; | ||
317 | for (i = 0; i < pdata->rxq_cnt; i++) { | ||
318 | ring = pdata->rx_ring[i]->buf_pool; | ||
319 | |||
320 | val = xgene_enet_ring_bufnum(ring->id); | ||
321 | pb |= BIT(val - 0x20); | ||
322 | } | ||
323 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb); | ||
324 | |||
325 | pb = 0; | ||
326 | for (i = 0; i < pdata->txq_cnt; i++) { | ||
327 | ring = pdata->tx_ring[i]; | ||
328 | |||
329 | val = xgene_enet_ring_bufnum(ring->id); | ||
330 | pb |= BIT(val); | ||
331 | } | ||
332 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb); | ||
333 | |||
334 | if (dev->of_node) { | ||
335 | if (!IS_ERR(pdata->clk)) | ||
336 | clk_disable_unprepare(pdata->clk); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | static void xgene_enet_clear(struct xgene_enet_pdata *pdata, | ||
341 | struct xgene_enet_desc_ring *ring) | ||
342 | { | ||
343 | u32 addr, val, data; | ||
344 | |||
345 | val = xgene_enet_ring_bufnum(ring->id); | ||
346 | |||
347 | if (xgene_enet_is_bufpool(ring->id)) { | ||
348 | addr = ENET_CFGSSQMIFPRESET_ADDR; | ||
349 | data = BIT(val - 0x20); | ||
350 | } else { | ||
351 | addr = ENET_CFGSSQMIWQRESET_ADDR; | ||
352 | data = BIT(val); | ||
353 | } | ||
354 | |||
355 | xgene_enet_wr_ring_if(pdata, addr, data); | ||
297 | } | 356 | } |
298 | 357 | ||
299 | static void xgene_enet_link_state(struct work_struct *work) | 358 | static void xgene_enet_link_state(struct work_struct *work) |
@@ -340,6 +399,7 @@ const struct xgene_mac_ops xgene_xgmac_ops = { | |||
340 | 399 | ||
341 | const struct xgene_port_ops xgene_xgport_ops = { | 400 | const struct xgene_port_ops xgene_xgport_ops = { |
342 | .reset = xgene_enet_reset, | 401 | .reset = xgene_enet_reset, |
402 | .clear = xgene_enet_clear, | ||
343 | .cle_bypass = xgene_enet_xgcle_bypass, | 403 | .cle_bypass = xgene_enet_xgcle_bypass, |
344 | .shutdown = xgene_enet_shutdown, | 404 | .shutdown = xgene_enet_shutdown, |
345 | }; | 405 | }; |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h index 0a2dca8a1725..f1ea485f916b 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | |||
@@ -65,9 +65,12 @@ | |||
65 | #define XG_CFG_LINK_AGGR_RESUME_0_ADDR 0x0214 | 65 | #define XG_CFG_LINK_AGGR_RESUME_0_ADDR 0x0214 |
66 | #define XG_LINK_STATUS_ADDR 0x0228 | 66 | #define XG_LINK_STATUS_ADDR 0x0228 |
67 | #define XG_TSIF_MSS_REG0_ADDR 0x02a4 | 67 | #define XG_TSIF_MSS_REG0_ADDR 0x02a4 |
68 | #define XG_DEBUG_REG_ADDR 0x0400 | ||
68 | #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c | 69 | #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c |
69 | #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 | 70 | #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 |
70 | #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 | 71 | #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 |
72 | #define XG_MCX_ICM_CONFIG0_REG_0_ADDR 0x00e0 | ||
73 | #define XG_MCX_ICM_CONFIG2_REG_0_ADDR 0x00e8 | ||
71 | 74 | ||
72 | extern const struct xgene_mac_ops xgene_xgmac_ops; | 75 | extern const struct xgene_mac_ops xgene_xgmac_ops; |
73 | extern const struct xgene_port_ops xgene_xgport_ops; | 76 | extern const struct xgene_port_ops xgene_xgport_ops; |
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 1d7b208b1629..47a64342cc16 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig | |||
@@ -301,6 +301,12 @@ config MDIO_HISI_FEMAC | |||
301 | This module provides a driver for the MDIO busses found in the | 301 | This module provides a driver for the MDIO busses found in the |
302 | Hisilicon SoC that have an Fast Ethernet MAC. | 302 | Hisilicon SoC that have an Fast Ethernet MAC. |
303 | 303 | ||
304 | config MDIO_XGENE | ||
305 | tristate "APM X-Gene SoC MDIO bus controller" | ||
306 | help | ||
307 | This module provides a driver for the MDIO busses found in the | ||
308 | APM X-Gene SoC's. | ||
309 | |||
304 | endif # PHYLIB | 310 | endif # PHYLIB |
305 | 311 | ||
306 | config MICREL_KS8995MA | 312 | config MICREL_KS8995MA |
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 19e38a97963a..534dfa74d5a2 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile | |||
@@ -48,3 +48,4 @@ obj-$(CONFIG_MICROCHIP_PHY) += microchip.o | |||
48 | obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o | 48 | obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o |
49 | obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o | 49 | obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o |
50 | obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o | 50 | obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o |
51 | obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o | ||
diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c new file mode 100644 index 000000000000..d94a978024d9 --- /dev/null +++ b/drivers/net/phy/mdio-xgene.c | |||
@@ -0,0 +1,477 @@ | |||
1 | /* Applied Micro X-Gene SoC MDIO Driver | ||
2 | * | ||
3 | * Copyright (c) 2016, Applied Micro Circuits Corporation | ||
4 | * Author: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/acpi.h> | ||
21 | #include <linux/clk.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/efi.h> | ||
24 | #include <linux/if_vlan.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/of_platform.h> | ||
28 | #include <linux/of_net.h> | ||
29 | #include <linux/of_mdio.h> | ||
30 | #include <linux/prefetch.h> | ||
31 | #include <linux/phy.h> | ||
32 | #include <net/ip.h> | ||
33 | #include "mdio-xgene.h" | ||
34 | |||
35 | static bool xgene_mdio_status; | ||
36 | |||
37 | static u32 xgene_enet_rd_mac(void __iomem *base_addr, u32 rd_addr) | ||
38 | { | ||
39 | void __iomem *addr, *rd, *cmd, *cmd_done; | ||
40 | u32 done, rd_data = BUSY_MASK; | ||
41 | u8 wait = 10; | ||
42 | |||
43 | addr = base_addr + MAC_ADDR_REG_OFFSET; | ||
44 | rd = base_addr + MAC_READ_REG_OFFSET; | ||
45 | cmd = base_addr + MAC_COMMAND_REG_OFFSET; | ||
46 | cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET; | ||
47 | |||
48 | iowrite32(rd_addr, addr); | ||
49 | iowrite32(XGENE_ENET_RD_CMD, cmd); | ||
50 | |||
51 | while (wait--) { | ||
52 | done = ioread32(cmd_done); | ||
53 | if (done) | ||
54 | break; | ||
55 | udelay(1); | ||
56 | } | ||
57 | |||
58 | if (!done) | ||
59 | return rd_data; | ||
60 | |||
61 | rd_data = ioread32(rd); | ||
62 | iowrite32(0, cmd); | ||
63 | |||
64 | return rd_data; | ||
65 | } | ||
66 | |||
67 | static void xgene_enet_wr_mac(void __iomem *base_addr, u32 wr_addr, u32 wr_data) | ||
68 | { | ||
69 | void __iomem *addr, *wr, *cmd, *cmd_done; | ||
70 | u8 wait = 10; | ||
71 | u32 done; | ||
72 | |||
73 | addr = base_addr + MAC_ADDR_REG_OFFSET; | ||
74 | wr = base_addr + MAC_WRITE_REG_OFFSET; | ||
75 | cmd = base_addr + MAC_COMMAND_REG_OFFSET; | ||
76 | cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET; | ||
77 | |||
78 | iowrite32(wr_addr, addr); | ||
79 | iowrite32(wr_data, wr); | ||
80 | iowrite32(XGENE_ENET_WR_CMD, cmd); | ||
81 | |||
82 | while (wait--) { | ||
83 | done = ioread32(cmd_done); | ||
84 | if (done) | ||
85 | break; | ||
86 | udelay(1); | ||
87 | } | ||
88 | |||
89 | if (!done) | ||
90 | pr_err("MCX mac write failed, addr: 0x%04x\n", wr_addr); | ||
91 | |||
92 | iowrite32(0, cmd); | ||
93 | } | ||
94 | |||
95 | int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg) | ||
96 | { | ||
97 | void __iomem *addr = (void __iomem *)bus->priv; | ||
98 | u32 data, done; | ||
99 | u8 wait = 10; | ||
100 | |||
101 | data = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); | ||
102 | xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, data); | ||
103 | xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); | ||
104 | do { | ||
105 | usleep_range(5, 10); | ||
106 | done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR); | ||
107 | } while ((done & BUSY_MASK) && wait--); | ||
108 | |||
109 | if (done & BUSY_MASK) { | ||
110 | dev_err(&bus->dev, "MII_MGMT read failed\n"); | ||
111 | return -EBUSY; | ||
112 | } | ||
113 | |||
114 | data = xgene_enet_rd_mac(addr, MII_MGMT_STATUS_ADDR); | ||
115 | xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, 0); | ||
116 | |||
117 | return data; | ||
118 | } | ||
119 | EXPORT_SYMBOL(xgene_mdio_rgmii_read); | ||
120 | |||
121 | int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data) | ||
122 | { | ||
123 | void __iomem *addr = (void __iomem *)bus->priv; | ||
124 | u32 val, done; | ||
125 | u8 wait = 10; | ||
126 | |||
127 | val = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg); | ||
128 | xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, val); | ||
129 | |||
130 | xgene_enet_wr_mac(addr, MII_MGMT_CONTROL_ADDR, data); | ||
131 | do { | ||
132 | usleep_range(5, 10); | ||
133 | done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR); | ||
134 | } while ((done & BUSY_MASK) && wait--); | ||
135 | |||
136 | if (done & BUSY_MASK) { | ||
137 | dev_err(&bus->dev, "MII_MGMT write failed\n"); | ||
138 | return -EBUSY; | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | EXPORT_SYMBOL(xgene_mdio_rgmii_write); | ||
144 | |||
145 | static u32 xgene_menet_rd_diag_csr(struct xgene_mdio_pdata *pdata, u32 offset) | ||
146 | { | ||
147 | return ioread32(pdata->diag_csr_addr + offset); | ||
148 | } | ||
149 | |||
150 | static void xgene_menet_wr_diag_csr(struct xgene_mdio_pdata *pdata, | ||
151 | u32 offset, u32 val) | ||
152 | { | ||
153 | iowrite32(val, pdata->diag_csr_addr + offset); | ||
154 | } | ||
155 | |||
156 | static int xgene_enet_ecc_init(struct xgene_mdio_pdata *pdata) | ||
157 | { | ||
158 | u32 data; | ||
159 | u8 wait = 10; | ||
160 | |||
161 | xgene_menet_wr_diag_csr(pdata, MENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); | ||
162 | do { | ||
163 | usleep_range(100, 110); | ||
164 | data = xgene_menet_rd_diag_csr(pdata, MENET_BLOCK_MEM_RDY_ADDR); | ||
165 | } while ((data != 0xffffffff) && wait--); | ||
166 | |||
167 | if (data != 0xffffffff) { | ||
168 | dev_err(pdata->dev, "Failed to release memory from shutdown\n"); | ||
169 | return -ENODEV; | ||
170 | } | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static void xgene_gmac_reset(struct xgene_mdio_pdata *pdata) | ||
176 | { | ||
177 | xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, SOFT_RESET); | ||
178 | xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, 0); | ||
179 | } | ||
180 | |||
181 | static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata) | ||
182 | { | ||
183 | int ret; | ||
184 | |||
185 | if (pdata->dev->of_node) { | ||
186 | clk_prepare_enable(pdata->clk); | ||
187 | udelay(5); | ||
188 | clk_disable_unprepare(pdata->clk); | ||
189 | udelay(5); | ||
190 | clk_prepare_enable(pdata->clk); | ||
191 | udelay(5); | ||
192 | } else { | ||
193 | #ifdef CONFIG_ACPI | ||
194 | acpi_evaluate_object(ACPI_HANDLE(pdata->dev), | ||
195 | "_RST", NULL, NULL); | ||
196 | #endif | ||
197 | } | ||
198 | |||
199 | ret = xgene_enet_ecc_init(pdata); | ||
200 | if (ret) | ||
201 | return ret; | ||
202 | xgene_gmac_reset(pdata); | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static void xgene_enet_rd_mdio_csr(void __iomem *base_addr, | ||
208 | u32 offset, u32 *val) | ||
209 | { | ||
210 | void __iomem *addr = base_addr + offset; | ||
211 | |||
212 | *val = ioread32(addr); | ||
213 | } | ||
214 | |||
215 | static void xgene_enet_wr_mdio_csr(void __iomem *base_addr, | ||
216 | u32 offset, u32 val) | ||
217 | { | ||
218 | void __iomem *addr = base_addr + offset; | ||
219 | |||
220 | iowrite32(val, addr); | ||
221 | } | ||
222 | |||
223 | static int xgene_xfi_mdio_write(struct mii_bus *bus, int phy_id, | ||
224 | int reg, u16 data) | ||
225 | { | ||
226 | void __iomem *addr = (void __iomem *)bus->priv; | ||
227 | int timeout = 100; | ||
228 | u32 status, val; | ||
229 | |||
230 | val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg) | | ||
231 | SET_VAL(HSTMIIMWRDAT, data); | ||
232 | xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, data); | ||
233 | |||
234 | val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_WRITE); | ||
235 | xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); | ||
236 | |||
237 | do { | ||
238 | usleep_range(5, 10); | ||
239 | xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status); | ||
240 | } while ((status & BUSY_MASK) && timeout--); | ||
241 | |||
242 | xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int xgene_xfi_mdio_read(struct mii_bus *bus, int phy_id, int reg) | ||
248 | { | ||
249 | void __iomem *addr = (void __iomem *)bus->priv; | ||
250 | u32 data, status, val; | ||
251 | int timeout = 100; | ||
252 | |||
253 | val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg); | ||
254 | xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, val); | ||
255 | |||
256 | val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_READ); | ||
257 | xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); | ||
258 | |||
259 | do { | ||
260 | usleep_range(5, 10); | ||
261 | xgene_enet_rd_mdio_csr(addr, MIIM_INDICATOR_ADDR, &status); | ||
262 | } while ((status & BUSY_MASK) && timeout--); | ||
263 | |||
264 | if (status & BUSY_MASK) { | ||
265 | pr_err("XGENET_MII_MGMT write failed\n"); | ||
266 | return -EBUSY; | ||
267 | } | ||
268 | |||
269 | xgene_enet_rd_mdio_csr(addr, MIIMRD_FIELD_ADDR, &data); | ||
270 | xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, 0); | ||
271 | |||
272 | return data; | ||
273 | } | ||
274 | |||
275 | struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr) | ||
276 | { | ||
277 | struct phy_device *phy_dev; | ||
278 | |||
279 | phy_dev = get_phy_device(bus, phy_addr, false); | ||
280 | if (!phy_dev || IS_ERR(phy_dev)) | ||
281 | return NULL; | ||
282 | |||
283 | if (phy_device_register(phy_dev)) | ||
284 | phy_device_free(phy_dev); | ||
285 | |||
286 | return phy_dev; | ||
287 | } | ||
288 | EXPORT_SYMBOL(xgene_enet_phy_register); | ||
289 | |||
290 | #ifdef CONFIG_ACPI | ||
291 | static acpi_status acpi_register_phy(acpi_handle handle, u32 lvl, | ||
292 | void *context, void **ret) | ||
293 | { | ||
294 | struct mii_bus *mdio = context; | ||
295 | struct acpi_device *adev; | ||
296 | struct phy_device *phy_dev; | ||
297 | const union acpi_object *obj; | ||
298 | u32 phy_addr; | ||
299 | |||
300 | if (acpi_bus_get_device(handle, &adev)) | ||
301 | return AE_OK; | ||
302 | |||
303 | if (acpi_dev_get_property(adev, "phy-channel", ACPI_TYPE_INTEGER, &obj)) | ||
304 | return AE_OK; | ||
305 | phy_addr = obj->integer.value; | ||
306 | |||
307 | phy_dev = xgene_enet_phy_register(mdio, phy_addr); | ||
308 | adev->driver_data = phy_dev; | ||
309 | |||
310 | return AE_OK; | ||
311 | } | ||
312 | #endif | ||
313 | |||
314 | static int xgene_mdio_probe(struct platform_device *pdev) | ||
315 | { | ||
316 | struct device *dev = &pdev->dev; | ||
317 | struct mii_bus *mdio_bus; | ||
318 | const struct of_device_id *of_id; | ||
319 | struct resource *res; | ||
320 | struct xgene_mdio_pdata *pdata; | ||
321 | void __iomem *csr_base; | ||
322 | int mdio_id = 0, ret = 0; | ||
323 | |||
324 | of_id = of_match_device(xgene_mdio_of_match, &pdev->dev); | ||
325 | if (of_id) { | ||
326 | mdio_id = (enum xgene_mdio_id)of_id->data; | ||
327 | } else { | ||
328 | #ifdef CONFIG_ACPI | ||
329 | const struct acpi_device_id *acpi_id; | ||
330 | |||
331 | acpi_id = acpi_match_device(xgene_mdio_acpi_match, &pdev->dev); | ||
332 | if (acpi_id) | ||
333 | mdio_id = (enum xgene_mdio_id)acpi_id->driver_data; | ||
334 | #endif | ||
335 | } | ||
336 | |||
337 | if (!mdio_id) | ||
338 | return -ENODEV; | ||
339 | |||
340 | pdata = devm_kzalloc(dev, sizeof(struct xgene_mdio_pdata), GFP_KERNEL); | ||
341 | if (!pdata) | ||
342 | return -ENOMEM; | ||
343 | pdata->mdio_id = mdio_id; | ||
344 | pdata->dev = dev; | ||
345 | |||
346 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
347 | csr_base = devm_ioremap_resource(dev, res); | ||
348 | if (IS_ERR(csr_base)) { | ||
349 | dev_err(dev, "Unable to retrieve mac CSR region\n"); | ||
350 | return PTR_ERR(csr_base); | ||
351 | } | ||
352 | pdata->mac_csr_addr = csr_base; | ||
353 | pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET; | ||
354 | pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET; | ||
355 | |||
356 | if (dev->of_node) { | ||
357 | pdata->clk = devm_clk_get(dev, NULL); | ||
358 | if (IS_ERR(pdata->clk)) { | ||
359 | dev_err(dev, "Unable to retrieve clk\n"); | ||
360 | return PTR_ERR(pdata->clk); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | ret = xgene_mdio_reset(pdata); | ||
365 | if (ret) | ||
366 | return ret; | ||
367 | |||
368 | mdio_bus = mdiobus_alloc(); | ||
369 | if (!mdio_bus) | ||
370 | return -ENOMEM; | ||
371 | |||
372 | mdio_bus->name = "APM X-Gene MDIO bus"; | ||
373 | |||
374 | if (mdio_id == XGENE_MDIO_RGMII) { | ||
375 | mdio_bus->read = xgene_mdio_rgmii_read; | ||
376 | mdio_bus->write = xgene_mdio_rgmii_write; | ||
377 | mdio_bus->priv = (void __force *)pdata->mac_csr_addr; | ||
378 | snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", | ||
379 | "xgene-mii-rgmii"); | ||
380 | } else { | ||
381 | mdio_bus->read = xgene_xfi_mdio_read; | ||
382 | mdio_bus->write = xgene_xfi_mdio_write; | ||
383 | mdio_bus->priv = (void __force *)pdata->mdio_csr_addr; | ||
384 | snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s", | ||
385 | "xgene-mii-xfi"); | ||
386 | } | ||
387 | |||
388 | mdio_bus->parent = dev; | ||
389 | platform_set_drvdata(pdev, pdata); | ||
390 | |||
391 | if (dev->of_node) { | ||
392 | ret = of_mdiobus_register(mdio_bus, dev->of_node); | ||
393 | } else { | ||
394 | #ifdef CONFIG_ACPI | ||
395 | /* Mask out all PHYs from auto probing. */ | ||
396 | mdio_bus->phy_mask = ~0; | ||
397 | ret = mdiobus_register(mdio_bus); | ||
398 | if (ret) | ||
399 | goto out; | ||
400 | |||
401 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_HANDLE(dev), 1, | ||
402 | acpi_register_phy, NULL, mdio_bus, NULL); | ||
403 | #endif | ||
404 | } | ||
405 | |||
406 | if (ret) | ||
407 | goto out; | ||
408 | |||
409 | pdata->mdio_bus = mdio_bus; | ||
410 | xgene_mdio_status = true; | ||
411 | |||
412 | return 0; | ||
413 | |||
414 | out: | ||
415 | mdiobus_free(mdio_bus); | ||
416 | |||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | static int xgene_mdio_remove(struct platform_device *pdev) | ||
421 | { | ||
422 | struct xgene_mdio_pdata *pdata = platform_get_drvdata(pdev); | ||
423 | struct mii_bus *mdio_bus = pdata->mdio_bus; | ||
424 | struct device *dev = &pdev->dev; | ||
425 | |||
426 | mdiobus_unregister(mdio_bus); | ||
427 | mdiobus_free(mdio_bus); | ||
428 | |||
429 | if (dev->of_node) { | ||
430 | if (IS_ERR(pdata->clk)) | ||
431 | clk_disable_unprepare(pdata->clk); | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | #ifdef CONFIG_OF | ||
438 | static const struct of_device_id xgene_mdio_of_match[] = { | ||
439 | { | ||
440 | .compatible = "apm,xgene-mdio-rgmii", | ||
441 | .data = (void *)XGENE_MDIO_RGMII | ||
442 | }, | ||
443 | { | ||
444 | .compatible = "apm,xgene-mdio-xfi", | ||
445 | .data = (void *)XGENE_MDIO_XFI | ||
446 | }, | ||
447 | {}, | ||
448 | }; | ||
449 | |||
450 | MODULE_DEVICE_TABLE(of, xgene_mdio_of_match); | ||
451 | #endif | ||
452 | |||
453 | #ifdef CONFIG_ACPI | ||
454 | static const struct acpi_device_id xgene_mdio_acpi_match[] = { | ||
455 | { "APMC0D65", XGENE_MDIO_RGMII }, | ||
456 | { "APMC0D66", XGENE_MDIO_XFI }, | ||
457 | { } | ||
458 | }; | ||
459 | |||
460 | MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match); | ||
461 | #endif | ||
462 | |||
463 | static struct platform_driver xgene_mdio_driver = { | ||
464 | .driver = { | ||
465 | .name = "xgene-mdio", | ||
466 | .of_match_table = of_match_ptr(xgene_mdio_of_match), | ||
467 | .acpi_match_table = ACPI_PTR(xgene_mdio_acpi_match), | ||
468 | }, | ||
469 | .probe = xgene_mdio_probe, | ||
470 | .remove = xgene_mdio_remove, | ||
471 | }; | ||
472 | |||
473 | module_platform_driver(xgene_mdio_driver); | ||
474 | |||
475 | MODULE_DESCRIPTION("APM X-Gene SoC MDIO driver"); | ||
476 | MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>"); | ||
477 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h new file mode 100644 index 000000000000..354241b53c1d --- /dev/null +++ b/drivers/net/phy/mdio-xgene.h | |||
@@ -0,0 +1,143 @@ | |||
1 | /* Applied Micro X-Gene SoC MDIO Driver | ||
2 | * | ||
3 | * Copyright (c) 2016, Applied Micro Circuits Corporation | ||
4 | * Author: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #ifndef __MDIO_XGENE_H__ | ||
21 | #define __MDIO_XGENE_H__ | ||
22 | |||
23 | #define BLOCK_XG_MDIO_CSR_OFFSET 0x5000 | ||
24 | #define BLOCK_DIAG_CSR_OFFSET 0xd000 | ||
25 | #define XGENET_CONFIG_REG_ADDR 0x20 | ||
26 | |||
27 | #define MAC_ADDR_REG_OFFSET 0x00 | ||
28 | #define MAC_COMMAND_REG_OFFSET 0x04 | ||
29 | #define MAC_WRITE_REG_OFFSET 0x08 | ||
30 | #define MAC_READ_REG_OFFSET 0x0c | ||
31 | #define MAC_COMMAND_DONE_REG_OFFSET 0x10 | ||
32 | |||
33 | #define CLKEN_OFFSET 0x08 | ||
34 | #define SRST_OFFSET 0x00 | ||
35 | |||
36 | #define MENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70 | ||
37 | #define MENET_BLOCK_MEM_RDY_ADDR 0x74 | ||
38 | |||
39 | #define MAC_CONFIG_1_ADDR 0x00 | ||
40 | #define MII_MGMT_COMMAND_ADDR 0x24 | ||
41 | #define MII_MGMT_ADDRESS_ADDR 0x28 | ||
42 | #define MII_MGMT_CONTROL_ADDR 0x2c | ||
43 | #define MII_MGMT_STATUS_ADDR 0x30 | ||
44 | #define MII_MGMT_INDICATORS_ADDR 0x34 | ||
45 | #define SOFT_RESET BIT(31) | ||
46 | |||
47 | #define MII_MGMT_CONFIG_ADDR 0x20 | ||
48 | #define MII_MGMT_COMMAND_ADDR 0x24 | ||
49 | #define MII_MGMT_ADDRESS_ADDR 0x28 | ||
50 | #define MII_MGMT_CONTROL_ADDR 0x2c | ||
51 | #define MII_MGMT_STATUS_ADDR 0x30 | ||
52 | #define MII_MGMT_INDICATORS_ADDR 0x34 | ||
53 | |||
54 | #define MIIM_COMMAND_ADDR 0x20 | ||
55 | #define MIIM_FIELD_ADDR 0x24 | ||
56 | #define MIIM_CONFIGURATION_ADDR 0x28 | ||
57 | #define MIIM_LINKFAILVECTOR_ADDR 0x2c | ||
58 | #define MIIM_INDICATOR_ADDR 0x30 | ||
59 | #define MIIMRD_FIELD_ADDR 0x34 | ||
60 | |||
61 | #define MDIO_CSR_OFFSET 0x5000 | ||
62 | |||
63 | #define REG_ADDR_POS 0 | ||
64 | #define REG_ADDR_LEN 5 | ||
65 | #define PHY_ADDR_POS 8 | ||
66 | #define PHY_ADDR_LEN 5 | ||
67 | |||
68 | #define HSTMIIMWRDAT_POS 0 | ||
69 | #define HSTMIIMWRDAT_LEN 16 | ||
70 | #define HSTPHYADX_POS 23 | ||
71 | #define HSTPHYADX_LEN 5 | ||
72 | #define HSTREGADX_POS 18 | ||
73 | #define HSTREGADX_LEN 5 | ||
74 | #define HSTLDCMD BIT(3) | ||
75 | #define HSTMIIMCMD_POS 0 | ||
76 | #define HSTMIIMCMD_LEN 3 | ||
77 | |||
78 | #define BUSY_MASK BIT(0) | ||
79 | #define READ_CYCLE_MASK BIT(0) | ||
80 | |||
81 | enum xgene_enet_cmd { | ||
82 | XGENE_ENET_WR_CMD = BIT(31), | ||
83 | XGENE_ENET_RD_CMD = BIT(30) | ||
84 | }; | ||
85 | |||
86 | enum { | ||
87 | MIIM_CMD_IDLE, | ||
88 | MIIM_CMD_LEGACY_WRITE, | ||
89 | MIIM_CMD_LEGACY_READ, | ||
90 | }; | ||
91 | |||
92 | enum xgene_mdio_id { | ||
93 | XGENE_MDIO_RGMII = 1, | ||
94 | XGENE_MDIO_XFI | ||
95 | }; | ||
96 | |||
97 | struct xgene_mdio_pdata { | ||
98 | struct clk *clk; | ||
99 | struct device *dev; | ||
100 | void __iomem *mac_csr_addr; | ||
101 | void __iomem *diag_csr_addr; | ||
102 | void __iomem *mdio_csr_addr; | ||
103 | struct mii_bus *mdio_bus; | ||
104 | int mdio_id; | ||
105 | }; | ||
106 | |||
107 | /* Set the specified value into a bit-field defined by its starting position | ||
108 | * and length within a single u64. | ||
109 | */ | ||
110 | static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) | ||
111 | { | ||
112 | return (val & ((1ULL << len) - 1)) << pos; | ||
113 | } | ||
114 | |||
115 | #define SET_VAL(field, val) \ | ||
116 | xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) | ||
117 | |||
118 | #define SET_BIT(field) \ | ||
119 | xgene_enet_set_field_value(field ## _POS, 1, 1) | ||
120 | |||
121 | /* Get the value from a bit-field defined by its starting position | ||
122 | * and length within the specified u64. | ||
123 | */ | ||
124 | static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) | ||
125 | { | ||
126 | return (src >> pos) & ((1ULL << len) - 1); | ||
127 | } | ||
128 | |||
129 | #define GET_VAL(field, src) \ | ||
130 | xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) | ||
131 | |||
132 | #define GET_BIT(field, src) \ | ||
133 | xgene_enet_get_field_value(field ## _POS, 1, src) | ||
134 | |||
135 | static const struct of_device_id xgene_mdio_of_match[]; | ||
136 | #ifdef CONFIG_ACPI | ||
137 | static const struct acpi_device_id xgene_mdio_acpi_match[]; | ||
138 | #endif | ||
139 | int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg); | ||
140 | int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data); | ||
141 | struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr); | ||
142 | |||
143 | #endif /* __MDIO_XGENE_H__ */ | ||