blob: 9d69c8408dacc614714e74893932957832112191 [file] [log] [blame]
Michal Simek185f7d92012-09-13 20:23:34 +00001/*
2 * (C) Copyright 2011 Michal Simek
3 *
4 * Michal SIMEK <monstr@monstr.eu>
5 *
6 * Based on Xilinx gmac driver:
7 * (C) Copyright 2011 Xilinx
8 *
Wolfgang Denk3765b3e2013-10-07 13:07:26 +02009 * SPDX-License-Identifier: GPL-2.0+
Michal Simek185f7d92012-09-13 20:23:34 +000010 */
11
12#include <common.h>
13#include <net.h>
Michal Simek2fd24892014-04-25 14:17:38 +020014#include <netdev.h>
Michal Simek185f7d92012-09-13 20:23:34 +000015#include <config.h>
Michal Simekf88a6862014-02-24 11:16:30 +010016#include <fdtdec.h>
17#include <libfdt.h>
Michal Simek185f7d92012-09-13 20:23:34 +000018#include <malloc.h>
19#include <asm/io.h>
20#include <phy.h>
21#include <miiphy.h>
22#include <watchdog.h>
Siva Durga Prasad Paladugu96f4f142014-12-06 12:57:53 +053023#include <asm/system.h>
David Andrey01fbf312013-04-05 17:24:24 +020024#include <asm/arch/hardware.h>
Michal Simek80243522012-10-15 14:01:23 +020025#include <asm/arch/sys_proto.h>
Michal Simeke4d23182015-08-17 09:57:46 +020026#include <asm-generic/errno.h>
Michal Simek185f7d92012-09-13 20:23:34 +000027
28#if !defined(CONFIG_PHYLIB)
29# error XILINX_GEM_ETHERNET requires PHYLIB
30#endif
31
32/* Bit/mask specification */
33#define ZYNQ_GEM_PHYMNTNC_OP_MASK 0x40020000 /* operation mask bits */
34#define ZYNQ_GEM_PHYMNTNC_OP_R_MASK 0x20000000 /* read operation */
35#define ZYNQ_GEM_PHYMNTNC_OP_W_MASK 0x10000000 /* write operation */
36#define ZYNQ_GEM_PHYMNTNC_PHYAD_SHIFT_MASK 23 /* Shift bits for PHYAD */
37#define ZYNQ_GEM_PHYMNTNC_PHREG_SHIFT_MASK 18 /* Shift bits for PHREG */
38
39#define ZYNQ_GEM_RXBUF_EOF_MASK 0x00008000 /* End of frame. */
40#define ZYNQ_GEM_RXBUF_SOF_MASK 0x00004000 /* Start of frame. */
41#define ZYNQ_GEM_RXBUF_LEN_MASK 0x00003FFF /* Mask for length field */
42
43#define ZYNQ_GEM_RXBUF_WRAP_MASK 0x00000002 /* Wrap bit, last BD */
44#define ZYNQ_GEM_RXBUF_NEW_MASK 0x00000001 /* Used bit.. */
45#define ZYNQ_GEM_RXBUF_ADD_MASK 0xFFFFFFFC /* Mask for address */
46
47/* Wrap bit, last descriptor */
48#define ZYNQ_GEM_TXBUF_WRAP_MASK 0x40000000
49#define ZYNQ_GEM_TXBUF_LAST_MASK 0x00008000 /* Last buffer */
Michal Simek23a598f2015-08-17 09:58:54 +020050#define ZYNQ_GEM_TXBUF_USED_MASK 0x80000000 /* Used by Hw */
Michal Simek185f7d92012-09-13 20:23:34 +000051
Michal Simek185f7d92012-09-13 20:23:34 +000052#define ZYNQ_GEM_NWCTRL_TXEN_MASK 0x00000008 /* Enable transmit */
53#define ZYNQ_GEM_NWCTRL_RXEN_MASK 0x00000004 /* Enable receive */
54#define ZYNQ_GEM_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */
55#define ZYNQ_GEM_NWCTRL_STARTTX_MASK 0x00000200 /* Start tx (tx_go) */
56
Michal Simek80243522012-10-15 14:01:23 +020057#define ZYNQ_GEM_NWCFG_SPEED100 0x000000001 /* 100 Mbps operation */
58#define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */
59#define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */
60#define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */
Michal Simek185f7d92012-09-13 20:23:34 +000061#define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000080000 /* Div pclk by 32, 80MHz */
Michal Simek80243522012-10-15 14:01:23 +020062#define ZYNQ_GEM_NWCFG_MDCCLKDIV2 0x0000c0000 /* Div pclk by 48, 120MHz */
Michal Simek185f7d92012-09-13 20:23:34 +000063
Siva Durga Prasad Paladugu8a584c82014-07-08 15:31:03 +053064#ifdef CONFIG_ARM64
65# define ZYNQ_GEM_DBUS_WIDTH (1 << 21) /* 64 bit bus */
66#else
67# define ZYNQ_GEM_DBUS_WIDTH (0 << 21) /* 32 bit bus */
68#endif
69
70#define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_DBUS_WIDTH | \
71 ZYNQ_GEM_NWCFG_FDEN | \
Michal Simek185f7d92012-09-13 20:23:34 +000072 ZYNQ_GEM_NWCFG_FSREM | \
73 ZYNQ_GEM_NWCFG_MDCCLKDIV)
74
75#define ZYNQ_GEM_NWSR_MDIOIDLE_MASK 0x00000004 /* PHY management idle */
76
77#define ZYNQ_GEM_DMACR_BLENGTH 0x00000004 /* INCR4 AHB bursts */
78/* Use full configured addressable space (8 Kb) */
79#define ZYNQ_GEM_DMACR_RXSIZE 0x00000300
80/* Use full configured addressable space (4 Kb) */
81#define ZYNQ_GEM_DMACR_TXSIZE 0x00000400
82/* Set with binary 00011000 to use 1536 byte(1*max length frame/buffer) */
83#define ZYNQ_GEM_DMACR_RXBUF 0x00180000
84
85#define ZYNQ_GEM_DMACR_INIT (ZYNQ_GEM_DMACR_BLENGTH | \
86 ZYNQ_GEM_DMACR_RXSIZE | \
87 ZYNQ_GEM_DMACR_TXSIZE | \
88 ZYNQ_GEM_DMACR_RXBUF)
89
Michal Simeke4d23182015-08-17 09:57:46 +020090#define ZYNQ_GEM_TSR_DONE 0x00000020 /* Tx done mask */
91
Michal Simekf97d7e82013-04-22 14:41:09 +020092/* Use MII register 1 (MII status register) to detect PHY */
93#define PHY_DETECT_REG 1
94
95/* Mask used to verify certain PHY features (or register contents)
96 * in the register above:
97 * 0x1000: 10Mbps full duplex support
98 * 0x0800: 10Mbps half duplex support
99 * 0x0008: Auto-negotiation support
100 */
101#define PHY_DETECT_MASK 0x1808
102
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530103/* TX BD status masks */
104#define ZYNQ_GEM_TXBUF_FRMLEN_MASK 0x000007ff
105#define ZYNQ_GEM_TXBUF_EXHAUSTED 0x08000000
106#define ZYNQ_GEM_TXBUF_UNDERRUN 0x10000000
107
Soren Brinkmann97598fc2013-11-21 13:39:01 -0800108/* Clock frequencies for different speeds */
109#define ZYNQ_GEM_FREQUENCY_10 2500000UL
110#define ZYNQ_GEM_FREQUENCY_100 25000000UL
111#define ZYNQ_GEM_FREQUENCY_1000 125000000UL
112
Michal Simek185f7d92012-09-13 20:23:34 +0000113/* Device registers */
114struct zynq_gem_regs {
Michal Simek97a51a02015-10-05 11:49:43 +0200115 u32 nwctrl; /* 0x0 - Network Control reg */
116 u32 nwcfg; /* 0x4 - Network Config reg */
117 u32 nwsr; /* 0x8 - Network Status reg */
Michal Simek185f7d92012-09-13 20:23:34 +0000118 u32 reserved1;
Michal Simek97a51a02015-10-05 11:49:43 +0200119 u32 dmacr; /* 0x10 - DMA Control reg */
120 u32 txsr; /* 0x14 - TX Status reg */
121 u32 rxqbase; /* 0x18 - RX Q Base address reg */
122 u32 txqbase; /* 0x1c - TX Q Base address reg */
123 u32 rxsr; /* 0x20 - RX Status reg */
Michal Simek185f7d92012-09-13 20:23:34 +0000124 u32 reserved2[2];
Michal Simek97a51a02015-10-05 11:49:43 +0200125 u32 idr; /* 0x2c - Interrupt Disable reg */
Michal Simek185f7d92012-09-13 20:23:34 +0000126 u32 reserved3;
Michal Simek97a51a02015-10-05 11:49:43 +0200127 u32 phymntnc; /* 0x34 - Phy Maintaince reg */
Michal Simek185f7d92012-09-13 20:23:34 +0000128 u32 reserved4[18];
Michal Simek97a51a02015-10-05 11:49:43 +0200129 u32 hashl; /* 0x80 - Hash Low address reg */
130 u32 hashh; /* 0x84 - Hash High address reg */
Michal Simek185f7d92012-09-13 20:23:34 +0000131#define LADDR_LOW 0
132#define LADDR_HIGH 1
Michal Simek97a51a02015-10-05 11:49:43 +0200133 u32 laddr[4][LADDR_HIGH + 1]; /* 0x8c - Specific1 addr low/high reg */
134 u32 match[4]; /* 0xa8 - Type ID1 Match reg */
Michal Simek185f7d92012-09-13 20:23:34 +0000135 u32 reserved6[18];
Michal Simek0ebf4042015-10-05 12:49:48 +0200136#define STAT_SIZE 44
137 u32 stat[STAT_SIZE]; /* 0x100 - Octects transmitted Low reg */
Edgar E. Iglesias603ff002015-09-25 23:50:07 -0700138 u32 reserved7[164];
139 u32 transmit_q1_ptr; /* 0x440 - Transmit priority queue 1 */
140 u32 reserved8[15];
141 u32 receive_q1_ptr; /* 0x480 - Receive priority queue 1 */
Michal Simek185f7d92012-09-13 20:23:34 +0000142};
143
144/* BD descriptors */
145struct emac_bd {
146 u32 addr; /* Next descriptor pointer */
147 u32 status;
148};
149
Siva Durga Prasad Paladugueda9d302015-04-15 12:15:01 +0530150#define RX_BUF 32
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530151/* Page table entries are set to 1MB, or multiples of 1MB
152 * (not < 1MB). driver uses less bd's so use 1MB bdspace.
153 */
154#define BD_SPACE 0x100000
155/* BD separation space */
Michal Simekff475872015-08-17 09:45:53 +0200156#define BD_SEPRN_SPACE (RX_BUF * sizeof(struct emac_bd))
Michal Simek185f7d92012-09-13 20:23:34 +0000157
Edgar E. Iglesias603ff002015-09-25 23:50:07 -0700158/* Setup the first free TX descriptor */
159#define TX_FREE_DESC 2
160
Michal Simek185f7d92012-09-13 20:23:34 +0000161/* Initialized, rxbd_current, rx_first_buf must be 0 after init */
162struct zynq_gem_priv {
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530163 struct emac_bd *tx_bd;
164 struct emac_bd *rx_bd;
165 char *rxbuffers;
Michal Simek185f7d92012-09-13 20:23:34 +0000166 u32 rxbd_current;
167 u32 rx_first_buf;
168 int phyaddr;
David Andrey01fbf312013-04-05 17:24:24 +0200169 u32 emio;
Michal Simek05868752013-01-24 13:04:12 +0100170 int init;
Michal Simek16ce6de2015-10-07 16:42:56 +0200171 phy_interface_t interface;
Michal Simek185f7d92012-09-13 20:23:34 +0000172 struct phy_device *phydev;
173 struct mii_dev *bus;
174};
175
176static inline int mdio_wait(struct eth_device *dev)
177{
178 struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
Michal Simek4c8b7bf2012-10-16 17:37:11 +0200179 u32 timeout = 20000;
Michal Simek185f7d92012-09-13 20:23:34 +0000180
181 /* Wait till MDIO interface is ready to accept a new transaction. */
182 while (--timeout) {
183 if (readl(&regs->nwsr) & ZYNQ_GEM_NWSR_MDIOIDLE_MASK)
184 break;
185 WATCHDOG_RESET();
186 }
187
188 if (!timeout) {
189 printf("%s: Timeout\n", __func__);
190 return 1;
191 }
192
193 return 0;
194}
195
196static u32 phy_setup_op(struct eth_device *dev, u32 phy_addr, u32 regnum,
197 u32 op, u16 *data)
198{
199 u32 mgtcr;
200 struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
201
202 if (mdio_wait(dev))
203 return 1;
204
205 /* Construct mgtcr mask for the operation */
206 mgtcr = ZYNQ_GEM_PHYMNTNC_OP_MASK | op |
207 (phy_addr << ZYNQ_GEM_PHYMNTNC_PHYAD_SHIFT_MASK) |
208 (regnum << ZYNQ_GEM_PHYMNTNC_PHREG_SHIFT_MASK) | *data;
209
210 /* Write mgtcr and wait for completion */
211 writel(mgtcr, &regs->phymntnc);
212
213 if (mdio_wait(dev))
214 return 1;
215
216 if (op == ZYNQ_GEM_PHYMNTNC_OP_R_MASK)
217 *data = readl(&regs->phymntnc);
218
219 return 0;
220}
221
222static u32 phyread(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 *val)
223{
Michal Simek198e9a42015-10-07 16:34:51 +0200224 u32 ret;
225
226 ret = phy_setup_op(dev, phy_addr, regnum,
Michal Simek185f7d92012-09-13 20:23:34 +0000227 ZYNQ_GEM_PHYMNTNC_OP_R_MASK, val);
Michal Simek198e9a42015-10-07 16:34:51 +0200228
229 if (!ret)
230 debug("%s: phy_addr %d, regnum 0x%x, val 0x%x\n", __func__,
231 phy_addr, regnum, *val);
232
233 return ret;
Michal Simek185f7d92012-09-13 20:23:34 +0000234}
235
236static u32 phywrite(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 data)
237{
Michal Simek198e9a42015-10-07 16:34:51 +0200238 debug("%s: phy_addr %d, regnum 0x%x, data 0x%x\n", __func__, phy_addr,
239 regnum, data);
240
Michal Simek185f7d92012-09-13 20:23:34 +0000241 return phy_setup_op(dev, phy_addr, regnum,
242 ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data);
243}
244
Michal Simekf97d7e82013-04-22 14:41:09 +0200245static void phy_detection(struct eth_device *dev)
246{
247 int i;
248 u16 phyreg;
249 struct zynq_gem_priv *priv = dev->priv;
250
251 if (priv->phyaddr != -1) {
252 phyread(dev, priv->phyaddr, PHY_DETECT_REG, &phyreg);
253 if ((phyreg != 0xFFFF) &&
254 ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
255 /* Found a valid PHY address */
256 debug("Default phy address %d is valid\n",
257 priv->phyaddr);
258 return;
259 } else {
260 debug("PHY address is not setup correctly %d\n",
261 priv->phyaddr);
262 priv->phyaddr = -1;
263 }
264 }
265
266 debug("detecting phy address\n");
267 if (priv->phyaddr == -1) {
268 /* detect the PHY address */
269 for (i = 31; i >= 0; i--) {
270 phyread(dev, i, PHY_DETECT_REG, &phyreg);
271 if ((phyreg != 0xFFFF) &&
272 ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
273 /* Found a valid PHY address */
274 priv->phyaddr = i;
275 debug("Found valid phy address, %d\n", i);
276 return;
277 }
278 }
279 }
280 printf("PHY is not detected\n");
281}
282
Michal Simek185f7d92012-09-13 20:23:34 +0000283static int zynq_gem_setup_mac(struct eth_device *dev)
284{
285 u32 i, macaddrlow, macaddrhigh;
286 struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
287
288 /* Set the MAC bits [31:0] in BOT */
289 macaddrlow = dev->enetaddr[0];
290 macaddrlow |= dev->enetaddr[1] << 8;
291 macaddrlow |= dev->enetaddr[2] << 16;
292 macaddrlow |= dev->enetaddr[3] << 24;
293
294 /* Set MAC bits [47:32] in TOP */
295 macaddrhigh = dev->enetaddr[4];
296 macaddrhigh |= dev->enetaddr[5] << 8;
297
298 for (i = 0; i < 4; i++) {
299 writel(0, &regs->laddr[i][LADDR_LOW]);
300 writel(0, &regs->laddr[i][LADDR_HIGH]);
301 /* Do not use MATCHx register */
302 writel(0, &regs->match[i]);
303 }
304
305 writel(macaddrlow, &regs->laddr[0][LADDR_LOW]);
306 writel(macaddrhigh, &regs->laddr[0][LADDR_HIGH]);
307
308 return 0;
309}
310
311static int zynq_gem_init(struct eth_device *dev, bd_t * bis)
312{
Soren Brinkmann97598fc2013-11-21 13:39:01 -0800313 u32 i;
314 unsigned long clk_rate = 0;
Michal Simek185f7d92012-09-13 20:23:34 +0000315 struct phy_device *phydev;
Michal Simek185f7d92012-09-13 20:23:34 +0000316 struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
317 struct zynq_gem_priv *priv = dev->priv;
Edgar E. Iglesias603ff002015-09-25 23:50:07 -0700318 struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC];
319 struct emac_bd *dummy_rx_bd = &priv->tx_bd[TX_FREE_DESC + 2];
Michal Simek185f7d92012-09-13 20:23:34 +0000320 const u32 supported = SUPPORTED_10baseT_Half |
321 SUPPORTED_10baseT_Full |
322 SUPPORTED_100baseT_Half |
323 SUPPORTED_100baseT_Full |
324 SUPPORTED_1000baseT_Half |
325 SUPPORTED_1000baseT_Full;
326
Michal Simek05868752013-01-24 13:04:12 +0100327 if (!priv->init) {
328 /* Disable all interrupts */
329 writel(0xFFFFFFFF, &regs->idr);
Michal Simek185f7d92012-09-13 20:23:34 +0000330
Michal Simek05868752013-01-24 13:04:12 +0100331 /* Disable the receiver & transmitter */
332 writel(0, &regs->nwctrl);
333 writel(0, &regs->txsr);
334 writel(0, &regs->rxsr);
335 writel(0, &regs->phymntnc);
Michal Simek185f7d92012-09-13 20:23:34 +0000336
Michal Simek05868752013-01-24 13:04:12 +0100337 /* Clear the Hash registers for the mac address
338 * pointed by AddressPtr
339 */
340 writel(0x0, &regs->hashl);
341 /* Write bits [63:32] in TOP */
342 writel(0x0, &regs->hashh);
Michal Simek185f7d92012-09-13 20:23:34 +0000343
Michal Simek05868752013-01-24 13:04:12 +0100344 /* Clear all counters */
Michal Simek0ebf4042015-10-05 12:49:48 +0200345 for (i = 0; i < STAT_SIZE; i++)
Michal Simek05868752013-01-24 13:04:12 +0100346 readl(&regs->stat[i]);
Michal Simek185f7d92012-09-13 20:23:34 +0000347
Michal Simek05868752013-01-24 13:04:12 +0100348 /* Setup RxBD space */
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530349 memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd));
Michal Simek185f7d92012-09-13 20:23:34 +0000350
Michal Simek05868752013-01-24 13:04:12 +0100351 for (i = 0; i < RX_BUF; i++) {
352 priv->rx_bd[i].status = 0xF0000000;
353 priv->rx_bd[i].addr =
Prabhakar Kushwaha5b47d402015-10-25 13:18:54 +0530354 ((ulong)(priv->rxbuffers) +
Michal Simek185f7d92012-09-13 20:23:34 +0000355 (i * PKTSIZE_ALIGN));
Michal Simek05868752013-01-24 13:04:12 +0100356 }
357 /* WRAP bit to last BD */
358 priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK;
359 /* Write RxBDs to IP */
Prabhakar Kushwaha5b47d402015-10-25 13:18:54 +0530360 writel((ulong)priv->rx_bd, &regs->rxqbase);
Michal Simek185f7d92012-09-13 20:23:34 +0000361
Michal Simek05868752013-01-24 13:04:12 +0100362 /* Setup for DMA Configuration register */
363 writel(ZYNQ_GEM_DMACR_INIT, &regs->dmacr);
Michal Simek185f7d92012-09-13 20:23:34 +0000364
Michal Simek05868752013-01-24 13:04:12 +0100365 /* Setup for Network Control register, MDIO, Rx and Tx enable */
Michal Simek80243522012-10-15 14:01:23 +0200366 setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
Michal Simek185f7d92012-09-13 20:23:34 +0000367
Edgar E. Iglesias603ff002015-09-25 23:50:07 -0700368 /* Disable the second priority queue */
369 dummy_tx_bd->addr = 0;
370 dummy_tx_bd->status = ZYNQ_GEM_TXBUF_WRAP_MASK |
371 ZYNQ_GEM_TXBUF_LAST_MASK|
372 ZYNQ_GEM_TXBUF_USED_MASK;
373
374 dummy_rx_bd->addr = ZYNQ_GEM_RXBUF_WRAP_MASK |
375 ZYNQ_GEM_RXBUF_NEW_MASK;
376 dummy_rx_bd->status = 0;
377 flush_dcache_range((ulong)&dummy_tx_bd, (ulong)&dummy_tx_bd +
378 sizeof(dummy_tx_bd));
379 flush_dcache_range((ulong)&dummy_rx_bd, (ulong)&dummy_rx_bd +
380 sizeof(dummy_rx_bd));
381
382 writel((ulong)dummy_tx_bd, &regs->transmit_q1_ptr);
383 writel((ulong)dummy_rx_bd, &regs->receive_q1_ptr);
384
Michal Simek05868752013-01-24 13:04:12 +0100385 priv->init++;
386 }
387
Michal Simekf97d7e82013-04-22 14:41:09 +0200388 phy_detection(dev);
389
Michal Simek185f7d92012-09-13 20:23:34 +0000390 /* interface - look at tsec */
Michal Simekc1a9fa42014-02-25 10:25:38 +0100391 phydev = phy_connect(priv->bus, priv->phyaddr, dev,
Michal Simek16ce6de2015-10-07 16:42:56 +0200392 priv->interface);
Michal Simek185f7d92012-09-13 20:23:34 +0000393
Michal Simek80243522012-10-15 14:01:23 +0200394 phydev->supported = supported | ADVERTISED_Pause |
395 ADVERTISED_Asym_Pause;
Michal Simek185f7d92012-09-13 20:23:34 +0000396 phydev->advertising = phydev->supported;
397 priv->phydev = phydev;
398 phy_config(phydev);
399 phy_startup(phydev);
400
Michal Simek4ed4aa22013-11-12 14:25:29 +0100401 if (!phydev->link) {
402 printf("%s: No link.\n", phydev->dev->name);
403 return -1;
404 }
405
Michal Simek80243522012-10-15 14:01:23 +0200406 switch (phydev->speed) {
407 case SPEED_1000:
408 writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000,
409 &regs->nwcfg);
Soren Brinkmann97598fc2013-11-21 13:39:01 -0800410 clk_rate = ZYNQ_GEM_FREQUENCY_1000;
Michal Simek80243522012-10-15 14:01:23 +0200411 break;
412 case SPEED_100:
Michal Simek242b1542015-09-08 16:55:42 +0200413 writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100,
414 &regs->nwcfg);
Soren Brinkmann97598fc2013-11-21 13:39:01 -0800415 clk_rate = ZYNQ_GEM_FREQUENCY_100;
Michal Simek80243522012-10-15 14:01:23 +0200416 break;
417 case SPEED_10:
Soren Brinkmann97598fc2013-11-21 13:39:01 -0800418 clk_rate = ZYNQ_GEM_FREQUENCY_10;
Michal Simek80243522012-10-15 14:01:23 +0200419 break;
420 }
David Andrey01fbf312013-04-05 17:24:24 +0200421
422 /* Change the rclk and clk only not using EMIO interface */
423 if (!priv->emio)
424 zynq_slcr_gem_clk_setup(dev->iobase !=
Soren Brinkmann97598fc2013-11-21 13:39:01 -0800425 ZYNQ_GEM_BASEADDR0, clk_rate);
Michal Simek80243522012-10-15 14:01:23 +0200426
427 setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
428 ZYNQ_GEM_NWCTRL_TXEN_MASK);
429
Michal Simek185f7d92012-09-13 20:23:34 +0000430 return 0;
431}
432
Michal Simeke4d23182015-08-17 09:57:46 +0200433static int wait_for_bit(const char *func, u32 *reg, const u32 mask,
434 bool set, unsigned int timeout)
435{
436 u32 val;
437 unsigned long start = get_timer(0);
438
439 while (1) {
440 val = readl(reg);
441
442 if (!set)
443 val = ~val;
444
445 if ((val & mask) == mask)
446 return 0;
447
448 if (get_timer(start) > timeout)
449 break;
450
451 udelay(1);
452 }
453
454 debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
455 func, reg, mask, set);
456
457 return -ETIMEDOUT;
458}
459
Michal Simek185f7d92012-09-13 20:23:34 +0000460static int zynq_gem_send(struct eth_device *dev, void *ptr, int len)
461{
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530462 u32 addr, size;
Michal Simek185f7d92012-09-13 20:23:34 +0000463 struct zynq_gem_priv *priv = dev->priv;
464 struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
Michal Simek23a598f2015-08-17 09:58:54 +0200465 struct emac_bd *current_bd = &priv->tx_bd[1];
Michal Simek185f7d92012-09-13 20:23:34 +0000466
Michal Simek185f7d92012-09-13 20:23:34 +0000467 /* Setup Tx BD */
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530468 memset(priv->tx_bd, 0, sizeof(struct emac_bd));
Michal Simek185f7d92012-09-13 20:23:34 +0000469
Prabhakar Kushwaha5b47d402015-10-25 13:18:54 +0530470 priv->tx_bd->addr = (ulong)ptr;
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530471 priv->tx_bd->status = (len & ZYNQ_GEM_TXBUF_FRMLEN_MASK) |
Michal Simek23a598f2015-08-17 09:58:54 +0200472 ZYNQ_GEM_TXBUF_LAST_MASK;
473 /* Dummy descriptor to mark it as the last in descriptor chain */
474 current_bd->addr = 0x0;
475 current_bd->status = ZYNQ_GEM_TXBUF_WRAP_MASK |
476 ZYNQ_GEM_TXBUF_LAST_MASK|
477 ZYNQ_GEM_TXBUF_USED_MASK;
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530478
Michal Simek45c07742015-08-17 09:50:09 +0200479 /* setup BD */
480 writel((ulong)priv->tx_bd, &regs->txqbase);
481
Prabhakar Kushwaha5b47d402015-10-25 13:18:54 +0530482 addr = (ulong) ptr;
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530483 addr &= ~(ARCH_DMA_MINALIGN - 1);
484 size = roundup(len, ARCH_DMA_MINALIGN);
485 flush_dcache_range(addr, addr + size);
Siva Durga Prasad Paladugu96f4f142014-12-06 12:57:53 +0530486
Prabhakar Kushwaha5b47d402015-10-25 13:18:54 +0530487 addr = (ulong)priv->rxbuffers;
Siva Durga Prasad Paladugu96f4f142014-12-06 12:57:53 +0530488 addr &= ~(ARCH_DMA_MINALIGN - 1);
489 size = roundup((RX_BUF * PKTSIZE_ALIGN), ARCH_DMA_MINALIGN);
490 flush_dcache_range(addr, addr + size);
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530491 barrier();
Michal Simek185f7d92012-09-13 20:23:34 +0000492
493 /* Start transmit */
494 setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK);
495
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530496 /* Read TX BD status */
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530497 if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_EXHAUSTED)
498 printf("TX buffers exhausted in mid frame\n");
Michal Simek185f7d92012-09-13 20:23:34 +0000499
Michal Simeke4d23182015-08-17 09:57:46 +0200500 return wait_for_bit(__func__, &regs->txsr, ZYNQ_GEM_TSR_DONE,
501 true, 20000);
Michal Simek185f7d92012-09-13 20:23:34 +0000502}
503
504/* Do not check frame_recd flag in rx_status register 0x20 - just poll BD */
505static int zynq_gem_recv(struct eth_device *dev)
506{
507 int frame_len;
508 struct zynq_gem_priv *priv = dev->priv;
509 struct emac_bd *current_bd = &priv->rx_bd[priv->rxbd_current];
510 struct emac_bd *first_bd;
511
512 if (!(current_bd->addr & ZYNQ_GEM_RXBUF_NEW_MASK))
513 return 0;
514
515 if (!(current_bd->status &
516 (ZYNQ_GEM_RXBUF_SOF_MASK | ZYNQ_GEM_RXBUF_EOF_MASK))) {
517 printf("GEM: SOF or EOF not set for last buffer received!\n");
518 return 0;
519 }
520
521 frame_len = current_bd->status & ZYNQ_GEM_RXBUF_LEN_MASK;
522 if (frame_len) {
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530523 u32 addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK;
524 addr &= ~(ARCH_DMA_MINALIGN - 1);
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530525
Prabhakar Kushwaha5b47d402015-10-25 13:18:54 +0530526 net_process_received_packet((u8 *)(ulong)addr, frame_len);
Michal Simek185f7d92012-09-13 20:23:34 +0000527
528 if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK)
529 priv->rx_first_buf = priv->rxbd_current;
530 else {
531 current_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK;
532 current_bd->status = 0xF0000000; /* FIXME */
533 }
534
535 if (current_bd->status & ZYNQ_GEM_RXBUF_EOF_MASK) {
536 first_bd = &priv->rx_bd[priv->rx_first_buf];
537 first_bd->addr &= ~ZYNQ_GEM_RXBUF_NEW_MASK;
538 first_bd->status = 0xF0000000;
539 }
540
541 if ((++priv->rxbd_current) >= RX_BUF)
542 priv->rxbd_current = 0;
Michal Simek185f7d92012-09-13 20:23:34 +0000543 }
544
Michal Simek3b90d0a2013-01-25 08:24:18 +0100545 return frame_len;
Michal Simek185f7d92012-09-13 20:23:34 +0000546}
547
548static void zynq_gem_halt(struct eth_device *dev)
549{
550 struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase;
551
Michal Simek80243522012-10-15 14:01:23 +0200552 clrsetbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
553 ZYNQ_GEM_NWCTRL_TXEN_MASK, 0);
Michal Simek185f7d92012-09-13 20:23:34 +0000554}
555
556static int zynq_gem_miiphyread(const char *devname, uchar addr,
557 uchar reg, ushort *val)
558{
559 struct eth_device *dev = eth_get_dev();
560 int ret;
561
562 ret = phyread(dev, addr, reg, val);
563 debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, *val);
564 return ret;
565}
566
567static int zynq_gem_miiphy_write(const char *devname, uchar addr,
568 uchar reg, ushort val)
569{
570 struct eth_device *dev = eth_get_dev();
571
572 debug("%s 0x%x, 0x%x, 0x%x\n", __func__, addr, reg, val);
573 return phywrite(dev, addr, reg, val);
574}
575
Michal Simek58405372015-01-14 15:44:21 +0100576int zynq_gem_initialize(bd_t *bis, phys_addr_t base_addr,
577 int phy_addr, u32 emio)
Michal Simek185f7d92012-09-13 20:23:34 +0000578{
579 struct eth_device *dev;
580 struct zynq_gem_priv *priv;
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530581 void *bd_space;
Michal Simek185f7d92012-09-13 20:23:34 +0000582
583 dev = calloc(1, sizeof(*dev));
584 if (dev == NULL)
585 return -1;
586
587 dev->priv = calloc(1, sizeof(struct zynq_gem_priv));
588 if (dev->priv == NULL) {
589 free(dev);
590 return -1;
591 }
592 priv = dev->priv;
593
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530594 /* Align rxbuffers to ARCH_DMA_MINALIGN */
595 priv->rxbuffers = memalign(ARCH_DMA_MINALIGN, RX_BUF * PKTSIZE_ALIGN);
596 memset(priv->rxbuffers, 0, RX_BUF * PKTSIZE_ALIGN);
597
Siva Durga Prasad Paladugu96f4f142014-12-06 12:57:53 +0530598 /* Align bd_space to MMU_SECTION_SHIFT */
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530599 bd_space = memalign(1 << MMU_SECTION_SHIFT, BD_SPACE);
Michal Simek9ce1edc2015-04-15 13:31:28 +0200600 mmu_set_region_dcache_behaviour((phys_addr_t)bd_space,
601 BD_SPACE, DCACHE_OFF);
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530602
603 /* Initialize the bd spaces for tx and rx bd's */
604 priv->tx_bd = (struct emac_bd *)bd_space;
Prabhakar Kushwaha5b47d402015-10-25 13:18:54 +0530605 priv->rx_bd = (struct emac_bd *)((ulong)bd_space + BD_SEPRN_SPACE);
Srikanth Thokalaa5144232013-11-08 22:55:48 +0530606
David Andrey117cd4c2013-04-04 19:13:07 +0200607 priv->phyaddr = phy_addr;
David Andrey01fbf312013-04-05 17:24:24 +0200608 priv->emio = emio;
Michal Simek185f7d92012-09-13 20:23:34 +0000609
Michal Simek16ce6de2015-10-07 16:42:56 +0200610#ifndef CONFIG_ZYNQ_GEM_INTERFACE
611 priv->interface = PHY_INTERFACE_MODE_MII;
612#else
613 priv->interface = CONFIG_ZYNQ_GEM_INTERFACE;
614#endif
615
Michal Simek58405372015-01-14 15:44:21 +0100616 sprintf(dev->name, "Gem.%lx", base_addr);
Michal Simek185f7d92012-09-13 20:23:34 +0000617
618 dev->iobase = base_addr;
619
620 dev->init = zynq_gem_init;
621 dev->halt = zynq_gem_halt;
622 dev->send = zynq_gem_send;
623 dev->recv = zynq_gem_recv;
624 dev->write_hwaddr = zynq_gem_setup_mac;
625
626 eth_register(dev);
627
628 miiphy_register(dev->name, zynq_gem_miiphyread, zynq_gem_miiphy_write);
629 priv->bus = miiphy_get_dev_by_name(dev->name);
630
631 return 1;
632}
Michal Simekf88a6862014-02-24 11:16:30 +0100633
Masahiro Yamada0f925822015-08-12 07:31:55 +0900634#if CONFIG_IS_ENABLED(OF_CONTROL)
Michal Simekf88a6862014-02-24 11:16:30 +0100635int zynq_gem_of_init(const void *blob)
636{
637 int offset = 0;
638 u32 ret = 0;
639 u32 reg, phy_reg;
640
641 debug("ZYNQ GEM: Initialization\n");
642
643 do {
644 offset = fdt_node_offset_by_compatible(blob, offset,
645 "xlnx,ps7-ethernet-1.00.a");
646 if (offset != -1) {
647 reg = fdtdec_get_addr(blob, offset, "reg");
648 if (reg != FDT_ADDR_T_NONE) {
649 offset = fdtdec_lookup_phandle(blob, offset,
650 "phy-handle");
651 if (offset != -1)
652 phy_reg = fdtdec_get_addr(blob, offset,
653 "reg");
654 else
655 phy_reg = 0;
656
657 debug("ZYNQ GEM: addr %x, phyaddr %x\n",
658 reg, phy_reg);
659
660 ret |= zynq_gem_initialize(NULL, reg,
661 phy_reg, 0);
662
663 } else {
664 debug("ZYNQ GEM: Can't get base address\n");
665 return -1;
666 }
667 }
668 } while (offset != -1);
669
670 return ret;
671}
672#endif