blob: 6c9f1f7c2728922108949176f698726608144c24 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Michal Simek14b4c702009-09-07 09:08:02 +02002/*
3 * (C) Copyright 2007-2009 Michal Simek
4 * (C) Copyright 2003 Xilinx Inc.
Michal Simek4514b372008-03-28 12:41:56 +01005 *
Michal Simek4514b372008-03-28 12:41:56 +01006 * Michal SIMEK <monstr@monstr.eu>
Michal Simek14b4c702009-09-07 09:08:02 +02007 */
Michal Simek4514b372008-03-28 12:41:56 +01008
9#include <common.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Michal Simek4514b372008-03-28 12:41:56 +010011#include <net.h>
12#include <config.h>
Michal Simekf7cba782015-12-10 17:15:52 +010013#include <dm.h>
Michal Simek912145b2015-12-10 13:33:20 +010014#include <console.h>
Michal Simekb4a1d082010-10-11 11:41:47 +100015#include <malloc.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060016#include <asm/global_data.h>
Michal Simek4514b372008-03-28 12:41:56 +010017#include <asm/io.h>
Michal Simek912145b2015-12-10 13:33:20 +010018#include <phy.h>
19#include <miiphy.h>
Michal Simekbb8b27b2012-06-28 21:37:57 +000020#include <fdtdec.h>
Simon Glassdbd79542020-05-10 11:40:11 -060021#include <linux/delay.h>
Masahiro Yamada64e4f7f2016-09-21 11:28:57 +090022#include <linux/errno.h>
Michal Simek36f7a412015-12-10 16:31:38 +010023#include <linux/kernel.h>
Zubair Lutfullah Kakakheld23bf842016-07-27 12:25:07 +010024#include <asm/io.h>
T Karthik Reddycff10842022-05-10 13:26:10 +020025#include <eth_phy.h>
Michal Simekbb8b27b2012-06-28 21:37:57 +000026
Michal Simekf7cba782015-12-10 17:15:52 +010027DECLARE_GLOBAL_DATA_PTR;
Michal Simek4514b372008-03-28 12:41:56 +010028
Michal Simek4514b372008-03-28 12:41:56 +010029#define ENET_ADDR_LENGTH 6
Michal Simek36f7a412015-12-10 16:31:38 +010030#define ETH_FCS_LEN 4 /* Octets in the FCS */
Michal Simek4514b372008-03-28 12:41:56 +010031
32/* Xmit complete */
33#define XEL_TSR_XMIT_BUSY_MASK 0x00000001UL
34/* Xmit interrupt enable bit */
35#define XEL_TSR_XMIT_IE_MASK 0x00000008UL
Michal Simek4514b372008-03-28 12:41:56 +010036/* Program the MAC address */
37#define XEL_TSR_PROGRAM_MASK 0x00000002UL
38/* define for programming the MAC address into the EMAC Lite */
39#define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK)
40
41/* Transmit packet length upper byte */
42#define XEL_TPLR_LENGTH_MASK_HI 0x0000FF00UL
43/* Transmit packet length lower byte */
44#define XEL_TPLR_LENGTH_MASK_LO 0x000000FFUL
45
46/* Recv complete */
47#define XEL_RSR_RECV_DONE_MASK 0x00000001UL
48/* Recv interrupt enable bit */
49#define XEL_RSR_RECV_IE_MASK 0x00000008UL
50
Michal Simek912145b2015-12-10 13:33:20 +010051/* MDIO Address Register Bit Masks */
52#define XEL_MDIOADDR_REGADR_MASK 0x0000001F /* Register Address */
53#define XEL_MDIOADDR_PHYADR_MASK 0x000003E0 /* PHY Address */
54#define XEL_MDIOADDR_PHYADR_SHIFT 5
55#define XEL_MDIOADDR_OP_MASK 0x00000400 /* RD/WR Operation */
56
57/* MDIO Write Data Register Bit Masks */
58#define XEL_MDIOWR_WRDATA_MASK 0x0000FFFF /* Data to be Written */
59
60/* MDIO Read Data Register Bit Masks */
61#define XEL_MDIORD_RDDATA_MASK 0x0000FFFF /* Data to be Read */
62
63/* MDIO Control Register Bit Masks */
64#define XEL_MDIOCTRL_MDIOSTS_MASK 0x00000001 /* MDIO Status Mask */
65#define XEL_MDIOCTRL_MDIOEN_MASK 0x00000008 /* MDIO Enable */
66
Michal Simek905f0982015-12-10 14:18:15 +010067struct emaclite_regs {
68 u32 tx_ping; /* 0x0 - TX Ping buffer */
69 u32 reserved1[504];
70 u32 mdioaddr; /* 0x7e4 - MDIO Address Register */
71 u32 mdiowr; /* 0x7e8 - MDIO Write Data Register */
72 u32 mdiord;/* 0x7ec - MDIO Read Data Register */
73 u32 mdioctrl; /* 0x7f0 - MDIO Control Register */
74 u32 tx_ping_tplr; /* 0x7f4 - Tx packet length */
75 u32 global_interrupt; /* 0x7f8 - Global interrupt enable */
76 u32 tx_ping_tsr; /* 0x7fc - Tx status */
77 u32 tx_pong; /* 0x800 - TX Pong buffer */
78 u32 reserved2[508];
79 u32 tx_pong_tplr; /* 0xff4 - Tx packet length */
80 u32 reserved3; /* 0xff8 */
81 u32 tx_pong_tsr; /* 0xffc - Tx status */
82 u32 rx_ping; /* 0x1000 - Receive Buffer */
83 u32 reserved4[510];
84 u32 rx_ping_rsr; /* 0x17fc - Rx status */
85 u32 rx_pong; /* 0x1800 - Receive Buffer */
86 u32 reserved5[510];
87 u32 rx_pong_rsr; /* 0x1ffc - Rx status */
88};
89
Michal Simekf35b7cd2011-08-25 12:47:56 +020090struct xemaclite {
Michal Simek36f7a412015-12-10 16:31:38 +010091 bool use_rx_pong_buffer_next; /* Next RX buffer to read from */
Michal Simekdf40ead2011-09-12 21:10:01 +000092 u32 txpp; /* TX ping pong buffer */
93 u32 rxpp; /* RX ping pong buffer */
Michal Simek912145b2015-12-10 13:33:20 +010094 int phyaddr;
Michal Simek905f0982015-12-10 14:18:15 +010095 struct emaclite_regs *regs;
Michal Simek912145b2015-12-10 13:33:20 +010096 struct phy_device *phydev;
97 struct mii_dev *bus;
Michal Simekf35b7cd2011-08-25 12:47:56 +020098};
Michal Simek4514b372008-03-28 12:41:56 +010099
Michal Simek641ade02015-12-16 10:52:39 +0100100static uchar etherrxbuff[PKTSIZE_ALIGN]; /* Receive buffer */
Michal Simek4514b372008-03-28 12:41:56 +0100101
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000102static void xemaclite_alignedread(u32 *srcptr, void *destptr, u32 bytecount)
Michal Simek4514b372008-03-28 12:41:56 +0100103{
Michal Simekb4a1d082010-10-11 11:41:47 +1000104 u32 i;
Michal Simek4514b372008-03-28 12:41:56 +0100105 u32 alignbuffer;
106 u32 *to32ptr;
107 u32 *from32ptr;
108 u8 *to8ptr;
109 u8 *from8ptr;
110
111 from32ptr = (u32 *) srcptr;
112
113 /* Word aligned buffer, no correction needed. */
114 to32ptr = (u32 *) destptr;
115 while (bytecount > 3) {
116 *to32ptr++ = *from32ptr++;
117 bytecount -= 4;
118 }
119 to8ptr = (u8 *) to32ptr;
120
121 alignbuffer = *from32ptr++;
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000122 from8ptr = (u8 *) &alignbuffer;
Michal Simek4514b372008-03-28 12:41:56 +0100123
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000124 for (i = 0; i < bytecount; i++)
Michal Simek4514b372008-03-28 12:41:56 +0100125 *to8ptr++ = *from8ptr++;
Michal Simek4514b372008-03-28 12:41:56 +0100126}
127
Michal Simek90e89bf2015-12-10 16:01:50 +0100128static void xemaclite_alignedwrite(void *srcptr, u32 *destptr, u32 bytecount)
Michal Simek4514b372008-03-28 12:41:56 +0100129{
Michal Simekb4a1d082010-10-11 11:41:47 +1000130 u32 i;
Michal Simek4514b372008-03-28 12:41:56 +0100131 u32 alignbuffer;
132 u32 *to32ptr = (u32 *) destptr;
133 u32 *from32ptr;
134 u8 *to8ptr;
135 u8 *from8ptr;
136
137 from32ptr = (u32 *) srcptr;
138 while (bytecount > 3) {
139
140 *to32ptr++ = *from32ptr++;
141 bytecount -= 4;
142 }
143
144 alignbuffer = 0;
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000145 to8ptr = (u8 *) &alignbuffer;
Michal Simek4514b372008-03-28 12:41:56 +0100146 from8ptr = (u8 *) from32ptr;
147
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000148 for (i = 0; i < bytecount; i++)
Michal Simek4514b372008-03-28 12:41:56 +0100149 *to8ptr++ = *from8ptr++;
Michal Simek4514b372008-03-28 12:41:56 +0100150
151 *to32ptr++ = alignbuffer;
152}
153
Michal Simek912145b2015-12-10 13:33:20 +0100154static int wait_for_bit(const char *func, u32 *reg, const u32 mask,
155 bool set, unsigned int timeout)
156{
157 u32 val;
158 unsigned long start = get_timer(0);
159
160 while (1) {
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100161 val = __raw_readl(reg);
Michal Simek912145b2015-12-10 13:33:20 +0100162
163 if (!set)
164 val = ~val;
165
166 if ((val & mask) == mask)
167 return 0;
168
169 if (get_timer(start) > timeout)
170 break;
171
172 if (ctrlc()) {
173 puts("Abort\n");
174 return -EINTR;
175 }
176
177 udelay(1);
178 }
179
180 debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
181 func, reg, mask, set);
182
183 return -ETIMEDOUT;
184}
185
Michal Simek905f0982015-12-10 14:18:15 +0100186static int mdio_wait(struct emaclite_regs *regs)
Michal Simek912145b2015-12-10 13:33:20 +0100187{
Michal Simek905f0982015-12-10 14:18:15 +0100188 return wait_for_bit(__func__, &regs->mdioctrl,
Michal Simek912145b2015-12-10 13:33:20 +0100189 XEL_MDIOCTRL_MDIOSTS_MASK, false, 2000);
190}
191
Michal Simek905f0982015-12-10 14:18:15 +0100192static u32 phyread(struct xemaclite *emaclite, u32 phyaddress, u32 registernum,
Michal Simek912145b2015-12-10 13:33:20 +0100193 u16 *data)
194{
Michal Simek905f0982015-12-10 14:18:15 +0100195 struct emaclite_regs *regs = emaclite->regs;
196
197 if (mdio_wait(regs))
Michal Simek912145b2015-12-10 13:33:20 +0100198 return 1;
199
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100200 u32 ctrl_reg = __raw_readl(&regs->mdioctrl);
201 __raw_writel(XEL_MDIOADDR_OP_MASK
202 | ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT)
203 | registernum), &regs->mdioaddr);
204 __raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK, &regs->mdioctrl);
Michal Simek912145b2015-12-10 13:33:20 +0100205
Michal Simek905f0982015-12-10 14:18:15 +0100206 if (mdio_wait(regs))
Michal Simek912145b2015-12-10 13:33:20 +0100207 return 1;
208
209 /* Read data */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100210 *data = __raw_readl(&regs->mdiord);
Michal Simek912145b2015-12-10 13:33:20 +0100211 return 0;
212}
213
Michal Simek905f0982015-12-10 14:18:15 +0100214static u32 phywrite(struct xemaclite *emaclite, u32 phyaddress, u32 registernum,
Michal Simek912145b2015-12-10 13:33:20 +0100215 u16 data)
216{
Michal Simek905f0982015-12-10 14:18:15 +0100217 struct emaclite_regs *regs = emaclite->regs;
218
219 if (mdio_wait(regs))
Michal Simek912145b2015-12-10 13:33:20 +0100220 return 1;
221
222 /*
223 * Write the PHY address, register number and clear the OP bit in the
224 * MDIO Address register and then write the value into the MDIO Write
225 * Data register. Finally, set the Status bit in the MDIO Control
226 * register to start a MDIO write transaction.
227 */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100228 u32 ctrl_reg = __raw_readl(&regs->mdioctrl);
229 __raw_writel(~XEL_MDIOADDR_OP_MASK
230 & ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT)
231 | registernum), &regs->mdioaddr);
232 __raw_writel(data, &regs->mdiowr);
233 __raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK, &regs->mdioctrl);
Michal Simek912145b2015-12-10 13:33:20 +0100234
Michal Simek905f0982015-12-10 14:18:15 +0100235 if (mdio_wait(regs))
Michal Simek912145b2015-12-10 13:33:20 +0100236 return 1;
237
238 return 0;
239}
Michal Simek912145b2015-12-10 13:33:20 +0100240
Michal Simekfeebc8a2015-12-16 10:40:05 +0100241static void emaclite_stop(struct udevice *dev)
Michal Simek4514b372008-03-28 12:41:56 +0100242{
Michal Simekfeebc8a2015-12-16 10:40:05 +0100243 debug("eth_stop\n");
Michal Simek4514b372008-03-28 12:41:56 +0100244}
Michal Simek912145b2015-12-10 13:33:20 +0100245
246/* Use MII register 1 (MII status register) to detect PHY */
247#define PHY_DETECT_REG 1
248
249/* Mask used to verify certain PHY features (or register contents)
250 * in the register above:
251 * 0x1000: 10Mbps full duplex support
252 * 0x0800: 10Mbps half duplex support
253 * 0x0008: Auto-negotiation support
254 */
255#define PHY_DETECT_MASK 0x1808
256
Michal Simekf7cba782015-12-10 17:15:52 +0100257static int setup_phy(struct udevice *dev)
Michal Simek912145b2015-12-10 13:33:20 +0100258{
Michal Simekdbc0cfc2016-05-18 12:37:22 +0200259 int i, ret;
Michal Simek912145b2015-12-10 13:33:20 +0100260 u16 phyreg;
Michal Simekf7cba782015-12-10 17:15:52 +0100261 struct xemaclite *emaclite = dev_get_priv(dev);
Michal Simek912145b2015-12-10 13:33:20 +0100262 struct phy_device *phydev;
263
264 u32 supported = SUPPORTED_10baseT_Half |
265 SUPPORTED_10baseT_Full |
266 SUPPORTED_100baseT_Half |
267 SUPPORTED_100baseT_Full;
268
269 if (emaclite->phyaddr != -1) {
Michal Simek905f0982015-12-10 14:18:15 +0100270 phyread(emaclite, emaclite->phyaddr, PHY_DETECT_REG, &phyreg);
Michal Simek912145b2015-12-10 13:33:20 +0100271 if ((phyreg != 0xFFFF) &&
272 ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
273 /* Found a valid PHY address */
274 debug("Default phy address %d is valid\n",
275 emaclite->phyaddr);
276 } else {
277 debug("PHY address is not setup correctly %d\n",
278 emaclite->phyaddr);
279 emaclite->phyaddr = -1;
280 }
281 }
282
283 if (emaclite->phyaddr == -1) {
284 /* detect the PHY address */
285 for (i = 31; i >= 0; i--) {
Michal Simek905f0982015-12-10 14:18:15 +0100286 phyread(emaclite, i, PHY_DETECT_REG, &phyreg);
Michal Simek912145b2015-12-10 13:33:20 +0100287 if ((phyreg != 0xFFFF) &&
288 ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
289 /* Found a valid PHY address */
290 emaclite->phyaddr = i;
291 debug("emaclite: Found valid phy address, %d\n",
292 i);
293 break;
294 }
295 }
296 }
297
298 /* interface - look at tsec */
299 phydev = phy_connect(emaclite->bus, emaclite->phyaddr, dev,
300 PHY_INTERFACE_MODE_MII);
301 /*
302 * Phy can support 1000baseT but device NOT that's why phydev->supported
303 * must be setup for 1000baseT. phydev->advertising setups what speeds
304 * will be used for autonegotiation where 1000baseT must be disabled.
305 */
306 phydev->supported = supported | SUPPORTED_1000baseT_Half |
307 SUPPORTED_1000baseT_Full;
308 phydev->advertising = supported;
309 emaclite->phydev = phydev;
310 phy_config(phydev);
Michal Simekdbc0cfc2016-05-18 12:37:22 +0200311 ret = phy_startup(phydev);
312 if (ret)
313 return ret;
Michal Simek912145b2015-12-10 13:33:20 +0100314
315 if (!phydev->link) {
316 printf("%s: No link.\n", phydev->dev->name);
317 return 0;
318 }
319
320 /* Do not setup anything */
321 return 1;
322}
Michal Simek4514b372008-03-28 12:41:56 +0100323
Michal Simekfeebc8a2015-12-16 10:40:05 +0100324static int emaclite_start(struct udevice *dev)
Michal Simek4514b372008-03-28 12:41:56 +0100325{
Michal Simekf7cba782015-12-10 17:15:52 +0100326 struct xemaclite *emaclite = dev_get_priv(dev);
Simon Glassfa20e932020-12-03 16:55:20 -0700327 struct eth_pdata *pdata = dev_get_plat(dev);
Michal Simek905f0982015-12-10 14:18:15 +0100328 struct emaclite_regs *regs = emaclite->regs;
329
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000330 debug("EmacLite Initialization Started\n");
Michal Simek4514b372008-03-28 12:41:56 +0100331
332/*
333 * TX - TX_PING & TX_PONG initialization
334 */
335 /* Restart PING TX */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100336 __raw_writel(0, &regs->tx_ping_tsr);
Michal Simek4514b372008-03-28 12:41:56 +0100337 /* Copy MAC address */
Michal Simekf7cba782015-12-10 17:15:52 +0100338 xemaclite_alignedwrite(pdata->enetaddr, &regs->tx_ping,
Michal Simek34240c42015-12-10 15:22:21 +0100339 ENET_ADDR_LENGTH);
Michal Simek4514b372008-03-28 12:41:56 +0100340 /* Set the length */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100341 __raw_writel(ENET_ADDR_LENGTH, &regs->tx_ping_tplr);
Michal Simek4514b372008-03-28 12:41:56 +0100342 /* Update the MAC address in the EMAC Lite */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100343 __raw_writel(XEL_TSR_PROG_MAC_ADDR, &regs->tx_ping_tsr);
Michal Simek4514b372008-03-28 12:41:56 +0100344 /* Wait for EMAC Lite to finish with the MAC address update */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100345 while ((__raw_readl(&regs->tx_ping_tsr) &
Michal Simekac357ac2011-08-25 12:36:39 +0200346 XEL_TSR_PROG_MAC_ADDR) != 0)
347 ;
Michal Simek4514b372008-03-28 12:41:56 +0100348
Michal Simekdf40ead2011-09-12 21:10:01 +0000349 if (emaclite->txpp) {
350 /* The same operation with PONG TX */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100351 __raw_writel(0, &regs->tx_pong_tsr);
Michal Simekf7cba782015-12-10 17:15:52 +0100352 xemaclite_alignedwrite(pdata->enetaddr, &regs->tx_pong,
Michal Simek34240c42015-12-10 15:22:21 +0100353 ENET_ADDR_LENGTH);
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100354 __raw_writel(ENET_ADDR_LENGTH, &regs->tx_pong_tplr);
355 __raw_writel(XEL_TSR_PROG_MAC_ADDR, &regs->tx_pong_tsr);
356 while ((__raw_readl(&regs->tx_pong_tsr) &
Michal Simek34240c42015-12-10 15:22:21 +0100357 XEL_TSR_PROG_MAC_ADDR) != 0)
Michal Simekdf40ead2011-09-12 21:10:01 +0000358 ;
359 }
Michal Simek4514b372008-03-28 12:41:56 +0100360
361/*
362 * RX - RX_PING & RX_PONG initialization
363 */
364 /* Write out the value to flush the RX buffer */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100365 __raw_writel(XEL_RSR_RECV_IE_MASK, &regs->rx_ping_rsr);
Michal Simekdf40ead2011-09-12 21:10:01 +0000366
367 if (emaclite->rxpp)
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100368 __raw_writel(XEL_RSR_RECV_IE_MASK, &regs->rx_pong_rsr);
Michal Simek4514b372008-03-28 12:41:56 +0100369
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100370 __raw_writel(XEL_MDIOCTRL_MDIOEN_MASK, &regs->mdioctrl);
371 if (__raw_readl(&regs->mdioctrl) & XEL_MDIOCTRL_MDIOEN_MASK)
Michal Simek912145b2015-12-10 13:33:20 +0100372 if (!setup_phy(dev))
373 return -1;
Michal Simekf7cba782015-12-10 17:15:52 +0100374
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000375 debug("EmacLite Initialization complete\n");
Michal Simek4514b372008-03-28 12:41:56 +0100376 return 0;
377}
378
Michal Simek1edc6572015-12-10 15:42:01 +0100379static int xemaclite_txbufferavailable(struct xemaclite *emaclite)
Michal Simek4514b372008-03-28 12:41:56 +0100380{
Michal Simek1edc6572015-12-10 15:42:01 +0100381 u32 tmp;
382 struct emaclite_regs *regs = emaclite->regs;
Michal Simekf35b7cd2011-08-25 12:47:56 +0200383
Michal Simek4514b372008-03-28 12:41:56 +0100384 /*
385 * Read the other buffer register
386 * and determine if the other buffer is available
387 */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100388 tmp = ~__raw_readl(&regs->tx_ping_tsr);
Michal Simek1edc6572015-12-10 15:42:01 +0100389 if (emaclite->txpp)
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100390 tmp |= ~__raw_readl(&regs->tx_pong_tsr);
Michal Simek4514b372008-03-28 12:41:56 +0100391
Michal Simek1edc6572015-12-10 15:42:01 +0100392 return !(tmp & XEL_TSR_XMIT_BUSY_MASK);
Michal Simek4514b372008-03-28 12:41:56 +0100393}
394
Michal Simekf7cba782015-12-10 17:15:52 +0100395static int emaclite_send(struct udevice *dev, void *ptr, int len)
Michal Simekb4a1d082010-10-11 11:41:47 +1000396{
397 u32 reg;
Michal Simekf7cba782015-12-10 17:15:52 +0100398 struct xemaclite *emaclite = dev_get_priv(dev);
Michal Simek9b9423b2015-12-10 15:32:11 +0100399 struct emaclite_regs *regs = emaclite->regs;
Michal Simek4514b372008-03-28 12:41:56 +0100400
Michal Simekb4a1d082010-10-11 11:41:47 +1000401 u32 maxtry = 1000;
Michal Simek4514b372008-03-28 12:41:56 +0100402
Michal Simek3aa96f82011-09-12 21:10:04 +0000403 if (len > PKTSIZE)
404 len = PKTSIZE;
Michal Simek4514b372008-03-28 12:41:56 +0100405
Michal Simek1edc6572015-12-10 15:42:01 +0100406 while (xemaclite_txbufferavailable(emaclite) && maxtry) {
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000407 udelay(10);
Michal Simek4514b372008-03-28 12:41:56 +0100408 maxtry--;
409 }
410
411 if (!maxtry) {
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000412 printf("Error: Timeout waiting for ethernet TX buffer\n");
Michal Simek4514b372008-03-28 12:41:56 +0100413 /* Restart PING TX */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100414 __raw_writel(0, &regs->tx_ping_tsr);
Michal Simekdf40ead2011-09-12 21:10:01 +0000415 if (emaclite->txpp) {
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100416 __raw_writel(0, &regs->tx_pong_tsr);
Michal Simekdf40ead2011-09-12 21:10:01 +0000417 }
Michal Simek29869212011-03-08 04:25:53 +0000418 return -1;
Michal Simek4514b372008-03-28 12:41:56 +0100419 }
420
Michal Simek4514b372008-03-28 12:41:56 +0100421 /* Determine if the expected buffer address is empty */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100422 reg = __raw_readl(&regs->tx_ping_tsr);
Michal Simekd92cef42015-12-10 16:06:07 +0100423 if ((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) {
Michal Simek90e89bf2015-12-10 16:01:50 +0100424 debug("Send packet from tx_ping buffer\n");
Michal Simek4514b372008-03-28 12:41:56 +0100425 /* Write the frame to the buffer */
Michal Simek90e89bf2015-12-10 16:01:50 +0100426 xemaclite_alignedwrite(ptr, &regs->tx_ping, len);
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100427 __raw_writel(len
428 & (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO),
429 &regs->tx_ping_tplr);
430 reg = __raw_readl(&regs->tx_ping_tsr);
Michal Simek4514b372008-03-28 12:41:56 +0100431 reg |= XEL_TSR_XMIT_BUSY_MASK;
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100432 __raw_writel(reg, &regs->tx_ping_tsr);
Michal Simek29869212011-03-08 04:25:53 +0000433 return 0;
Michal Simek4514b372008-03-28 12:41:56 +0100434 }
Michal Simekdf40ead2011-09-12 21:10:01 +0000435
436 if (emaclite->txpp) {
Michal Simekdf40ead2011-09-12 21:10:01 +0000437 /* Determine if the expected buffer address is empty */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100438 reg = __raw_readl(&regs->tx_pong_tsr);
Michal Simekd92cef42015-12-10 16:06:07 +0100439 if ((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) {
Michal Simek90e89bf2015-12-10 16:01:50 +0100440 debug("Send packet from tx_pong buffer\n");
Michal Simekdf40ead2011-09-12 21:10:01 +0000441 /* Write the frame to the buffer */
Michal Simek90e89bf2015-12-10 16:01:50 +0100442 xemaclite_alignedwrite(ptr, &regs->tx_pong, len);
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100443 __raw_writel(len &
Michal Simek90e89bf2015-12-10 16:01:50 +0100444 (XEL_TPLR_LENGTH_MASK_HI |
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100445 XEL_TPLR_LENGTH_MASK_LO),
446 &regs->tx_pong_tplr);
447 reg = __raw_readl(&regs->tx_pong_tsr);
Michal Simekdf40ead2011-09-12 21:10:01 +0000448 reg |= XEL_TSR_XMIT_BUSY_MASK;
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100449 __raw_writel(reg, &regs->tx_pong_tsr);
Michal Simekdf40ead2011-09-12 21:10:01 +0000450 return 0;
Michal Simek4514b372008-03-28 12:41:56 +0100451 }
Michal Simek4514b372008-03-28 12:41:56 +0100452 }
Michal Simekdf40ead2011-09-12 21:10:01 +0000453
Michal Simek5d1cf6c2011-09-12 21:10:05 +0000454 puts("Error while sending frame\n");
Michal Simek29869212011-03-08 04:25:53 +0000455 return -1;
Michal Simek4514b372008-03-28 12:41:56 +0100456}
457
Michal Simekf7cba782015-12-10 17:15:52 +0100458static int emaclite_recv(struct udevice *dev, int flags, uchar **packetp)
Michal Simek4514b372008-03-28 12:41:56 +0100459{
Michal Simek36f7a412015-12-10 16:31:38 +0100460 u32 length, first_read, reg, attempt = 0;
461 void *addr, *ack;
Simon Glass95588622020-12-22 19:30:28 -0700462 struct xemaclite *emaclite = dev_get_priv(dev);
Michal Simek36f7a412015-12-10 16:31:38 +0100463 struct emaclite_regs *regs = emaclite->regs;
464 struct ethernet_hdr *eth;
465 struct ip_udp_hdr *ip;
Michal Simek4514b372008-03-28 12:41:56 +0100466
Michal Simek36f7a412015-12-10 16:31:38 +0100467try_again:
468 if (!emaclite->use_rx_pong_buffer_next) {
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100469 reg = __raw_readl(&regs->rx_ping_rsr);
Michal Simek36f7a412015-12-10 16:31:38 +0100470 debug("Testing data at rx_ping\n");
471 if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
472 debug("Data found in rx_ping buffer\n");
473 addr = &regs->rx_ping;
474 ack = &regs->rx_ping_rsr;
475 } else {
476 debug("Data not found in rx_ping buffer\n");
477 /* Pong buffer is not available - return immediately */
478 if (!emaclite->rxpp)
479 return -1;
Michal Simekdf40ead2011-09-12 21:10:01 +0000480
Michal Simek36f7a412015-12-10 16:31:38 +0100481 /* Try pong buffer if this is first attempt */
482 if (attempt++)
483 return -1;
484 emaclite->use_rx_pong_buffer_next =
485 !emaclite->use_rx_pong_buffer_next;
486 goto try_again;
487 }
488 } else {
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100489 reg = __raw_readl(&regs->rx_pong_rsr);
Michal Simek36f7a412015-12-10 16:31:38 +0100490 debug("Testing data at rx_pong\n");
491 if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
492 debug("Data found in rx_pong buffer\n");
493 addr = &regs->rx_pong;
494 ack = &regs->rx_pong_rsr;
Michal Simekdf40ead2011-09-12 21:10:01 +0000495 } else {
Michal Simek36f7a412015-12-10 16:31:38 +0100496 debug("Data not found in rx_pong buffer\n");
497 /* Try ping buffer if this is first attempt */
498 if (attempt++)
499 return -1;
500 emaclite->use_rx_pong_buffer_next =
501 !emaclite->use_rx_pong_buffer_next;
502 goto try_again;
Michal Simek4514b372008-03-28 12:41:56 +0100503 }
Michal Simek4514b372008-03-28 12:41:56 +0100504 }
Michal Simek36f7a412015-12-10 16:31:38 +0100505
506 /* Read all bytes for ARP packet with 32bit alignment - 48bytes */
507 first_read = ALIGN(ETHER_HDR_SIZE + ARP_HDR_SIZE + ETH_FCS_LEN, 4);
508 xemaclite_alignedread(addr, etherrxbuff, first_read);
509
510 /* Detect real packet size */
511 eth = (struct ethernet_hdr *)etherrxbuff;
512 switch (ntohs(eth->et_protlen)) {
513 case PROT_ARP:
514 length = first_read;
515 debug("ARP Packet %x\n", length);
516 break;
517 case PROT_IP:
518 ip = (struct ip_udp_hdr *)(etherrxbuff + ETHER_HDR_SIZE);
519 length = ntohs(ip->ip_len);
520 length += ETHER_HDR_SIZE + ETH_FCS_LEN;
521 debug("IP Packet %x\n", length);
522 break;
523 default:
524 debug("Other Packet\n");
525 length = PKTSIZE;
526 break;
Michal Simek4514b372008-03-28 12:41:56 +0100527 }
528
Michal Simek36f7a412015-12-10 16:31:38 +0100529 /* Read the rest of the packet which is longer then first read */
530 if (length != first_read)
531 xemaclite_alignedread(addr + first_read,
532 etherrxbuff + first_read,
533 length - first_read);
Michal Simek4514b372008-03-28 12:41:56 +0100534
535 /* Acknowledge the frame */
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100536 reg = __raw_readl(ack);
Michal Simek4514b372008-03-28 12:41:56 +0100537 reg &= ~XEL_RSR_RECV_DONE_MASK;
Zubair Lutfullah Kakakhel91664592016-07-27 12:25:08 +0100538 __raw_writel(reg, ack);
Michal Simek4514b372008-03-28 12:41:56 +0100539
Michal Simek36f7a412015-12-10 16:31:38 +0100540 debug("Packet receive from 0x%p, length %dB\n", addr, length);
Michal Simek641ade02015-12-16 10:52:39 +0100541 *packetp = etherrxbuff;
542 return length;
Michal Simek912145b2015-12-10 13:33:20 +0100543}
544
Michal Simekf7cba782015-12-10 17:15:52 +0100545static int emaclite_miiphy_read(struct mii_dev *bus, int addr,
546 int devad, int reg)
Michal Simek912145b2015-12-10 13:33:20 +0100547{
548 u32 ret;
Michal Simekf7cba782015-12-10 17:15:52 +0100549 u16 val = 0;
Michal Simek912145b2015-12-10 13:33:20 +0100550
Michal Simekf7cba782015-12-10 17:15:52 +0100551 ret = phyread(bus->priv, addr, reg, &val);
552 debug("emaclite: Read MII 0x%x, 0x%x, 0x%x, %d\n", addr, reg, val, ret);
553 return val;
Michal Simek4514b372008-03-28 12:41:56 +0100554}
Michal Simekb4a1d082010-10-11 11:41:47 +1000555
Michal Simekf7cba782015-12-10 17:15:52 +0100556static int emaclite_miiphy_write(struct mii_dev *bus, int addr, int devad,
557 int reg, u16 value)
Michal Simek912145b2015-12-10 13:33:20 +0100558{
Michal Simekf7cba782015-12-10 17:15:52 +0100559 debug("emaclite: Write MII 0x%x, 0x%x, 0x%x\n", addr, reg, value);
560 return phywrite(bus->priv, addr, reg, value);
Michal Simek912145b2015-12-10 13:33:20 +0100561}
Michal Simek912145b2015-12-10 13:33:20 +0100562
Michal Simekf7cba782015-12-10 17:15:52 +0100563static int emaclite_probe(struct udevice *dev)
Michal Simekb4a1d082010-10-11 11:41:47 +1000564{
Michal Simekf7cba782015-12-10 17:15:52 +0100565 struct xemaclite *emaclite = dev_get_priv(dev);
566 int ret;
Michal Simekb4a1d082010-10-11 11:41:47 +1000567
T Karthik Reddycff10842022-05-10 13:26:10 +0200568 if (IS_ENABLED(CONFIG_DM_ETH_PHY))
569 emaclite->bus = eth_phy_get_mdio_bus(dev);
Michal Simekf35b7cd2011-08-25 12:47:56 +0200570
T Karthik Reddycff10842022-05-10 13:26:10 +0200571 if (!emaclite->bus) {
572 emaclite->bus = mdio_alloc();
573 emaclite->bus->read = emaclite_miiphy_read;
574 emaclite->bus->write = emaclite_miiphy_write;
575 emaclite->bus->priv = emaclite;
576
577 ret = mdio_register_seq(emaclite->bus, dev_seq(dev));
578 if (ret)
579 return ret;
580 }
581
582 if (IS_ENABLED(CONFIG_DM_ETH_PHY)) {
583 eth_phy_set_mdio_bus(dev, emaclite->bus);
584 emaclite->phyaddr = eth_phy_get_addr(dev);
585 }
586
587 printf("EMACLITE: %lx, phyaddr %d, %d/%d\n", (ulong)emaclite->regs,
588 emaclite->phyaddr, emaclite->txpp, emaclite->rxpp);
Michal Simekf7cba782015-12-10 17:15:52 +0100589
590 return 0;
591}
Michal Simekf35b7cd2011-08-25 12:47:56 +0200592
Michal Simekf7cba782015-12-10 17:15:52 +0100593static int emaclite_remove(struct udevice *dev)
594{
595 struct xemaclite *emaclite = dev_get_priv(dev);
596
597 free(emaclite->phydev);
598 mdio_unregister(emaclite->bus);
599 mdio_free(emaclite->bus);
Michal Simekb4a1d082010-10-11 11:41:47 +1000600
Michal Simekf7cba782015-12-10 17:15:52 +0100601 return 0;
602}
Michal Simekdf40ead2011-09-12 21:10:01 +0000603
Michal Simekf7cba782015-12-10 17:15:52 +0100604static const struct eth_ops emaclite_ops = {
Michal Simekfeebc8a2015-12-16 10:40:05 +0100605 .start = emaclite_start,
Michal Simekf7cba782015-12-10 17:15:52 +0100606 .send = emaclite_send,
607 .recv = emaclite_recv,
Michal Simekfeebc8a2015-12-16 10:40:05 +0100608 .stop = emaclite_stop,
Michal Simekf7cba782015-12-10 17:15:52 +0100609};
610
Simon Glassaad29ae2020-12-03 16:55:21 -0700611static int emaclite_of_to_plat(struct udevice *dev)
Michal Simekf7cba782015-12-10 17:15:52 +0100612{
Simon Glassfa20e932020-12-03 16:55:20 -0700613 struct eth_pdata *pdata = dev_get_plat(dev);
Michal Simekf7cba782015-12-10 17:15:52 +0100614 struct xemaclite *emaclite = dev_get_priv(dev);
615 int offset = 0;
Michal Simekb4a1d082010-10-11 11:41:47 +1000616
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900617 pdata->iobase = dev_read_addr(dev);
Zubair Lutfullah Kakakheld23bf842016-07-27 12:25:07 +0100618 emaclite->regs = (struct emaclite_regs *)ioremap_nocache(pdata->iobase,
619 0x10000);
Michal Simekb4a1d082010-10-11 11:41:47 +1000620
Michal Simek912145b2015-12-10 13:33:20 +0100621 emaclite->phyaddr = -1;
Michal Simek912145b2015-12-10 13:33:20 +0100622
T Karthik Reddycff10842022-05-10 13:26:10 +0200623 if (!(IS_ENABLED(CONFIG_DM_ETH_PHY))) {
624 offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev),
625 "phy-handle");
626 if (offset > 0)
627 emaclite->phyaddr = fdtdec_get_int(gd->fdt_blob,
628 offset, "reg", -1);
629 }
Michal Simekb4a1d082010-10-11 11:41:47 +1000630
Simon Glassdd79d6e2017-01-17 16:52:55 -0700631 emaclite->txpp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
Michal Simekf7cba782015-12-10 17:15:52 +0100632 "xlnx,tx-ping-pong", 0);
Simon Glassdd79d6e2017-01-17 16:52:55 -0700633 emaclite->rxpp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
Michal Simekf7cba782015-12-10 17:15:52 +0100634 "xlnx,rx-ping-pong", 0);
Michal Simek912145b2015-12-10 13:33:20 +0100635
Michal Simekf7cba782015-12-10 17:15:52 +0100636 return 0;
Michal Simekb4a1d082010-10-11 11:41:47 +1000637}
Michal Simekf7cba782015-12-10 17:15:52 +0100638
639static const struct udevice_id emaclite_ids[] = {
640 { .compatible = "xlnx,xps-ethernetlite-1.00.a" },
641 { }
642};
643
644U_BOOT_DRIVER(emaclite) = {
645 .name = "emaclite",
646 .id = UCLASS_ETH,
647 .of_match = emaclite_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700648 .of_to_plat = emaclite_of_to_plat,
Michal Simekf7cba782015-12-10 17:15:52 +0100649 .probe = emaclite_probe,
650 .remove = emaclite_remove,
651 .ops = &emaclite_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700652 .priv_auto = sizeof(struct xemaclite),
Simon Glass71fa5b42020-12-03 16:55:18 -0700653 .plat_auto = sizeof(struct eth_pdata),
Michal Simekf7cba782015-12-10 17:15:52 +0100654};