11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20148d38dSIyappan Subramanian /* Applied Micro X-Gene SoC Ethernet Driver
30148d38dSIyappan Subramanian *
40148d38dSIyappan Subramanian * Copyright (c) 2014, Applied Micro Circuits Corporation
50148d38dSIyappan Subramanian * Authors: Iyappan Subramanian <isubramanian@apm.com>
60148d38dSIyappan Subramanian * Keyur Chudgar <kchudgar@apm.com>
70148d38dSIyappan Subramanian */
80148d38dSIyappan Subramanian
927ecf87cSIyappan Subramanian #include <linux/of_gpio.h>
1027ecf87cSIyappan Subramanian #include <linux/gpio.h>
110148d38dSIyappan Subramanian #include "xgene_enet_main.h"
120148d38dSIyappan Subramanian #include "xgene_enet_hw.h"
130148d38dSIyappan Subramanian #include "xgene_enet_xgmac.h"
140148d38dSIyappan Subramanian
xgene_enet_wr_csr(struct xgene_enet_pdata * pdata,u32 offset,u32 val)150148d38dSIyappan Subramanian static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata,
160148d38dSIyappan Subramanian u32 offset, u32 val)
170148d38dSIyappan Subramanian {
180148d38dSIyappan Subramanian void __iomem *addr = pdata->eth_csr_addr + offset;
190148d38dSIyappan Subramanian
200148d38dSIyappan Subramanian iowrite32(val, addr);
210148d38dSIyappan Subramanian }
220148d38dSIyappan Subramanian
xgene_enet_wr_ring_if(struct xgene_enet_pdata * pdata,u32 offset,u32 val)230148d38dSIyappan Subramanian static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata,
240148d38dSIyappan Subramanian u32 offset, u32 val)
250148d38dSIyappan Subramanian {
260148d38dSIyappan Subramanian void __iomem *addr = pdata->eth_ring_if_addr + offset;
270148d38dSIyappan Subramanian
280148d38dSIyappan Subramanian iowrite32(val, addr);
290148d38dSIyappan Subramanian }
300148d38dSIyappan Subramanian
xgene_enet_wr_diag_csr(struct xgene_enet_pdata * pdata,u32 offset,u32 val)310148d38dSIyappan Subramanian static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata,
320148d38dSIyappan Subramanian u32 offset, u32 val)
330148d38dSIyappan Subramanian {
340148d38dSIyappan Subramanian void __iomem *addr = pdata->eth_diag_csr_addr + offset;
350148d38dSIyappan Subramanian
360148d38dSIyappan Subramanian iowrite32(val, addr);
370148d38dSIyappan Subramanian }
380148d38dSIyappan Subramanian
xgene_enet_wr_indirect(void __iomem * addr,void __iomem * wr,void __iomem * cmd,void __iomem * cmd_done,u32 wr_addr,u32 wr_data)390148d38dSIyappan Subramanian static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr,
400148d38dSIyappan Subramanian void __iomem *cmd, void __iomem *cmd_done,
410148d38dSIyappan Subramanian u32 wr_addr, u32 wr_data)
420148d38dSIyappan Subramanian {
430148d38dSIyappan Subramanian u32 done;
440148d38dSIyappan Subramanian u8 wait = 10;
450148d38dSIyappan Subramanian
460148d38dSIyappan Subramanian iowrite32(wr_addr, addr);
470148d38dSIyappan Subramanian iowrite32(wr_data, wr);
480148d38dSIyappan Subramanian iowrite32(XGENE_ENET_WR_CMD, cmd);
490148d38dSIyappan Subramanian
500148d38dSIyappan Subramanian /* wait for write command to complete */
510148d38dSIyappan Subramanian while (!(done = ioread32(cmd_done)) && wait--)
520148d38dSIyappan Subramanian udelay(1);
530148d38dSIyappan Subramanian
540148d38dSIyappan Subramanian if (!done)
550148d38dSIyappan Subramanian return false;
560148d38dSIyappan Subramanian
570148d38dSIyappan Subramanian iowrite32(0, cmd);
580148d38dSIyappan Subramanian
590148d38dSIyappan Subramanian return true;
600148d38dSIyappan Subramanian }
610148d38dSIyappan Subramanian
xgene_enet_wr_pcs(struct xgene_enet_pdata * pdata,u32 wr_addr,u32 wr_data)623eb7cb9dSIyappan Subramanian static void xgene_enet_wr_pcs(struct xgene_enet_pdata *pdata,
633eb7cb9dSIyappan Subramanian u32 wr_addr, u32 wr_data)
643eb7cb9dSIyappan Subramanian {
653eb7cb9dSIyappan Subramanian void __iomem *addr, *wr, *cmd, *cmd_done;
663eb7cb9dSIyappan Subramanian
673eb7cb9dSIyappan Subramanian addr = pdata->pcs_addr + PCS_ADDR_REG_OFFSET;
683eb7cb9dSIyappan Subramanian wr = pdata->pcs_addr + PCS_WRITE_REG_OFFSET;
693eb7cb9dSIyappan Subramanian cmd = pdata->pcs_addr + PCS_COMMAND_REG_OFFSET;
703eb7cb9dSIyappan Subramanian cmd_done = pdata->pcs_addr + PCS_COMMAND_DONE_REG_OFFSET;
713eb7cb9dSIyappan Subramanian
723eb7cb9dSIyappan Subramanian if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data))
733eb7cb9dSIyappan Subramanian netdev_err(pdata->ndev, "PCS write failed, addr: %04x\n",
743eb7cb9dSIyappan Subramanian wr_addr);
753eb7cb9dSIyappan Subramanian }
763eb7cb9dSIyappan Subramanian
xgene_enet_wr_axg_csr(struct xgene_enet_pdata * pdata,u32 offset,u32 val)77bb64fa09SIyappan Subramanian static void xgene_enet_wr_axg_csr(struct xgene_enet_pdata *pdata,
78bb64fa09SIyappan Subramanian u32 offset, u32 val)
79bb64fa09SIyappan Subramanian {
80bb64fa09SIyappan Subramanian void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
81bb64fa09SIyappan Subramanian
82bb64fa09SIyappan Subramanian iowrite32(val, addr);
83bb64fa09SIyappan Subramanian }
84bb64fa09SIyappan Subramanian
xgene_enet_rd_csr(struct xgene_enet_pdata * pdata,u32 offset,u32 * val)850148d38dSIyappan Subramanian static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata,
860148d38dSIyappan Subramanian u32 offset, u32 *val)
870148d38dSIyappan Subramanian {
880148d38dSIyappan Subramanian void __iomem *addr = pdata->eth_csr_addr + offset;
890148d38dSIyappan Subramanian
900148d38dSIyappan Subramanian *val = ioread32(addr);
910148d38dSIyappan Subramanian }
920148d38dSIyappan Subramanian
xgene_enet_rd_diag_csr(struct xgene_enet_pdata * pdata,u32 offset,u32 * val)930148d38dSIyappan Subramanian static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata,
940148d38dSIyappan Subramanian u32 offset, u32 *val)
950148d38dSIyappan Subramanian {
960148d38dSIyappan Subramanian void __iomem *addr = pdata->eth_diag_csr_addr + offset;
970148d38dSIyappan Subramanian
980148d38dSIyappan Subramanian *val = ioread32(addr);
990148d38dSIyappan Subramanian }
1000148d38dSIyappan Subramanian
xgene_enet_rd_indirect(void __iomem * addr,void __iomem * rd,void __iomem * cmd,void __iomem * cmd_done,u32 rd_addr,u32 * rd_data)1010148d38dSIyappan Subramanian static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd,
1020148d38dSIyappan Subramanian void __iomem *cmd, void __iomem *cmd_done,
1030148d38dSIyappan Subramanian u32 rd_addr, u32 *rd_data)
1040148d38dSIyappan Subramanian {
1050148d38dSIyappan Subramanian u32 done;
1060148d38dSIyappan Subramanian u8 wait = 10;
1070148d38dSIyappan Subramanian
1080148d38dSIyappan Subramanian iowrite32(rd_addr, addr);
1090148d38dSIyappan Subramanian iowrite32(XGENE_ENET_RD_CMD, cmd);
1100148d38dSIyappan Subramanian
1110148d38dSIyappan Subramanian /* wait for read command to complete */
1120148d38dSIyappan Subramanian while (!(done = ioread32(cmd_done)) && wait--)
1130148d38dSIyappan Subramanian udelay(1);
1140148d38dSIyappan Subramanian
1150148d38dSIyappan Subramanian if (!done)
1160148d38dSIyappan Subramanian return false;
1170148d38dSIyappan Subramanian
1180148d38dSIyappan Subramanian *rd_data = ioread32(rd);
1190148d38dSIyappan Subramanian iowrite32(0, cmd);
1200148d38dSIyappan Subramanian
1210148d38dSIyappan Subramanian return true;
1220148d38dSIyappan Subramanian }
1233eb7cb9dSIyappan Subramanian
xgene_enet_rd_pcs(struct xgene_enet_pdata * pdata,u32 rd_addr,u32 * rd_data)124f9dc7074SArnd Bergmann static bool xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata,
1253eb7cb9dSIyappan Subramanian u32 rd_addr, u32 *rd_data)
1263eb7cb9dSIyappan Subramanian {
1273eb7cb9dSIyappan Subramanian void __iomem *addr, *rd, *cmd, *cmd_done;
128f9dc7074SArnd Bergmann bool success;
1293eb7cb9dSIyappan Subramanian
1303eb7cb9dSIyappan Subramanian addr = pdata->pcs_addr + PCS_ADDR_REG_OFFSET;
1313eb7cb9dSIyappan Subramanian rd = pdata->pcs_addr + PCS_READ_REG_OFFSET;
1323eb7cb9dSIyappan Subramanian cmd = pdata->pcs_addr + PCS_COMMAND_REG_OFFSET;
1333eb7cb9dSIyappan Subramanian cmd_done = pdata->pcs_addr + PCS_COMMAND_DONE_REG_OFFSET;
1343eb7cb9dSIyappan Subramanian
135f9dc7074SArnd Bergmann success = xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data);
136f9dc7074SArnd Bergmann if (!success)
1373eb7cb9dSIyappan Subramanian netdev_err(pdata->ndev, "PCS read failed, addr: %04x\n",
1383eb7cb9dSIyappan Subramanian rd_addr);
139f9dc7074SArnd Bergmann
140f9dc7074SArnd Bergmann return success;
1413eb7cb9dSIyappan Subramanian }
1423eb7cb9dSIyappan Subramanian
xgene_enet_rd_axg_csr(struct xgene_enet_pdata * pdata,u32 offset,u32 * val)143bb64fa09SIyappan Subramanian static void xgene_enet_rd_axg_csr(struct xgene_enet_pdata *pdata,
144bb64fa09SIyappan Subramanian u32 offset, u32 *val)
145bb64fa09SIyappan Subramanian {
146bb64fa09SIyappan Subramanian void __iomem *addr = pdata->mcx_mac_csr_addr + offset;
147bb64fa09SIyappan Subramanian
148bb64fa09SIyappan Subramanian *val = ioread32(addr);
149bb64fa09SIyappan Subramanian }
150bb64fa09SIyappan Subramanian
xgene_enet_ecc_init(struct xgene_enet_pdata * pdata)1510148d38dSIyappan Subramanian static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
1520148d38dSIyappan Subramanian {
1530148d38dSIyappan Subramanian struct net_device *ndev = pdata->ndev;
1540148d38dSIyappan Subramanian u32 data;
1550148d38dSIyappan Subramanian u8 wait = 10;
1560148d38dSIyappan Subramanian
1570148d38dSIyappan Subramanian xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0);
1580148d38dSIyappan Subramanian do {
1590148d38dSIyappan Subramanian usleep_range(100, 110);
1600148d38dSIyappan Subramanian xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data);
1610148d38dSIyappan Subramanian } while ((data != 0xffffffff) && wait--);
1620148d38dSIyappan Subramanian
1630148d38dSIyappan Subramanian if (data != 0xffffffff) {
1640148d38dSIyappan Subramanian netdev_err(ndev, "Failed to release memory from shutdown\n");
1650148d38dSIyappan Subramanian return -ENODEV;
1660148d38dSIyappan Subramanian }
1670148d38dSIyappan Subramanian
1680148d38dSIyappan Subramanian return 0;
1690148d38dSIyappan Subramanian }
1700148d38dSIyappan Subramanian
xgene_xgmac_get_drop_cnt(struct xgene_enet_pdata * pdata,u32 * rx,u32 * tx)171ca6d550cSIyappan Subramanian static void xgene_xgmac_get_drop_cnt(struct xgene_enet_pdata *pdata,
172ca6d550cSIyappan Subramanian u32 *rx, u32 *tx)
173ca6d550cSIyappan Subramanian {
174ca6d550cSIyappan Subramanian u32 count;
175ca6d550cSIyappan Subramanian
176ca6d550cSIyappan Subramanian xgene_enet_rd_axg_csr(pdata, XGENET_ICM_ECM_DROP_COUNT_REG0, &count);
177ca6d550cSIyappan Subramanian *rx = ICM_DROP_COUNT(count);
178ca6d550cSIyappan Subramanian *tx = ECM_DROP_COUNT(count);
179a844e7d1SQuan Nguyen /* Errata: 10GE_4 - ICM_ECM_DROP_COUNT not clear-on-read */
180a844e7d1SQuan Nguyen xgene_enet_rd_axg_csr(pdata, XGENET_ECM_CONFIG0_REG_0, &count);
181ca6d550cSIyappan Subramanian }
182ca6d550cSIyappan Subramanian
xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata * pdata)1830148d38dSIyappan Subramanian static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata)
1840148d38dSIyappan Subramanian {
1850148d38dSIyappan Subramanian xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0);
1860148d38dSIyappan Subramanian xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, 0);
1870148d38dSIyappan Subramanian xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, 0);
1880148d38dSIyappan Subramanian xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, 0);
1890148d38dSIyappan Subramanian }
1900148d38dSIyappan Subramanian
xgene_xgmac_reset(struct xgene_enet_pdata * pdata)1910148d38dSIyappan Subramanian static void xgene_xgmac_reset(struct xgene_enet_pdata *pdata)
1920148d38dSIyappan Subramanian {
1930148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, HSTMACRST);
1940148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, 0);
1950148d38dSIyappan Subramanian }
1960148d38dSIyappan Subramanian
xgene_pcs_reset(struct xgene_enet_pdata * pdata)1973eb7cb9dSIyappan Subramanian static void xgene_pcs_reset(struct xgene_enet_pdata *pdata)
1983eb7cb9dSIyappan Subramanian {
1993eb7cb9dSIyappan Subramanian u32 data;
2003eb7cb9dSIyappan Subramanian
201f9dc7074SArnd Bergmann if (!xgene_enet_rd_pcs(pdata, PCS_CONTROL_1, &data))
202f9dc7074SArnd Bergmann return;
203f9dc7074SArnd Bergmann
2043eb7cb9dSIyappan Subramanian xgene_enet_wr_pcs(pdata, PCS_CONTROL_1, data | PCS_CTRL_PCS_RST);
2053eb7cb9dSIyappan Subramanian xgene_enet_wr_pcs(pdata, PCS_CONTROL_1, data & ~PCS_CTRL_PCS_RST);
2063eb7cb9dSIyappan Subramanian }
2073eb7cb9dSIyappan Subramanian
xgene_xgmac_set_mac_addr(struct xgene_enet_pdata * pdata)2080148d38dSIyappan Subramanian static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata)
2090148d38dSIyappan Subramanian {
210*76660757SJakub Kicinski const u8 *dev_addr = pdata->ndev->dev_addr;
2110148d38dSIyappan Subramanian u32 addr0, addr1;
2120148d38dSIyappan Subramanian
2130148d38dSIyappan Subramanian addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
2140148d38dSIyappan Subramanian (dev_addr[1] << 8) | dev_addr[0];
2150148d38dSIyappan Subramanian addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16);
2160148d38dSIyappan Subramanian
2170148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, HSTMACADR_LSW_ADDR, addr0);
2180148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1);
2190148d38dSIyappan Subramanian }
2200148d38dSIyappan Subramanian
xgene_xgmac_set_mss(struct xgene_enet_pdata * pdata,u16 mss,u8 index)221e3978673SIyappan Subramanian static void xgene_xgmac_set_mss(struct xgene_enet_pdata *pdata,
222e3978673SIyappan Subramanian u16 mss, u8 index)
2239b00eb49SIyappan Subramanian {
224e3978673SIyappan Subramanian u8 offset;
225e3978673SIyappan Subramanian u32 data;
226e3978673SIyappan Subramanian
227e3978673SIyappan Subramanian offset = (index < 2) ? 0 : 4;
228e3978673SIyappan Subramanian xgene_enet_rd_csr(pdata, XG_TSIF_MSS_REG0_ADDR + offset, &data);
229e3978673SIyappan Subramanian
230e3978673SIyappan Subramanian if (!(index & 0x1))
231e3978673SIyappan Subramanian data = SET_VAL(TSO_MSS1, data >> TSO_MSS1_POS) |
232e3978673SIyappan Subramanian SET_VAL(TSO_MSS0, mss);
233e3978673SIyappan Subramanian else
234e3978673SIyappan Subramanian data = SET_VAL(TSO_MSS1, mss) | SET_VAL(TSO_MSS0, data);
235e3978673SIyappan Subramanian
236e3978673SIyappan Subramanian xgene_enet_wr_csr(pdata, XG_TSIF_MSS_REG0_ADDR + offset, data);
2379b00eb49SIyappan Subramanian }
2389b00eb49SIyappan Subramanian
xgene_xgmac_set_frame_size(struct xgene_enet_pdata * pdata,int size)239350b4e33SIyappan Subramanian static void xgene_xgmac_set_frame_size(struct xgene_enet_pdata *pdata, int size)
240350b4e33SIyappan Subramanian {
241350b4e33SIyappan Subramanian xgene_enet_wr_mac(pdata, HSTMAXFRAME_LENGTH_ADDR,
242350b4e33SIyappan Subramanian ((((size + 2) >> 2) << 16) | size));
243350b4e33SIyappan Subramanian }
244350b4e33SIyappan Subramanian
xgene_enet_link_status(struct xgene_enet_pdata * pdata)2450148d38dSIyappan Subramanian static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata)
2460148d38dSIyappan Subramanian {
2470148d38dSIyappan Subramanian u32 data;
2480148d38dSIyappan Subramanian
2490148d38dSIyappan Subramanian xgene_enet_rd_csr(pdata, XG_LINK_STATUS_ADDR, &data);
2500148d38dSIyappan Subramanian
2510148d38dSIyappan Subramanian return data;
2520148d38dSIyappan Subramanian }
2530148d38dSIyappan Subramanian
xgene_xgmac_enable_tx_pause(struct xgene_enet_pdata * pdata,bool enable)254bb64fa09SIyappan Subramanian static void xgene_xgmac_enable_tx_pause(struct xgene_enet_pdata *pdata,
255bb64fa09SIyappan Subramanian bool enable)
256bb64fa09SIyappan Subramanian {
257bb64fa09SIyappan Subramanian u32 data;
258bb64fa09SIyappan Subramanian
259bb64fa09SIyappan Subramanian xgene_enet_rd_axg_csr(pdata, XGENET_CSR_ECM_CFG_0_ADDR, &data);
260bb64fa09SIyappan Subramanian
261bb64fa09SIyappan Subramanian if (enable)
262bb64fa09SIyappan Subramanian data |= MULTI_DPF_AUTOCTRL | PAUSE_XON_EN;
263bb64fa09SIyappan Subramanian else
264bb64fa09SIyappan Subramanian data &= ~(MULTI_DPF_AUTOCTRL | PAUSE_XON_EN);
265bb64fa09SIyappan Subramanian
266bb64fa09SIyappan Subramanian xgene_enet_wr_axg_csr(pdata, XGENET_CSR_ECM_CFG_0_ADDR, data);
267bb64fa09SIyappan Subramanian }
268bb64fa09SIyappan Subramanian
xgene_xgmac_flowctl_tx(struct xgene_enet_pdata * pdata,bool enable)269bb64fa09SIyappan Subramanian static void xgene_xgmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable)
270bb64fa09SIyappan Subramanian {
271bb64fa09SIyappan Subramanian u32 data;
272bb64fa09SIyappan Subramanian
273ae1aed95SIyappan Subramanian data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
274bb64fa09SIyappan Subramanian
275bb64fa09SIyappan Subramanian if (enable)
276bb64fa09SIyappan Subramanian data |= HSTTCTLEN;
277bb64fa09SIyappan Subramanian else
278bb64fa09SIyappan Subramanian data &= ~HSTTCTLEN;
279bb64fa09SIyappan Subramanian
280bb64fa09SIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
281bb64fa09SIyappan Subramanian
282bb64fa09SIyappan Subramanian pdata->mac_ops->enable_tx_pause(pdata, enable);
283bb64fa09SIyappan Subramanian }
284bb64fa09SIyappan Subramanian
xgene_xgmac_flowctl_rx(struct xgene_enet_pdata * pdata,bool enable)285bb64fa09SIyappan Subramanian static void xgene_xgmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable)
286bb64fa09SIyappan Subramanian {
287bb64fa09SIyappan Subramanian u32 data;
288bb64fa09SIyappan Subramanian
289ae1aed95SIyappan Subramanian data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
290bb64fa09SIyappan Subramanian
291bb64fa09SIyappan Subramanian if (enable)
292bb64fa09SIyappan Subramanian data |= HSTRCTLEN;
293bb64fa09SIyappan Subramanian else
294bb64fa09SIyappan Subramanian data &= ~HSTRCTLEN;
295bb64fa09SIyappan Subramanian
296bb64fa09SIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
297bb64fa09SIyappan Subramanian }
298bb64fa09SIyappan Subramanian
xgene_xgmac_init(struct xgene_enet_pdata * pdata)2990148d38dSIyappan Subramanian static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
3000148d38dSIyappan Subramanian {
3010148d38dSIyappan Subramanian u32 data;
3020148d38dSIyappan Subramanian
3030148d38dSIyappan Subramanian xgene_xgmac_reset(pdata);
3040148d38dSIyappan Subramanian
305ae1aed95SIyappan Subramanian data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
3060148d38dSIyappan Subramanian data |= HSTPPEN;
3070148d38dSIyappan Subramanian data &= ~HSTLENCHK;
3080148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
3090148d38dSIyappan Subramanian
3100148d38dSIyappan Subramanian xgene_xgmac_set_mac_addr(pdata);
3110148d38dSIyappan Subramanian
3120148d38dSIyappan Subramanian xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data);
3130148d38dSIyappan Subramanian data |= CFG_RSIF_FPBUFF_TIMEOUT_EN;
3147eac928cSQuan Nguyen /* Errata 10GE_1 - FIFO threshold default value incorrect */
3157eac928cSQuan Nguyen RSIF_CLE_BUFF_THRESH_SET(&data, XG_RSIF_CLE_BUFF_THRESH);
3160148d38dSIyappan Subramanian xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, data);
3170148d38dSIyappan Subramanian
3187eac928cSQuan Nguyen /* Errata 10GE_1 - FIFO threshold default value incorrect */
3197eac928cSQuan Nguyen xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG1_REG_ADDR, &data);
3207eac928cSQuan Nguyen RSIF_PLC_CLE_BUFF_THRESH_SET(&data, XG_RSIF_PLC_CLE_BUFF_THRESH);
3217eac928cSQuan Nguyen xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG1_REG_ADDR, data);
3227eac928cSQuan Nguyen
3230148d38dSIyappan Subramanian xgene_enet_rd_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, &data);
3240148d38dSIyappan Subramanian data |= BIT(12);
3250148d38dSIyappan Subramanian xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, data);
3260148d38dSIyappan Subramanian xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x82);
3274f1c8d81SIyappan Subramanian xgene_enet_wr_csr(pdata, XGENET_RX_DV_GATE_REG_0_ADDR, 0);
3284f1c8d81SIyappan Subramanian xgene_enet_wr_csr(pdata, XG_CFG_BYPASS_ADDR, RESUME_TX);
32956090b12SIyappan Subramanian
33056090b12SIyappan Subramanian /* Configure HW pause frame generation */
33156090b12SIyappan Subramanian xgene_enet_rd_axg_csr(pdata, XGENET_CSR_MULTI_DPF0_ADDR, &data);
33256090b12SIyappan Subramanian data = (DEF_QUANTA << 16) | (data & 0xFFFF);
33356090b12SIyappan Subramanian xgene_enet_wr_axg_csr(pdata, XGENET_CSR_MULTI_DPF0_ADDR, data);
33456090b12SIyappan Subramanian
33556090b12SIyappan Subramanian if (pdata->enet_id != XGENE_ENET1) {
33656090b12SIyappan Subramanian xgene_enet_rd_axg_csr(pdata, XGENET_CSR_MULTI_DPF1_ADDR, &data);
33756090b12SIyappan Subramanian data = (NORM_PAUSE_OPCODE << 16) | (data & 0xFFFF);
33856090b12SIyappan Subramanian xgene_enet_wr_axg_csr(pdata, XGENET_CSR_MULTI_DPF1_ADDR, data);
33956090b12SIyappan Subramanian }
34056090b12SIyappan Subramanian
34156090b12SIyappan Subramanian data = (XG_DEF_PAUSE_OFF_THRES << 16) | XG_DEF_PAUSE_THRES;
34256090b12SIyappan Subramanian xgene_enet_wr_csr(pdata, XG_RXBUF_PAUSE_THRESH, data);
34356090b12SIyappan Subramanian
34456090b12SIyappan Subramanian xgene_xgmac_flowctl_tx(pdata, pdata->tx_pause);
34556090b12SIyappan Subramanian xgene_xgmac_flowctl_rx(pdata, pdata->rx_pause);
3460148d38dSIyappan Subramanian }
3470148d38dSIyappan Subramanian
xgene_xgmac_rx_enable(struct xgene_enet_pdata * pdata)3480148d38dSIyappan Subramanian static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata)
3490148d38dSIyappan Subramanian {
3500148d38dSIyappan Subramanian u32 data;
3510148d38dSIyappan Subramanian
352ae1aed95SIyappan Subramanian data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
3530148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN);
3540148d38dSIyappan Subramanian }
3550148d38dSIyappan Subramanian
xgene_xgmac_tx_enable(struct xgene_enet_pdata * pdata)3560148d38dSIyappan Subramanian static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata)
3570148d38dSIyappan Subramanian {
3580148d38dSIyappan Subramanian u32 data;
3590148d38dSIyappan Subramanian
360ae1aed95SIyappan Subramanian data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
3610148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN);
3620148d38dSIyappan Subramanian }
3630148d38dSIyappan Subramanian
xgene_xgmac_rx_disable(struct xgene_enet_pdata * pdata)3640148d38dSIyappan Subramanian static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata)
3650148d38dSIyappan Subramanian {
3660148d38dSIyappan Subramanian u32 data;
3670148d38dSIyappan Subramanian
368ae1aed95SIyappan Subramanian data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
3690148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN);
3700148d38dSIyappan Subramanian }
3710148d38dSIyappan Subramanian
xgene_xgmac_tx_disable(struct xgene_enet_pdata * pdata)3720148d38dSIyappan Subramanian static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata)
3730148d38dSIyappan Subramanian {
3740148d38dSIyappan Subramanian u32 data;
3750148d38dSIyappan Subramanian
376ae1aed95SIyappan Subramanian data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
3770148d38dSIyappan Subramanian xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN);
3780148d38dSIyappan Subramanian }
3790148d38dSIyappan Subramanian
xgene_enet_reset(struct xgene_enet_pdata * pdata)380c3f4465dSIyappan Subramanian static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
3810148d38dSIyappan Subramanian {
382bc61167aSIyappan Subramanian struct device *dev = &pdata->pdev->dev;
383bc61167aSIyappan Subramanian
384c3f4465dSIyappan Subramanian if (!xgene_ring_mgr_init(pdata))
385c3f4465dSIyappan Subramanian return -ENODEV;
386c3f4465dSIyappan Subramanian
387bc61167aSIyappan Subramanian if (dev->of_node) {
3880148d38dSIyappan Subramanian clk_prepare_enable(pdata->clk);
389bc61167aSIyappan Subramanian udelay(5);
3900148d38dSIyappan Subramanian clk_disable_unprepare(pdata->clk);
391bc61167aSIyappan Subramanian udelay(5);
3920148d38dSIyappan Subramanian clk_prepare_enable(pdata->clk);
393bc61167aSIyappan Subramanian udelay(5);
394bc61167aSIyappan Subramanian } else {
395bc61167aSIyappan Subramanian #ifdef CONFIG_ACPI
39685d2c5cdSNathan Chancellor acpi_status status;
39785d2c5cdSNathan Chancellor
398570d785bSKelsey Skunberg status = acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
399bc61167aSIyappan Subramanian "_RST", NULL, NULL);
400570d785bSKelsey Skunberg if (ACPI_FAILURE(status)) {
401bc61167aSIyappan Subramanian acpi_evaluate_object(ACPI_HANDLE(&pdata->pdev->dev),
402bc61167aSIyappan Subramanian "_INI", NULL, NULL);
403bc61167aSIyappan Subramanian }
404bc61167aSIyappan Subramanian #endif
405c2d33bdcSSuman Tripathi }
4060148d38dSIyappan Subramanian
4070148d38dSIyappan Subramanian xgene_enet_ecc_init(pdata);
4080148d38dSIyappan Subramanian xgene_enet_config_ring_if_assoc(pdata);
409c3f4465dSIyappan Subramanian
410c3f4465dSIyappan Subramanian return 0;
4110148d38dSIyappan Subramanian }
4120148d38dSIyappan Subramanian
xgene_enet_xgcle_bypass(struct xgene_enet_pdata * pdata,u32 dst_ring_num,u16 bufpool_id,u16 nxtbufpool_id)4130148d38dSIyappan Subramanian static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata,
414d6d48969SIyappan Subramanian u32 dst_ring_num, u16 bufpool_id,
415d6d48969SIyappan Subramanian u16 nxtbufpool_id)
4160148d38dSIyappan Subramanian {
417d6d48969SIyappan Subramanian u32 cb, fpsel, nxtfpsel;
4180148d38dSIyappan Subramanian
4190148d38dSIyappan Subramanian xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG0_ADDR, &cb);
4200148d38dSIyappan Subramanian cb |= CFG_CLE_BYPASS_EN0;
4210148d38dSIyappan Subramanian CFG_CLE_IP_PROTOCOL0_SET(&cb, 3);
4220148d38dSIyappan Subramanian xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG0_ADDR, cb);
4230148d38dSIyappan Subramanian
4242c839337SIyappan Subramanian fpsel = xgene_enet_get_fpsel(bufpool_id);
425d6d48969SIyappan Subramanian nxtfpsel = xgene_enet_get_fpsel(nxtbufpool_id);
4260148d38dSIyappan Subramanian xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG1_ADDR, &cb);
4270148d38dSIyappan Subramanian CFG_CLE_DSTQID0_SET(&cb, dst_ring_num);
4280148d38dSIyappan Subramanian CFG_CLE_FPSEL0_SET(&cb, fpsel);
429d6d48969SIyappan Subramanian CFG_CLE_NXTFPSEL0_SET(&cb, nxtfpsel);
4300148d38dSIyappan Subramanian xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG1_ADDR, cb);
431a9380b0fSIyappan Subramanian pr_info("+ cle_bypass: fpsel: %d nxtfpsel: %d\n", fpsel, nxtfpsel);
4320148d38dSIyappan Subramanian }
4330148d38dSIyappan Subramanian
xgene_enet_shutdown(struct xgene_enet_pdata * pdata)4340148d38dSIyappan Subramanian static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
4350148d38dSIyappan Subramanian {
436bc61167aSIyappan Subramanian struct device *dev = &pdata->pdev->dev;
437bc61167aSIyappan Subramanian
438bc61167aSIyappan Subramanian if (dev->of_node) {
439bc61167aSIyappan Subramanian if (!IS_ERR(pdata->clk))
440bc61167aSIyappan Subramanian clk_disable_unprepare(pdata->clk);
441bc61167aSIyappan Subramanian }
442cb11c062SIyappan Subramanian }
443cb11c062SIyappan Subramanian
xgene_enet_clear(struct xgene_enet_pdata * pdata,struct xgene_enet_desc_ring * ring)444cb11c062SIyappan Subramanian static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
445cb11c062SIyappan Subramanian struct xgene_enet_desc_ring *ring)
446cb11c062SIyappan Subramanian {
4472c839337SIyappan Subramanian u32 addr, data;
448cb11c062SIyappan Subramanian
449cb11c062SIyappan Subramanian if (xgene_enet_is_bufpool(ring->id)) {
450cb11c062SIyappan Subramanian addr = ENET_CFGSSQMIFPRESET_ADDR;
4512c839337SIyappan Subramanian data = BIT(xgene_enet_get_fpsel(ring->id));
452cb11c062SIyappan Subramanian } else {
453cb11c062SIyappan Subramanian addr = ENET_CFGSSQMIWQRESET_ADDR;
4542c839337SIyappan Subramanian data = BIT(xgene_enet_ring_bufnum(ring->id));
455cb11c062SIyappan Subramanian }
456cb11c062SIyappan Subramanian
457cb11c062SIyappan Subramanian xgene_enet_wr_ring_if(pdata, addr, data);
4580148d38dSIyappan Subramanian }
4590148d38dSIyappan Subramanian
xgene_enet_gpio_lookup(struct xgene_enet_pdata * pdata)460751d6fd1SIyappan Subramanian static int xgene_enet_gpio_lookup(struct xgene_enet_pdata *pdata)
461751d6fd1SIyappan Subramanian {
462751d6fd1SIyappan Subramanian struct device *dev = &pdata->pdev->dev;
463751d6fd1SIyappan Subramanian
464751d6fd1SIyappan Subramanian pdata->sfp_rdy = gpiod_get(dev, "rxlos", GPIOD_IN);
465751d6fd1SIyappan Subramanian if (IS_ERR(pdata->sfp_rdy))
466751d6fd1SIyappan Subramanian pdata->sfp_rdy = gpiod_get(dev, "sfp", GPIOD_IN);
467751d6fd1SIyappan Subramanian
468751d6fd1SIyappan Subramanian if (IS_ERR(pdata->sfp_rdy))
469751d6fd1SIyappan Subramanian return -ENODEV;
470751d6fd1SIyappan Subramanian
471751d6fd1SIyappan Subramanian return 0;
472751d6fd1SIyappan Subramanian }
473751d6fd1SIyappan Subramanian
xgene_enet_link_state(struct work_struct * work)474dc8385f0SIyappan Subramanian static void xgene_enet_link_state(struct work_struct *work)
4750148d38dSIyappan Subramanian {
4760148d38dSIyappan Subramanian struct xgene_enet_pdata *pdata = container_of(to_delayed_work(work),
4770148d38dSIyappan Subramanian struct xgene_enet_pdata, link_work);
4780148d38dSIyappan Subramanian struct net_device *ndev = pdata->ndev;
4790148d38dSIyappan Subramanian u32 link_status, poll_interval;
4800148d38dSIyappan Subramanian
4810148d38dSIyappan Subramanian link_status = xgene_enet_link_status(pdata);
482751d6fd1SIyappan Subramanian if (pdata->sfp_gpio_en && link_status &&
483751d6fd1SIyappan Subramanian (!IS_ERR(pdata->sfp_rdy) || !xgene_enet_gpio_lookup(pdata)) &&
484751d6fd1SIyappan Subramanian !gpiod_get_value(pdata->sfp_rdy))
48527ecf87cSIyappan Subramanian link_status = 0;
48627ecf87cSIyappan Subramanian
4870148d38dSIyappan Subramanian if (link_status) {
4880148d38dSIyappan Subramanian if (!netif_carrier_ok(ndev)) {
4890148d38dSIyappan Subramanian netif_carrier_on(ndev);
4900148d38dSIyappan Subramanian xgene_xgmac_rx_enable(pdata);
4910148d38dSIyappan Subramanian xgene_xgmac_tx_enable(pdata);
4920148d38dSIyappan Subramanian netdev_info(ndev, "Link is Up - 10Gbps\n");
4930148d38dSIyappan Subramanian }
4940148d38dSIyappan Subramanian poll_interval = PHY_POLL_LINK_ON;
4950148d38dSIyappan Subramanian } else {
4960148d38dSIyappan Subramanian if (netif_carrier_ok(ndev)) {
4970148d38dSIyappan Subramanian xgene_xgmac_rx_disable(pdata);
4980148d38dSIyappan Subramanian xgene_xgmac_tx_disable(pdata);
4990148d38dSIyappan Subramanian netif_carrier_off(ndev);
5000148d38dSIyappan Subramanian netdev_info(ndev, "Link is Down\n");
5010148d38dSIyappan Subramanian }
5020148d38dSIyappan Subramanian poll_interval = PHY_POLL_LINK_OFF;
5033eb7cb9dSIyappan Subramanian
5043eb7cb9dSIyappan Subramanian xgene_pcs_reset(pdata);
5050148d38dSIyappan Subramanian }
5060148d38dSIyappan Subramanian
5070148d38dSIyappan Subramanian schedule_delayed_work(&pdata->link_work, poll_interval);
5080148d38dSIyappan Subramanian }
5090148d38dSIyappan Subramanian
5103cdb7309SJulia Lawall const struct xgene_mac_ops xgene_xgmac_ops = {
5110148d38dSIyappan Subramanian .init = xgene_xgmac_init,
5120148d38dSIyappan Subramanian .reset = xgene_xgmac_reset,
5130148d38dSIyappan Subramanian .rx_enable = xgene_xgmac_rx_enable,
5140148d38dSIyappan Subramanian .tx_enable = xgene_xgmac_tx_enable,
5150148d38dSIyappan Subramanian .rx_disable = xgene_xgmac_rx_disable,
5160148d38dSIyappan Subramanian .tx_disable = xgene_xgmac_tx_disable,
5170148d38dSIyappan Subramanian .set_mac_addr = xgene_xgmac_set_mac_addr,
518350b4e33SIyappan Subramanian .set_framesize = xgene_xgmac_set_frame_size,
5199b00eb49SIyappan Subramanian .set_mss = xgene_xgmac_set_mss,
520ca6d550cSIyappan Subramanian .get_drop_cnt = xgene_xgmac_get_drop_cnt,
521bb64fa09SIyappan Subramanian .link_state = xgene_enet_link_state,
522bb64fa09SIyappan Subramanian .enable_tx_pause = xgene_xgmac_enable_tx_pause,
523bb64fa09SIyappan Subramanian .flowctl_rx = xgene_xgmac_flowctl_rx,
524bb64fa09SIyappan Subramanian .flowctl_tx = xgene_xgmac_flowctl_tx
5250148d38dSIyappan Subramanian };
5260148d38dSIyappan Subramanian
5273cdb7309SJulia Lawall const struct xgene_port_ops xgene_xgport_ops = {
5280148d38dSIyappan Subramanian .reset = xgene_enet_reset,
529cb11c062SIyappan Subramanian .clear = xgene_enet_clear,
5300148d38dSIyappan Subramanian .cle_bypass = xgene_enet_xgcle_bypass,
5310148d38dSIyappan Subramanian .shutdown = xgene_enet_shutdown,
5320148d38dSIyappan Subramanian };
533