diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/apm/xgene/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 58 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 331 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 57 |
6 files changed, 438 insertions, 30 deletions
diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile index c643e8a0a0dc..589b35247713 100644 --- a/drivers/net/ethernet/apm/xgene/Makefile +++ b/drivers/net/ethernet/apm/xgene/Makefile | |||
@@ -2,5 +2,6 @@ | |||
2 | # Makefile for APM X-Gene Ethernet Driver. | 2 | # Makefile for APM X-Gene Ethernet Driver. |
3 | # | 3 | # |
4 | 4 | ||
5 | xgene-enet-objs := xgene_enet_hw.o xgene_enet_main.o xgene_enet_ethtool.o | 5 | xgene-enet-objs := xgene_enet_hw.o xgene_enet_xgmac.o \ |
6 | xgene_enet_main.o xgene_enet_ethtool.o | ||
6 | obj-$(CONFIG_NET_XGENE) += xgene-enet.o | 7 | obj-$(CONFIG_NET_XGENE) += xgene-enet.o |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 084ac68aed8d..15ec4267779c 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | |||
@@ -42,6 +42,11 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) | |||
42 | return (val & GENMASK(end, start)) >> start; | 42 | return (val & GENMASK(end, start)) >> start; |
43 | } | 43 | } |
44 | 44 | ||
45 | enum xgene_enet_rm { | ||
46 | RM0, | ||
47 | RM3 = 3 | ||
48 | }; | ||
49 | |||
45 | #define CSR_RING_ID 0x0008 | 50 | #define CSR_RING_ID 0x0008 |
46 | #define OVERWRITE BIT(31) | 51 | #define OVERWRITE BIT(31) |
47 | #define IS_BUFFER_POOL BIT(20) | 52 | #define IS_BUFFER_POOL BIT(20) |
@@ -52,7 +57,6 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) | |||
52 | #define CSR_RING_WR_BASE 0x0070 | 57 | #define CSR_RING_WR_BASE 0x0070 |
53 | #define NUM_RING_CONFIG 5 | 58 | #define NUM_RING_CONFIG 5 |
54 | #define BUFPOOL_MODE 3 | 59 | #define BUFPOOL_MODE 3 |
55 | #define RM3 3 | ||
56 | #define INC_DEC_CMD_ADDR 0x002c | 60 | #define INC_DEC_CMD_ADDR 0x002c |
57 | #define UDP_HDR_SIZE 2 | 61 | #define UDP_HDR_SIZE 2 |
58 | #define BUF_LEN_CODE_2K 0x5000 | 62 | #define BUF_LEN_CODE_2K 0x5000 |
@@ -94,11 +98,9 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) | |||
94 | 98 | ||
95 | #define BLOCK_ETH_CSR_OFFSET 0x2000 | 99 | #define BLOCK_ETH_CSR_OFFSET 0x2000 |
96 | #define BLOCK_ETH_RING_IF_OFFSET 0x9000 | 100 | #define BLOCK_ETH_RING_IF_OFFSET 0x9000 |
97 | #define BLOCK_ETH_CLKRST_CSR_OFFSET 0xC000 | ||
98 | #define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 | 101 | #define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 |
99 | 102 | ||
100 | #define BLOCK_ETH_MAC_OFFSET 0x0000 | 103 | #define BLOCK_ETH_MAC_OFFSET 0x0000 |
101 | #define BLOCK_ETH_STATS_OFFSET 0x0014 | ||
102 | #define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 | 104 | #define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 |
103 | 105 | ||
104 | #define MAC_ADDR_REG_OFFSET 0x00 | 106 | #define MAC_ADDR_REG_OFFSET 0x00 |
@@ -107,12 +109,6 @@ static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) | |||
107 | #define MAC_READ_REG_OFFSET 0x0c | 109 | #define MAC_READ_REG_OFFSET 0x0c |
108 | #define MAC_COMMAND_DONE_REG_OFFSET 0x10 | 110 | #define MAC_COMMAND_DONE_REG_OFFSET 0x10 |
109 | 111 | ||
110 | #define STAT_ADDR_REG_OFFSET 0x00 | ||
111 | #define STAT_COMMAND_REG_OFFSET 0x04 | ||
112 | #define STAT_WRITE_REG_OFFSET 0x08 | ||
113 | #define STAT_READ_REG_OFFSET 0x0c | ||
114 | #define STAT_COMMAND_DONE_REG_OFFSET 0x10 | ||
115 | |||
116 | #define MII_MGMT_CONFIG_ADDR 0x20 | 112 | #define MII_MGMT_CONFIG_ADDR 0x20 |
117 | #define MII_MGMT_COMMAND_ADDR 0x24 | 113 | #define MII_MGMT_COMMAND_ADDR 0x24 |
118 | #define MII_MGMT_ADDRESS_ADDR 0x28 | 114 | #define MII_MGMT_ADDRESS_ADDR 0x28 |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index c4326444deaf..9b85239ceedf 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include "xgene_enet_main.h" | 22 | #include "xgene_enet_main.h" |
23 | #include "xgene_enet_hw.h" | 23 | #include "xgene_enet_hw.h" |
24 | #include "xgene_enet_xgmac.h" | ||
24 | 25 | ||
25 | static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) | 26 | static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) |
26 | { | 27 | { |
@@ -390,7 +391,7 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, | |||
390 | } | 391 | } |
391 | } | 392 | } |
392 | 393 | ||
393 | return budget; | 394 | return count; |
394 | } | 395 | } |
395 | 396 | ||
396 | static int xgene_enet_napi(struct napi_struct *napi, const int budget) | 397 | static int xgene_enet_napi(struct napi_struct *napi, const int budget) |
@@ -456,8 +457,10 @@ static int xgene_enet_open(struct net_device *ndev) | |||
456 | return ret; | 457 | return ret; |
457 | napi_enable(&pdata->rx_ring->napi); | 458 | napi_enable(&pdata->rx_ring->napi); |
458 | 459 | ||
459 | if (pdata->phy_dev) | 460 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) |
460 | phy_start(pdata->phy_dev); | 461 | phy_start(pdata->phy_dev); |
462 | else | ||
463 | schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); | ||
461 | 464 | ||
462 | netif_start_queue(ndev); | 465 | netif_start_queue(ndev); |
463 | 466 | ||
@@ -471,8 +474,10 @@ static int xgene_enet_close(struct net_device *ndev) | |||
471 | 474 | ||
472 | netif_stop_queue(ndev); | 475 | netif_stop_queue(ndev); |
473 | 476 | ||
474 | if (pdata->phy_dev) | 477 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) |
475 | phy_stop(pdata->phy_dev); | 478 | phy_stop(pdata->phy_dev); |
479 | else | ||
480 | cancel_delayed_work_sync(&pdata->link_work); | ||
476 | 481 | ||
477 | napi_disable(&pdata->rx_ring->napi); | 482 | napi_disable(&pdata->rx_ring->napi); |
478 | xgene_enet_free_irq(ndev); | 483 | xgene_enet_free_irq(ndev); |
@@ -615,7 +620,6 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( | |||
615 | 620 | ||
616 | ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6); | 621 | ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6); |
617 | ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR; | 622 | ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR; |
618 | pdata->rm = RM3; | ||
619 | ring = xgene_enet_setup_ring(ring); | 623 | ring = xgene_enet_setup_ring(ring); |
620 | netdev_dbg(ndev, "ring info: num=%d size=%d id=%d slots=%d\n", | 624 | netdev_dbg(ndev, "ring info: num=%d size=%d id=%d slots=%d\n", |
621 | ring->num, ring->size, ring->id, ring->slots); | 625 | ring->num, ring->size, ring->id, ring->slots); |
@@ -805,8 +809,13 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | |||
805 | 809 | ||
806 | pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); | 810 | pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); |
807 | if (pdata->phy_mode < 0) { | 811 | if (pdata->phy_mode < 0) { |
808 | dev_err(dev, "Incorrect phy-connection-type in DTS\n"); | 812 | dev_err(dev, "Unable to get phy-connection-type\n"); |
809 | return -EINVAL; | 813 | return pdata->phy_mode; |
814 | } | ||
815 | if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII && | ||
816 | pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { | ||
817 | dev_err(dev, "Incorrect phy-connection-type specified\n"); | ||
818 | return -ENODEV; | ||
810 | } | 819 | } |
811 | 820 | ||
812 | pdata->clk = devm_clk_get(&pdev->dev, NULL); | 821 | pdata->clk = devm_clk_get(&pdev->dev, NULL); |
@@ -821,12 +830,18 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | |||
821 | pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET; | 830 | pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET; |
822 | pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; | 831 | pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; |
823 | pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; | 832 | pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; |
824 | pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; | 833 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { |
825 | pdata->mcx_stats_addr = base_addr + BLOCK_ETH_STATS_OFFSET; | 834 | pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; |
826 | pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; | 835 | pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; |
836 | pdata->rm = RM3; | ||
837 | } else { | ||
838 | pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET; | ||
839 | pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET; | ||
840 | pdata->rm = RM0; | ||
841 | } | ||
827 | pdata->rx_buff_cnt = NUM_PKT_BUF; | 842 | pdata->rx_buff_cnt = NUM_PKT_BUF; |
828 | 843 | ||
829 | return ret; | 844 | return 0; |
830 | } | 845 | } |
831 | 846 | ||
832 | static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) | 847 | static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) |
@@ -836,8 +851,7 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) | |||
836 | u16 dst_ring_num; | 851 | u16 dst_ring_num; |
837 | int ret; | 852 | int ret; |
838 | 853 | ||
839 | pdata->mac_ops->tx_disable(pdata); | 854 | pdata->port_ops->reset(pdata); |
840 | pdata->mac_ops->rx_disable(pdata); | ||
841 | 855 | ||
842 | ret = xgene_enet_create_desc_rings(ndev); | 856 | ret = xgene_enet_create_desc_rings(ndev); |
843 | if (ret) { | 857 | if (ret) { |
@@ -856,14 +870,23 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) | |||
856 | 870 | ||
857 | dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); | 871 | dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); |
858 | pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); | 872 | pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); |
873 | pdata->mac_ops->init(pdata); | ||
859 | 874 | ||
860 | return ret; | 875 | return ret; |
861 | } | 876 | } |
862 | 877 | ||
863 | static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) | 878 | static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) |
864 | { | 879 | { |
865 | pdata->mac_ops = &xgene_gmac_ops; | 880 | switch (pdata->phy_mode) { |
866 | pdata->port_ops = &xgene_gport_ops; | 881 | case PHY_INTERFACE_MODE_RGMII: |
882 | pdata->mac_ops = &xgene_gmac_ops; | ||
883 | pdata->port_ops = &xgene_gport_ops; | ||
884 | break; | ||
885 | default: | ||
886 | pdata->mac_ops = &xgene_xgmac_ops; | ||
887 | pdata->port_ops = &xgene_xgport_ops; | ||
888 | break; | ||
889 | } | ||
867 | } | 890 | } |
868 | 891 | ||
869 | static int xgene_enet_probe(struct platform_device *pdev) | 892 | static int xgene_enet_probe(struct platform_device *pdev) |
@@ -895,8 +918,6 @@ static int xgene_enet_probe(struct platform_device *pdev) | |||
895 | goto err; | 918 | goto err; |
896 | 919 | ||
897 | xgene_enet_setup_ops(pdata); | 920 | xgene_enet_setup_ops(pdata); |
898 | pdata->port_ops->reset(pdata); | ||
899 | pdata->mac_ops->init(pdata); | ||
900 | 921 | ||
901 | ret = register_netdev(ndev); | 922 | ret = register_netdev(ndev); |
902 | if (ret) { | 923 | if (ret) { |
@@ -916,7 +937,10 @@ static int xgene_enet_probe(struct platform_device *pdev) | |||
916 | 937 | ||
917 | napi = &pdata->rx_ring->napi; | 938 | napi = &pdata->rx_ring->napi; |
918 | netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT); | 939 | netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT); |
919 | ret = xgene_enet_mdio_config(pdata); | 940 | if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) |
941 | ret = xgene_enet_mdio_config(pdata); | ||
942 | else | ||
943 | INIT_DELAYED_WORK(&pdata->link_work, xgene_enet_link_state); | ||
920 | 944 | ||
921 | return ret; | 945 | return ret; |
922 | err: | 946 | err: |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index ac180f980fcd..86cf68b65584 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h | |||
@@ -105,18 +105,17 @@ struct xgene_enet_pdata { | |||
105 | void __iomem *eth_ring_if_addr; | 105 | void __iomem *eth_ring_if_addr; |
106 | void __iomem *eth_diag_csr_addr; | 106 | void __iomem *eth_diag_csr_addr; |
107 | void __iomem *mcx_mac_addr; | 107 | void __iomem *mcx_mac_addr; |
108 | void __iomem *mcx_stats_addr; | ||
109 | void __iomem *mcx_mac_csr_addr; | 108 | void __iomem *mcx_mac_csr_addr; |
110 | void __iomem *base_addr; | 109 | void __iomem *base_addr; |
111 | void __iomem *ring_csr_addr; | 110 | void __iomem *ring_csr_addr; |
112 | void __iomem *ring_cmd_addr; | 111 | void __iomem *ring_cmd_addr; |
113 | u32 phy_addr; | 112 | u32 phy_addr; |
114 | int phy_mode; | 113 | int phy_mode; |
115 | u32 speed; | 114 | enum xgene_enet_rm rm; |
116 | u16 rm; | ||
117 | struct rtnl_link_stats64 stats; | 115 | struct rtnl_link_stats64 stats; |
118 | struct xgene_mac_ops *mac_ops; | 116 | struct xgene_mac_ops *mac_ops; |
119 | struct xgene_port_ops *port_ops; | 117 | struct xgene_port_ops *port_ops; |
118 | struct delayed_work link_work; | ||
120 | }; | 119 | }; |
121 | 120 | ||
122 | /* Set the specified value into a bit-field defined by its starting position | 121 | /* Set the specified value into a bit-field defined by its starting position |
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c new file mode 100644 index 000000000000..cd64b9f18b58 --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | |||
@@ -0,0 +1,331 @@ | |||
1 | /* Applied Micro X-Gene SoC Ethernet Driver | ||
2 | * | ||
3 | * Copyright (c) 2014, Applied Micro Circuits Corporation | ||
4 | * Authors: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * Keyur Chudgar <kchudgar@apm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #include "xgene_enet_main.h" | ||
22 | #include "xgene_enet_hw.h" | ||
23 | #include "xgene_enet_xgmac.h" | ||
24 | |||
25 | static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata, | ||
26 | u32 offset, u32 val) | ||
27 | { | ||
28 | void __iomem *addr = pdata->eth_csr_addr + offset; | ||
29 | |||
30 | iowrite32(val, addr); | ||
31 | } | ||
32 | |||
33 | static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata, | ||
34 | u32 offset, u32 val) | ||
35 | { | ||
36 | void __iomem *addr = pdata->eth_ring_if_addr + offset; | ||
37 | |||
38 | iowrite32(val, addr); | ||
39 | } | ||
40 | |||
41 | static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata, | ||
42 | u32 offset, u32 val) | ||
43 | { | ||
44 | void __iomem *addr = pdata->eth_diag_csr_addr + offset; | ||
45 | |||
46 | iowrite32(val, addr); | ||
47 | } | ||
48 | |||
49 | static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, | ||
50 | void __iomem *cmd, void __iomem *cmd_done, | ||
51 | u32 wr_addr, u32 wr_data) | ||
52 | { | ||
53 | u32 done; | ||
54 | u8 wait = 10; | ||
55 | |||
56 | iowrite32(wr_addr, addr); | ||
57 | iowrite32(wr_data, wr); | ||
58 | iowrite32(XGENE_ENET_WR_CMD, cmd); | ||
59 | |||
60 | /* wait for write command to complete */ | ||
61 | while (!(done = ioread32(cmd_done)) && wait--) | ||
62 | udelay(1); | ||
63 | |||
64 | if (!done) | ||
65 | return false; | ||
66 | |||
67 | iowrite32(0, cmd); | ||
68 | |||
69 | return true; | ||
70 | } | ||
71 | |||
72 | static void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, | ||
73 | u32 wr_addr, u32 wr_data) | ||
74 | { | ||
75 | void __iomem *addr, *wr, *cmd, *cmd_done; | ||
76 | |||
77 | addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; | ||
78 | wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; | ||
79 | cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; | ||
80 | cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; | ||
81 | |||
82 | if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) | ||
83 | netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", | ||
84 | wr_addr); | ||
85 | } | ||
86 | |||
87 | static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata, | ||
88 | u32 offset, u32 *val) | ||
89 | { | ||
90 | void __iomem *addr = pdata->eth_csr_addr + offset; | ||
91 | |||
92 | *val = ioread32(addr); | ||
93 | } | ||
94 | |||
95 | static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata, | ||
96 | u32 offset, u32 *val) | ||
97 | { | ||
98 | void __iomem *addr = pdata->eth_diag_csr_addr + offset; | ||
99 | |||
100 | *val = ioread32(addr); | ||
101 | } | ||
102 | |||
103 | static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, | ||
104 | void __iomem *cmd, void __iomem *cmd_done, | ||
105 | u32 rd_addr, u32 *rd_data) | ||
106 | { | ||
107 | u32 done; | ||
108 | u8 wait = 10; | ||
109 | |||
110 | iowrite32(rd_addr, addr); | ||
111 | iowrite32(XGENE_ENET_RD_CMD, cmd); | ||
112 | |||
113 | /* wait for read command to complete */ | ||
114 | while (!(done = ioread32(cmd_done)) && wait--) | ||
115 | udelay(1); | ||
116 | |||
117 | if (!done) | ||
118 | return false; | ||
119 | |||
120 | *rd_data = ioread32(rd); | ||
121 | iowrite32(0, cmd); | ||
122 | |||
123 | return true; | ||
124 | } | ||
125 | |||
126 | static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, | ||
127 | u32 rd_addr, u32 *rd_data) | ||
128 | { | ||
129 | void __iomem *addr, *rd, *cmd, *cmd_done; | ||
130 | |||
131 | addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; | ||
132 | rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; | ||
133 | cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; | ||
134 | cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; | ||
135 | |||
136 | if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) | ||
137 | netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", | ||
138 | rd_addr); | ||
139 | } | ||
140 | |||
141 | static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) | ||
142 | { | ||
143 | struct net_device *ndev = pdata->ndev; | ||
144 | u32 data; | ||
145 | u8 wait = 10; | ||
146 | |||
147 | xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); | ||
148 | do { | ||
149 | usleep_range(100, 110); | ||
150 | xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data); | ||
151 | } while ((data != 0xffffffff) && wait--); | ||
152 | |||
153 | if (data != 0xffffffff) { | ||
154 | netdev_err(ndev, "Failed to release memory from shutdown\n"); | ||
155 | return -ENODEV; | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) | ||
162 | { | ||
163 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0); | ||
164 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, 0); | ||
165 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, 0); | ||
166 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, 0); | ||
167 | } | ||
168 | |||
169 | static void xgene_xgmac_reset(struct xgene_enet_pdata *pdata) | ||
170 | { | ||
171 | xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, HSTMACRST); | ||
172 | xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, 0); | ||
173 | } | ||
174 | |||
175 | static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata) | ||
176 | { | ||
177 | u32 addr0, addr1; | ||
178 | u8 *dev_addr = pdata->ndev->dev_addr; | ||
179 | |||
180 | addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | | ||
181 | (dev_addr[1] << 8) | dev_addr[0]; | ||
182 | addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); | ||
183 | |||
184 | xgene_enet_wr_mac(pdata, HSTMACADR_LSW_ADDR, addr0); | ||
185 | xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1); | ||
186 | } | ||
187 | |||
188 | static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata) | ||
189 | { | ||
190 | u32 data; | ||
191 | |||
192 | xgene_enet_rd_csr(pdata, XG_LINK_STATUS_ADDR, &data); | ||
193 | |||
194 | return data; | ||
195 | } | ||
196 | |||
197 | static void xgene_xgmac_init(struct xgene_enet_pdata *pdata) | ||
198 | { | ||
199 | u32 data; | ||
200 | |||
201 | xgene_xgmac_reset(pdata); | ||
202 | |||
203 | xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); | ||
204 | data |= HSTPPEN; | ||
205 | data &= ~HSTLENCHK; | ||
206 | xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data); | ||
207 | |||
208 | xgene_enet_wr_mac(pdata, HSTMAXFRAME_LENGTH_ADDR, 0x06000600); | ||
209 | xgene_xgmac_set_mac_addr(pdata); | ||
210 | |||
211 | xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data); | ||
212 | data |= CFG_RSIF_FPBUFF_TIMEOUT_EN; | ||
213 | xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, data); | ||
214 | |||
215 | xgene_enet_wr_csr(pdata, XG_CFG_BYPASS_ADDR, RESUME_TX); | ||
216 | xgene_enet_wr_csr(pdata, XGENET_RX_DV_GATE_REG_0_ADDR, 0); | ||
217 | xgene_enet_rd_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, &data); | ||
218 | data |= BIT(12); | ||
219 | xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, data); | ||
220 | xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x82); | ||
221 | } | ||
222 | |||
223 | static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata) | ||
224 | { | ||
225 | u32 data; | ||
226 | |||
227 | xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); | ||
228 | xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN); | ||
229 | } | ||
230 | |||
231 | static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata) | ||
232 | { | ||
233 | u32 data; | ||
234 | |||
235 | xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); | ||
236 | xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN); | ||
237 | } | ||
238 | |||
239 | static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata) | ||
240 | { | ||
241 | u32 data; | ||
242 | |||
243 | xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); | ||
244 | xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN); | ||
245 | } | ||
246 | |||
247 | static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) | ||
248 | { | ||
249 | u32 data; | ||
250 | |||
251 | xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); | ||
252 | xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN); | ||
253 | } | ||
254 | |||
255 | static void xgene_enet_reset(struct xgene_enet_pdata *pdata) | ||
256 | { | ||
257 | clk_prepare_enable(pdata->clk); | ||
258 | clk_disable_unprepare(pdata->clk); | ||
259 | clk_prepare_enable(pdata->clk); | ||
260 | |||
261 | xgene_enet_ecc_init(pdata); | ||
262 | xgene_enet_config_ring_if_assoc(pdata); | ||
263 | } | ||
264 | |||
265 | static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, | ||
266 | u32 dst_ring_num, u16 bufpool_id) | ||
267 | { | ||
268 | u32 cb, fpsel; | ||
269 | |||
270 | xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG0_ADDR, &cb); | ||
271 | cb |= CFG_CLE_BYPASS_EN0; | ||
272 | CFG_CLE_IP_PROTOCOL0_SET(&cb, 3); | ||
273 | xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG0_ADDR, cb); | ||
274 | |||
275 | fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20; | ||
276 | xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG1_ADDR, &cb); | ||
277 | CFG_CLE_DSTQID0_SET(&cb, dst_ring_num); | ||
278 | CFG_CLE_FPSEL0_SET(&cb, fpsel); | ||
279 | xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG1_ADDR, cb); | ||
280 | } | ||
281 | |||
282 | static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) | ||
283 | { | ||
284 | clk_disable_unprepare(pdata->clk); | ||
285 | } | ||
286 | |||
287 | void xgene_enet_link_state(struct work_struct *work) | ||
288 | { | ||
289 | struct xgene_enet_pdata *pdata = container_of(to_delayed_work(work), | ||
290 | struct xgene_enet_pdata, link_work); | ||
291 | struct net_device *ndev = pdata->ndev; | ||
292 | u32 link_status, poll_interval; | ||
293 | |||
294 | link_status = xgene_enet_link_status(pdata); | ||
295 | if (link_status) { | ||
296 | if (!netif_carrier_ok(ndev)) { | ||
297 | netif_carrier_on(ndev); | ||
298 | xgene_xgmac_init(pdata); | ||
299 | xgene_xgmac_rx_enable(pdata); | ||
300 | xgene_xgmac_tx_enable(pdata); | ||
301 | netdev_info(ndev, "Link is Up - 10Gbps\n"); | ||
302 | } | ||
303 | poll_interval = PHY_POLL_LINK_ON; | ||
304 | } else { | ||
305 | if (netif_carrier_ok(ndev)) { | ||
306 | xgene_xgmac_rx_disable(pdata); | ||
307 | xgene_xgmac_tx_disable(pdata); | ||
308 | netif_carrier_off(ndev); | ||
309 | netdev_info(ndev, "Link is Down\n"); | ||
310 | } | ||
311 | poll_interval = PHY_POLL_LINK_OFF; | ||
312 | } | ||
313 | |||
314 | schedule_delayed_work(&pdata->link_work, poll_interval); | ||
315 | } | ||
316 | |||
317 | struct xgene_mac_ops xgene_xgmac_ops = { | ||
318 | .init = xgene_xgmac_init, | ||
319 | .reset = xgene_xgmac_reset, | ||
320 | .rx_enable = xgene_xgmac_rx_enable, | ||
321 | .tx_enable = xgene_xgmac_tx_enable, | ||
322 | .rx_disable = xgene_xgmac_rx_disable, | ||
323 | .tx_disable = xgene_xgmac_tx_disable, | ||
324 | .set_mac_addr = xgene_xgmac_set_mac_addr, | ||
325 | }; | ||
326 | |||
327 | struct xgene_port_ops xgene_xgport_ops = { | ||
328 | .reset = xgene_enet_reset, | ||
329 | .cle_bypass = xgene_enet_xgcle_bypass, | ||
330 | .shutdown = xgene_enet_shutdown, | ||
331 | }; | ||
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h new file mode 100644 index 000000000000..d2d59e7ed9ab --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* Applied Micro X-Gene SoC Ethernet Driver | ||
2 | * | ||
3 | * Copyright (c) 2014, Applied Micro Circuits Corporation | ||
4 | * Authors: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * Keyur Chudgar <kchudgar@apm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifndef __XGENE_ENET_XGMAC_H__ | ||
22 | #define __XGENE_ENET_XGMAC_H__ | ||
23 | |||
24 | #define BLOCK_AXG_MAC_OFFSET 0x0800 | ||
25 | #define BLOCK_AXG_MAC_CSR_OFFSET 0x2000 | ||
26 | |||
27 | #define AXGMAC_CONFIG_0 0x0000 | ||
28 | #define AXGMAC_CONFIG_1 0x0004 | ||
29 | #define HSTMACRST BIT(31) | ||
30 | #define HSTTCTLEN BIT(31) | ||
31 | #define HSTTFEN BIT(30) | ||
32 | #define HSTRCTLEN BIT(29) | ||
33 | #define HSTRFEN BIT(28) | ||
34 | #define HSTPPEN BIT(7) | ||
35 | #define HSTDRPLT64 BIT(5) | ||
36 | #define HSTLENCHK BIT(3) | ||
37 | #define HSTMACADR_LSW_ADDR 0x0010 | ||
38 | #define HSTMACADR_MSW_ADDR 0x0014 | ||
39 | #define HSTMAXFRAME_LENGTH_ADDR 0x0020 | ||
40 | |||
41 | #define XG_RSIF_CONFIG_REG_ADDR 0x00a0 | ||
42 | #define XCLE_BYPASS_REG0_ADDR 0x0160 | ||
43 | #define XCLE_BYPASS_REG1_ADDR 0x0164 | ||
44 | #define XG_CFG_BYPASS_ADDR 0x0204 | ||
45 | #define XG_LINK_STATUS_ADDR 0x0228 | ||
46 | #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c | ||
47 | #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 | ||
48 | #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 | ||
49 | |||
50 | #define PHY_POLL_LINK_ON (10 * HZ) | ||
51 | #define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5) | ||
52 | |||
53 | void xgene_enet_link_state(struct work_struct *work); | ||
54 | extern struct xgene_mac_ops xgene_xgmac_ops; | ||
55 | extern struct xgene_port_ops xgene_xgport_ops; | ||
56 | |||
57 | #endif /* __XGENE_ENET_XGMAC_H__ */ | ||