blob: a174344b3ef512414b7639c13f7fb99f20253bbf [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Vipin KUMAR5b1b1882010-06-29 10:53:34 +05302/*
3 * (C) Copyright 2010
Patrick Delaunayeae488b2022-05-20 18:38:10 +02004 * Vipin Kumar, STMicroelectronics, vipin.kumar@st.com.
Vipin KUMAR5b1b1882010-06-29 10:53:34 +05305 */
6
7/*
Simon Glass64dcd252015-04-05 16:07:40 -06008 * Designware ethernet IP driver for U-Boot
Vipin KUMAR5b1b1882010-06-29 10:53:34 +05309 */
10
11#include <common.h>
Patrice Chotardba1f9662017-11-29 09:06:11 +010012#include <clk.h>
Simon Glass1eb69ae2019-11-14 12:57:39 -070013#include <cpu_func.h>
Simon Glass75577ba2015-04-05 16:07:41 -060014#include <dm.h>
Simon Glass64dcd252015-04-05 16:07:40 -060015#include <errno.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060016#include <log.h>
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053017#include <miiphy.h>
18#include <malloc.h>
Simon Glass90526e92020-05-10 11:39:56 -060019#include <net.h>
Bin Meng8b7ee662015-09-11 03:24:35 -070020#include <pci.h>
Ley Foon Tan495c70f2018-06-14 18:45:23 +080021#include <reset.h>
Baruch Siachd44f3d22023-10-25 11:08:44 +030022#include <phys2bus.h>
Simon Glass90526e92020-05-10 11:39:56 -060023#include <asm/cache.h>
Simon Glass336d4612020-02-03 07:36:16 -070024#include <dm/device_compat.h>
Neil Armstrong5160b452021-02-24 15:02:39 +010025#include <dm/device-internal.h>
Simon Glass61b29b82020-02-03 07:36:15 -070026#include <dm/devres.h>
Neil Armstrong5160b452021-02-24 15:02:39 +010027#include <dm/lists.h>
Stefan Roeseef760252012-05-07 12:04:25 +020028#include <linux/compiler.h>
Simon Glassc05ed002020-05-10 11:40:11 -060029#include <linux/delay.h>
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053030#include <linux/err.h>
Florian Fainelli7a9ca9d2017-12-09 14:59:55 -080031#include <linux/kernel.h>
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053032#include <asm/io.h>
Simon Glass1e94b462023-09-14 18:21:46 -060033#include <linux/printk.h>
Jacob Chen6ec922f2017-03-27 16:54:17 +080034#include <power/regulator.h>
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053035#include "designware.h"
36
Alexey Brodkin92a190a2014-01-22 20:54:06 +040037static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
38{
Sjoerd Simons90b7fc92016-02-28 22:24:55 +010039 struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv);
40 struct eth_mac_regs *mac_p = priv->mac_regs_p;
Alexey Brodkin92a190a2014-01-22 20:54:06 +040041 ulong start;
42 u16 miiaddr;
Tom Rini6e7df1d2023-01-10 11:19:45 -050043 int timeout = CFG_MDIO_TIMEOUT;
Alexey Brodkin92a190a2014-01-22 20:54:06 +040044
45 miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
46 ((reg << MIIREGSHIFT) & MII_REGMSK);
47
48 writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
49
50 start = get_timer(0);
51 while (get_timer(start) < timeout) {
52 if (!(readl(&mac_p->miiaddr) & MII_BUSY))
53 return readl(&mac_p->miidata);
54 udelay(10);
55 };
56
Simon Glass64dcd252015-04-05 16:07:40 -060057 return -ETIMEDOUT;
Alexey Brodkin92a190a2014-01-22 20:54:06 +040058}
59
60static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
61 u16 val)
62{
Sjoerd Simons90b7fc92016-02-28 22:24:55 +010063 struct dw_eth_dev *priv = dev_get_priv((struct udevice *)bus->priv);
64 struct eth_mac_regs *mac_p = priv->mac_regs_p;
Alexey Brodkin92a190a2014-01-22 20:54:06 +040065 ulong start;
66 u16 miiaddr;
Tom Rini6e7df1d2023-01-10 11:19:45 -050067 int ret = -ETIMEDOUT, timeout = CFG_MDIO_TIMEOUT;
Alexey Brodkin92a190a2014-01-22 20:54:06 +040068
69 writel(val, &mac_p->miidata);
70 miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
71 ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE;
72
73 writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
74
75 start = get_timer(0);
76 while (get_timer(start) < timeout) {
77 if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
78 ret = 0;
79 break;
80 }
81 udelay(10);
82 };
83
84 return ret;
85}
86
Tom Riniacb30cc2022-11-27 10:25:07 -050087#if CONFIG_IS_ENABLED(DM_GPIO)
Neil Armstrong98b82042021-04-21 10:58:01 +020088static int __dw_mdio_reset(struct udevice *dev)
Sjoerd Simons90b7fc92016-02-28 22:24:55 +010089{
Sjoerd Simons90b7fc92016-02-28 22:24:55 +010090 struct dw_eth_dev *priv = dev_get_priv(dev);
Simon Glassc69cda22020-12-03 16:55:20 -070091 struct dw_eth_pdata *pdata = dev_get_plat(dev);
Sjoerd Simons90b7fc92016-02-28 22:24:55 +010092 int ret;
93
94 if (!dm_gpio_is_valid(&priv->reset_gpio))
95 return 0;
96
97 /* reset the phy */
98 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
99 if (ret)
100 return ret;
101
102 udelay(pdata->reset_delays[0]);
103
104 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
105 if (ret)
106 return ret;
107
108 udelay(pdata->reset_delays[1]);
109
110 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
111 if (ret)
112 return ret;
113
114 udelay(pdata->reset_delays[2]);
115
116 return 0;
117}
Neil Armstrong98b82042021-04-21 10:58:01 +0200118
119static int dw_mdio_reset(struct mii_dev *bus)
120{
121 struct udevice *dev = bus->priv;
122
123 return __dw_mdio_reset(dev);
124}
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100125#endif
126
Neil Armstrong5160b452021-02-24 15:02:39 +0100127#if IS_ENABLED(CONFIG_DM_MDIO)
128int designware_eth_mdio_read(struct udevice *mdio_dev, int addr, int devad, int reg)
129{
130 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdio_dev);
131
132 return dw_mdio_read(pdata->mii_bus, addr, devad, reg);
133}
134
135int designware_eth_mdio_write(struct udevice *mdio_dev, int addr, int devad, int reg, u16 val)
136{
137 struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdio_dev);
138
139 return dw_mdio_write(pdata->mii_bus, addr, devad, reg, val);
140}
141
142#if CONFIG_IS_ENABLED(DM_GPIO)
143int designware_eth_mdio_reset(struct udevice *mdio_dev)
144{
Neil Armstrong98b82042021-04-21 10:58:01 +0200145 struct mdio_perdev_priv *mdio_pdata = dev_get_uclass_priv(mdio_dev);
146 struct udevice *dev = mdio_pdata->mii_bus->priv;
Neil Armstrong5160b452021-02-24 15:02:39 +0100147
Neil Armstrong98b82042021-04-21 10:58:01 +0200148 return __dw_mdio_reset(dev->parent);
Neil Armstrong5160b452021-02-24 15:02:39 +0100149}
150#endif
151
152static const struct mdio_ops designware_eth_mdio_ops = {
153 .read = designware_eth_mdio_read,
154 .write = designware_eth_mdio_write,
155#if CONFIG_IS_ENABLED(DM_GPIO)
156 .reset = designware_eth_mdio_reset,
157#endif
158};
159
160static int designware_eth_mdio_probe(struct udevice *dev)
161{
162 /* Use the priv data of parent */
163 dev_set_priv(dev, dev_get_priv(dev->parent));
164
165 return 0;
166}
167
168U_BOOT_DRIVER(designware_eth_mdio) = {
169 .name = "eth_designware_mdio",
170 .id = UCLASS_MDIO,
171 .probe = designware_eth_mdio_probe,
172 .ops = &designware_eth_mdio_ops,
173 .plat_auto = sizeof(struct mdio_perdev_priv),
174};
175#endif
176
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100177static int dw_mdio_init(const char *name, void *priv)
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400178{
179 struct mii_dev *bus = mdio_alloc();
180
181 if (!bus) {
182 printf("Failed to allocate MDIO bus\n");
Simon Glass64dcd252015-04-05 16:07:40 -0600183 return -ENOMEM;
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400184 }
185
186 bus->read = dw_mdio_read;
187 bus->write = dw_mdio_write;
Ben Whitten192bc692015-12-30 13:05:58 +0000188 snprintf(bus->name, sizeof(bus->name), "%s", name);
Tom Riniacb30cc2022-11-27 10:25:07 -0500189#if CONFIG_IS_ENABLED(DM_GPIO)
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100190 bus->reset = dw_mdio_reset;
191#endif
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400192
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100193 bus->priv = priv;
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400194
195 return mdio_register(bus);
196}
Vipin Kumar13edd172012-03-26 00:09:56 +0000197
Neil Armstrong5160b452021-02-24 15:02:39 +0100198#if IS_ENABLED(CONFIG_DM_MDIO)
199static int dw_dm_mdio_init(const char *name, void *priv)
200{
201 struct udevice *dev = priv;
202 ofnode node;
203 int ret;
204
205 ofnode_for_each_subnode(node, dev_ofnode(dev)) {
206 const char *subnode_name = ofnode_get_name(node);
207 struct udevice *mdiodev;
208
209 if (strcmp(subnode_name, "mdio"))
210 continue;
211
212 ret = device_bind_driver_to_node(dev, "eth_designware_mdio",
213 subnode_name, node, &mdiodev);
214 if (ret)
215 debug("%s: not able to bind mdio device node\n", __func__);
216
217 return 0;
218 }
219
220 printf("%s: mdio node is missing, registering legacy mdio bus", __func__);
221
222 return dw_mdio_init(name, priv);
223}
224#endif
225
Simon Glass64dcd252015-04-05 16:07:40 -0600226static void tx_descs_init(struct dw_eth_dev *priv)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530227{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530228 struct eth_dma_regs *dma_p = priv->dma_regs_p;
229 struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
230 char *txbuffs = &priv->txbuffs[0];
231 struct dmamacdescr *desc_p;
232 u32 idx;
233
Tom Rini6e7df1d2023-01-10 11:19:45 -0500234 for (idx = 0; idx < CFG_TX_DESCR_NUM; idx++) {
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530235 desc_p = &desc_table_p[idx];
Baruch Siachd44f3d22023-10-25 11:08:44 +0300236 desc_p->dmamac_addr = dev_phys_to_bus(priv->dev,
237 (ulong)&txbuffs[idx * CFG_ETH_BUFSIZE]);
238 desc_p->dmamac_next = dev_phys_to_bus(priv->dev,
239 (ulong)&desc_table_p[idx + 1]);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530240
241#if defined(CONFIG_DW_ALTDESCRIPTOR)
242 desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
Marek Vasut2b261092015-12-20 03:59:23 +0100243 DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS |
244 DESC_TXSTS_TXCHECKINSCTRL |
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530245 DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
246
247 desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
248 desc_p->dmamac_cntl = 0;
249 desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
250#else
251 desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
252 desc_p->txrx_status = 0;
253#endif
254 }
255
256 /* Correcting the last pointer of the chain */
Baruch Siachd44f3d22023-10-25 11:08:44 +0300257 desc_p->dmamac_next = dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530258
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400259 /* Flush all Tx buffer descriptors at once */
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200260 flush_dcache_range((ulong)priv->tx_mac_descrtable,
261 (ulong)priv->tx_mac_descrtable +
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400262 sizeof(priv->tx_mac_descrtable));
263
Baruch Siachd44f3d22023-10-25 11:08:44 +0300264 writel(dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]),
265 &dma_p->txdesclistaddr);
Alexey Brodkin74cb7082014-01-13 13:28:38 +0400266 priv->tx_currdescnum = 0;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530267}
268
Simon Glass64dcd252015-04-05 16:07:40 -0600269static void rx_descs_init(struct dw_eth_dev *priv)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530270{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530271 struct eth_dma_regs *dma_p = priv->dma_regs_p;
272 struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
273 char *rxbuffs = &priv->rxbuffs[0];
274 struct dmamacdescr *desc_p;
275 u32 idx;
276
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400277 /* Before passing buffers to GMAC we need to make sure zeros
278 * written there right after "priv" structure allocation were
279 * flushed into RAM.
280 * Otherwise there's a chance to get some of them flushed in RAM when
281 * GMAC is already pushing data to RAM via DMA. This way incoming from
282 * GMAC data will be corrupted. */
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200283 flush_dcache_range((ulong)rxbuffs, (ulong)rxbuffs + RX_TOTAL_BUFSIZE);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400284
Tom Rini6e7df1d2023-01-10 11:19:45 -0500285 for (idx = 0; idx < CFG_RX_DESCR_NUM; idx++) {
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530286 desc_p = &desc_table_p[idx];
Baruch Siachd44f3d22023-10-25 11:08:44 +0300287 desc_p->dmamac_addr = dev_phys_to_bus(priv->dev,
288 (ulong)&rxbuffs[idx * CFG_ETH_BUFSIZE]);
289 desc_p->dmamac_next = dev_phys_to_bus(priv->dev,
290 (ulong)&desc_table_p[idx + 1]);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530291
292 desc_p->dmamac_cntl =
Marek Vasut2b261092015-12-20 03:59:23 +0100293 (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) |
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530294 DESC_RXCTRL_RXCHAIN;
295
296 desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
297 }
298
299 /* Correcting the last pointer of the chain */
Baruch Siachd44f3d22023-10-25 11:08:44 +0300300 desc_p->dmamac_next = dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530301
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400302 /* Flush all Rx buffer descriptors at once */
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200303 flush_dcache_range((ulong)priv->rx_mac_descrtable,
304 (ulong)priv->rx_mac_descrtable +
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400305 sizeof(priv->rx_mac_descrtable));
306
Baruch Siachd44f3d22023-10-25 11:08:44 +0300307 writel(dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]),
308 &dma_p->rxdesclistaddr);
Alexey Brodkin74cb7082014-01-13 13:28:38 +0400309 priv->rx_currdescnum = 0;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530310}
311
Simon Glass64dcd252015-04-05 16:07:40 -0600312static int _dw_write_hwaddr(struct dw_eth_dev *priv, u8 *mac_id)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530313{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530314 struct eth_mac_regs *mac_p = priv->mac_regs_p;
315 u32 macid_lo, macid_hi;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530316
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400317 macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
318 (mac_id[3] << 24);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530319 macid_hi = mac_id[4] + (mac_id[5] << 8);
320
321 writel(macid_hi, &mac_p->macaddr0hi);
322 writel(macid_lo, &mac_p->macaddr0lo);
323
324 return 0;
325}
326
Simon Glass0ea38db2017-01-11 11:46:08 +0100327static int dw_adjust_link(struct dw_eth_dev *priv, struct eth_mac_regs *mac_p,
328 struct phy_device *phydev)
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400329{
330 u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN;
331
332 if (!phydev->link) {
333 printf("%s: No link.\n", phydev->dev->name);
Simon Glass0ea38db2017-01-11 11:46:08 +0100334 return 0;
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400335 }
336
337 if (phydev->speed != 1000)
338 conf |= MII_PORTSELECT;
Alexey Brodkinb884c3f2016-01-13 16:59:36 +0300339 else
340 conf &= ~MII_PORTSELECT;
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400341
342 if (phydev->speed == 100)
343 conf |= FES_100;
344
345 if (phydev->duplex)
346 conf |= FULLDPLXMODE;
347
348 writel(conf, &mac_p->conf);
349
350 printf("Speed: %d, %s duplex%s\n", phydev->speed,
351 (phydev->duplex) ? "full" : "half",
352 (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
Simon Glass0ea38db2017-01-11 11:46:08 +0100353
354 return 0;
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400355}
356
Simon Glass64dcd252015-04-05 16:07:40 -0600357static void _dw_eth_halt(struct dw_eth_dev *priv)
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400358{
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400359 struct eth_mac_regs *mac_p = priv->mac_regs_p;
360 struct eth_dma_regs *dma_p = priv->dma_regs_p;
361
362 writel(readl(&mac_p->conf) & ~(RXENABLE | TXENABLE), &mac_p->conf);
363 writel(readl(&dma_p->opmode) & ~(RXSTART | TXSTART), &dma_p->opmode);
364
365 phy_shutdown(priv->phydev);
366}
367
Simon Glasse72ced22017-01-11 11:46:10 +0100368int designware_eth_init(struct dw_eth_dev *priv, u8 *enetaddr)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530369{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530370 struct eth_mac_regs *mac_p = priv->mac_regs_p;
371 struct eth_dma_regs *dma_p = priv->dma_regs_p;
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400372 unsigned int start;
Simon Glass64dcd252015-04-05 16:07:40 -0600373 int ret;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530374
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400375 writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode);
Vipin Kumar13edd172012-03-26 00:09:56 +0000376
Quentin Schulzc6122192018-06-04 12:17:33 +0200377 /*
378 * When a MII PHY is used, we must set the PS bit for the DMA
379 * reset to succeed.
380 */
381 if (priv->phydev->interface == PHY_INTERFACE_MODE_MII)
382 writel(readl(&mac_p->conf) | MII_PORTSELECT, &mac_p->conf);
383 else
384 writel(readl(&mac_p->conf) & ~MII_PORTSELECT, &mac_p->conf);
385
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400386 start = get_timer(0);
387 while (readl(&dma_p->busmode) & DMAMAC_SRST) {
Tom Rini6e7df1d2023-01-10 11:19:45 -0500388 if (get_timer(start) >= CFG_MACRESET_TIMEOUT) {
Alexey Brodkin875143f2015-01-13 17:10:24 +0300389 printf("DMA reset timeout\n");
Simon Glass64dcd252015-04-05 16:07:40 -0600390 return -ETIMEDOUT;
Alexey Brodkin875143f2015-01-13 17:10:24 +0300391 }
Stefan Roeseef760252012-05-07 12:04:25 +0200392
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400393 mdelay(100);
394 };
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530395
Bin Mengf3edfd32015-06-15 18:40:19 +0800396 /*
397 * Soft reset above clears HW address registers.
398 * So we have to set it here once again.
399 */
400 _dw_write_hwaddr(priv, enetaddr);
401
Simon Glass64dcd252015-04-05 16:07:40 -0600402 rx_descs_init(priv);
403 tx_descs_init(priv);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530404
Ian Campbell49692c52014-05-08 22:26:35 +0100405 writel(FIXEDBURST | PRIORXTX_41 | DMA_PBL, &dma_p->busmode);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530406
Sonic Zhangd2279222015-01-29 14:38:50 +0800407#ifndef CONFIG_DW_MAC_FORCE_THRESHOLD_MODE
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400408 writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD,
409 &dma_p->opmode);
Sonic Zhangd2279222015-01-29 14:38:50 +0800410#else
411 writel(readl(&dma_p->opmode) | FLUSHTXFIFO,
412 &dma_p->opmode);
413#endif
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530414
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400415 writel(readl(&dma_p->opmode) | RXSTART | TXSTART, &dma_p->opmode);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530416
Sonic Zhang2ddaf132015-01-29 13:37:31 +0800417#ifdef CONFIG_DW_AXI_BURST_LEN
418 writel((CONFIG_DW_AXI_BURST_LEN & 0x1FF >> 1), &dma_p->axibus);
419#endif
420
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400421 /* Start up the PHY */
Simon Glass64dcd252015-04-05 16:07:40 -0600422 ret = phy_startup(priv->phydev);
423 if (ret) {
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400424 printf("Could not initialize PHY %s\n",
425 priv->phydev->dev->name);
Simon Glass64dcd252015-04-05 16:07:40 -0600426 return ret;
Vipin Kumar9afc1af2012-05-07 13:06:44 +0530427 }
428
Simon Glass0ea38db2017-01-11 11:46:08 +0100429 ret = dw_adjust_link(priv, mac_p, priv->phydev);
430 if (ret)
431 return ret;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530432
Simon Glassf63f28e2017-01-11 11:46:09 +0100433 return 0;
434}
435
Simon Glasse72ced22017-01-11 11:46:10 +0100436int designware_eth_enable(struct dw_eth_dev *priv)
Simon Glassf63f28e2017-01-11 11:46:09 +0100437{
438 struct eth_mac_regs *mac_p = priv->mac_regs_p;
439
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400440 if (!priv->phydev->link)
Simon Glass64dcd252015-04-05 16:07:40 -0600441 return -EIO;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530442
Armando Viscontiaa510052012-03-26 00:09:55 +0000443 writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530444
445 return 0;
446}
447
Florian Fainelli7a9ca9d2017-12-09 14:59:55 -0800448#define ETH_ZLEN 60
449
Simon Glass64dcd252015-04-05 16:07:40 -0600450static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530451{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530452 struct eth_dma_regs *dma_p = priv->dma_regs_p;
453 u32 desc_num = priv->tx_currdescnum;
454 struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200455 ulong desc_start = (ulong)desc_p;
456 ulong desc_end = desc_start +
Marek Vasut96cec172014-09-15 01:05:23 +0200457 roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
Baruch Siachd44f3d22023-10-25 11:08:44 +0300458 ulong data_start = dev_bus_to_phys(priv->dev, desc_p->dmamac_addr);
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200459 ulong data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
Ian Campbell964ea7c2014-05-08 22:26:33 +0100460 /*
461 * Strictly we only need to invalidate the "txrx_status" field
462 * for the following check, but on some platforms we cannot
Marek Vasut96cec172014-09-15 01:05:23 +0200463 * invalidate only 4 bytes, so we flush the entire descriptor,
464 * which is 16 bytes in total. This is safe because the
465 * individual descriptors in the array are each aligned to
466 * ARCH_DMA_MINALIGN and padded appropriately.
Ian Campbell964ea7c2014-05-08 22:26:33 +0100467 */
Marek Vasut96cec172014-09-15 01:05:23 +0200468 invalidate_dcache_range(desc_start, desc_end);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400469
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530470 /* Check if the descriptor is owned by CPU */
471 if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
472 printf("CPU not owner of tx frame\n");
Simon Glass64dcd252015-04-05 16:07:40 -0600473 return -EPERM;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530474 }
475
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200476 memcpy((void *)data_start, packet, length);
Simon Goldschmidt7efb75b2018-11-17 10:24:42 +0100477 if (length < ETH_ZLEN) {
478 memset(&((char *)data_start)[length], 0, ETH_ZLEN - length);
479 length = ETH_ZLEN;
480 }
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530481
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400482 /* Flush data to be sent */
Marek Vasut96cec172014-09-15 01:05:23 +0200483 flush_dcache_range(data_start, data_end);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400484
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530485#if defined(CONFIG_DW_ALTDESCRIPTOR)
486 desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
Simon Goldschmidtae8ac8d2018-11-17 10:24:41 +0100487 desc_p->dmamac_cntl = (desc_p->dmamac_cntl & ~DESC_TXCTRL_SIZE1MASK) |
488 ((length << DESC_TXCTRL_SIZE1SHFT) &
489 DESC_TXCTRL_SIZE1MASK);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530490
491 desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
492 desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
493#else
Simon Goldschmidtae8ac8d2018-11-17 10:24:41 +0100494 desc_p->dmamac_cntl = (desc_p->dmamac_cntl & ~DESC_TXCTRL_SIZE1MASK) |
495 ((length << DESC_TXCTRL_SIZE1SHFT) &
496 DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST |
497 DESC_TXCTRL_TXFIRST;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530498
499 desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
500#endif
501
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400502 /* Flush modified buffer descriptor */
Marek Vasut96cec172014-09-15 01:05:23 +0200503 flush_dcache_range(desc_start, desc_end);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400504
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530505 /* Test the wrap-around condition. */
Tom Rini6e7df1d2023-01-10 11:19:45 -0500506 if (++desc_num >= CFG_TX_DESCR_NUM)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530507 desc_num = 0;
508
509 priv->tx_currdescnum = desc_num;
510
511 /* Start the transmission */
512 writel(POLL_DATA, &dma_p->txpolldemand);
513
514 return 0;
515}
516
Simon Glass75577ba2015-04-05 16:07:41 -0600517static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530518{
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400519 u32 status, desc_num = priv->rx_currdescnum;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530520 struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
Simon Glass75577ba2015-04-05 16:07:41 -0600521 int length = -EAGAIN;
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200522 ulong desc_start = (ulong)desc_p;
523 ulong desc_end = desc_start +
Marek Vasut96cec172014-09-15 01:05:23 +0200524 roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
Baruch Siachd44f3d22023-10-25 11:08:44 +0300525 ulong data_start = dev_bus_to_phys(priv->dev, desc_p->dmamac_addr);
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200526 ulong data_end;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530527
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400528 /* Invalidate entire buffer descriptor */
Marek Vasut96cec172014-09-15 01:05:23 +0200529 invalidate_dcache_range(desc_start, desc_end);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400530
531 status = desc_p->txrx_status;
532
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530533 /* Check if the owner is the CPU */
534 if (!(status & DESC_RXSTS_OWNBYDMA)) {
535
Marek Vasut2b261092015-12-20 03:59:23 +0100536 length = (status & DESC_RXSTS_FRMLENMSK) >>
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530537 DESC_RXSTS_FRMLENSHFT;
538
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400539 /* Invalidate received data */
Marek Vasut96cec172014-09-15 01:05:23 +0200540 data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
541 invalidate_dcache_range(data_start, data_end);
Baruch Siachd44f3d22023-10-25 11:08:44 +0300542 *packetp = (uchar *)(ulong)dev_bus_to_phys(priv->dev,
543 desc_p->dmamac_addr);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530544 }
545
Simon Glass75577ba2015-04-05 16:07:41 -0600546 return length;
547}
548
549static int _dw_free_pkt(struct dw_eth_dev *priv)
550{
551 u32 desc_num = priv->rx_currdescnum;
552 struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200553 ulong desc_start = (ulong)desc_p;
554 ulong desc_end = desc_start +
Simon Glass75577ba2015-04-05 16:07:41 -0600555 roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
556
557 /*
558 * Make the current descriptor valid again and go to
559 * the next one
560 */
561 desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
562
563 /* Flush only status field - others weren't changed */
564 flush_dcache_range(desc_start, desc_end);
565
566 /* Test the wrap-around condition. */
Tom Rini6e7df1d2023-01-10 11:19:45 -0500567 if (++desc_num >= CFG_RX_DESCR_NUM)
Simon Glass75577ba2015-04-05 16:07:41 -0600568 desc_num = 0;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530569 priv->rx_currdescnum = desc_num;
570
Simon Glass75577ba2015-04-05 16:07:41 -0600571 return 0;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530572}
573
Simon Glass64dcd252015-04-05 16:07:40 -0600574static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530575{
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400576 struct phy_device *phydev;
Neil Armstrong5160b452021-02-24 15:02:39 +0100577 int ret;
578
Tom Riniacb30cc2022-11-27 10:25:07 -0500579#if IS_ENABLED(CONFIG_DM_MDIO)
Neil Armstrong5160b452021-02-24 15:02:39 +0100580 phydev = dm_eth_phy_connect(dev);
581 if (!phydev)
582 return -ENODEV;
583#else
584 int phy_addr = -1;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530585
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400586#ifdef CONFIG_PHY_ADDR
Simon Goldschmidt5dce9df2019-07-15 21:53:05 +0200587 phy_addr = CONFIG_PHY_ADDR;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530588#endif
589
Simon Goldschmidt5dce9df2019-07-15 21:53:05 +0200590 phydev = phy_connect(priv->bus, phy_addr, dev, priv->interface);
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400591 if (!phydev)
Simon Glass64dcd252015-04-05 16:07:40 -0600592 return -ENODEV;
Neil Armstrong5160b452021-02-24 15:02:39 +0100593#endif
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530594
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400595 phydev->supported &= PHY_GBIT_FEATURES;
Alexey Brodkin6968ec92016-01-13 16:59:37 +0300596 if (priv->max_speed) {
597 ret = phy_set_supported(phydev, priv->max_speed);
598 if (ret)
599 return ret;
600 }
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400601 phydev->advertising = phydev->supported;
602
603 priv->phydev = phydev;
604 phy_config(phydev);
605
Simon Glass64dcd252015-04-05 16:07:40 -0600606 return 0;
607}
608
Simon Glass75577ba2015-04-05 16:07:41 -0600609static int designware_eth_start(struct udevice *dev)
610{
Simon Glassc69cda22020-12-03 16:55:20 -0700611 struct eth_pdata *pdata = dev_get_plat(dev);
Simon Glassf63f28e2017-01-11 11:46:09 +0100612 struct dw_eth_dev *priv = dev_get_priv(dev);
613 int ret;
Simon Glass75577ba2015-04-05 16:07:41 -0600614
Simon Glasse72ced22017-01-11 11:46:10 +0100615 ret = designware_eth_init(priv, pdata->enetaddr);
Simon Glassf63f28e2017-01-11 11:46:09 +0100616 if (ret)
617 return ret;
618 ret = designware_eth_enable(priv);
619 if (ret)
620 return ret;
621
622 return 0;
Simon Glass75577ba2015-04-05 16:07:41 -0600623}
624
Simon Glasse72ced22017-01-11 11:46:10 +0100625int designware_eth_send(struct udevice *dev, void *packet, int length)
Simon Glass75577ba2015-04-05 16:07:41 -0600626{
627 struct dw_eth_dev *priv = dev_get_priv(dev);
628
629 return _dw_eth_send(priv, packet, length);
630}
631
Simon Glasse72ced22017-01-11 11:46:10 +0100632int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp)
Simon Glass75577ba2015-04-05 16:07:41 -0600633{
634 struct dw_eth_dev *priv = dev_get_priv(dev);
635
636 return _dw_eth_recv(priv, packetp);
637}
638
Simon Glasse72ced22017-01-11 11:46:10 +0100639int designware_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
Simon Glass75577ba2015-04-05 16:07:41 -0600640{
641 struct dw_eth_dev *priv = dev_get_priv(dev);
642
643 return _dw_free_pkt(priv);
644}
645
Simon Glasse72ced22017-01-11 11:46:10 +0100646void designware_eth_stop(struct udevice *dev)
Simon Glass75577ba2015-04-05 16:07:41 -0600647{
648 struct dw_eth_dev *priv = dev_get_priv(dev);
649
650 return _dw_eth_halt(priv);
651}
652
Simon Glasse72ced22017-01-11 11:46:10 +0100653int designware_eth_write_hwaddr(struct udevice *dev)
Simon Glass75577ba2015-04-05 16:07:41 -0600654{
Simon Glassc69cda22020-12-03 16:55:20 -0700655 struct eth_pdata *pdata = dev_get_plat(dev);
Simon Glass75577ba2015-04-05 16:07:41 -0600656 struct dw_eth_dev *priv = dev_get_priv(dev);
657
658 return _dw_write_hwaddr(priv, pdata->enetaddr);
659}
660
Bin Meng8b7ee662015-09-11 03:24:35 -0700661static int designware_eth_bind(struct udevice *dev)
662{
Simon Glasse882a592021-08-01 18:54:34 -0600663 if (IS_ENABLED(CONFIG_PCI)) {
664 static int num_cards;
665 char name[20];
Bin Meng8b7ee662015-09-11 03:24:35 -0700666
Simon Glasse882a592021-08-01 18:54:34 -0600667 /* Create a unique device name for PCI type devices */
668 if (device_is_on_pci_bus(dev)) {
669 sprintf(name, "eth_designware#%u", num_cards++);
670 device_set_name(dev, name);
671 }
Bin Meng8b7ee662015-09-11 03:24:35 -0700672 }
Bin Meng8b7ee662015-09-11 03:24:35 -0700673
674 return 0;
675}
676
Sjoerd Simonsb9e08d02017-01-11 11:46:07 +0100677int designware_eth_probe(struct udevice *dev)
Simon Glass75577ba2015-04-05 16:07:41 -0600678{
Simon Glassc69cda22020-12-03 16:55:20 -0700679 struct eth_pdata *pdata = dev_get_plat(dev);
Simon Glass75577ba2015-04-05 16:07:41 -0600680 struct dw_eth_dev *priv = dev_get_priv(dev);
Bin Mengf0dc73c2015-09-03 05:37:29 -0700681 u32 iobase = pdata->iobase;
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200682 ulong ioaddr;
Simon Goldschmidt4ee587e2019-07-12 21:07:03 +0200683 int ret, err;
Ley Foon Tan495c70f2018-06-14 18:45:23 +0800684 struct reset_ctl_bulk reset_bulk;
Patrice Chotardba1f9662017-11-29 09:06:11 +0100685#ifdef CONFIG_CLK
Simon Goldschmidt4ee587e2019-07-12 21:07:03 +0200686 int i, clock_nb;
Patrice Chotardba1f9662017-11-29 09:06:11 +0100687
688 priv->clock_count = 0;
Patrick Delaunay89f68302020-09-25 09:41:14 +0200689 clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells",
690 0);
Patrice Chotardba1f9662017-11-29 09:06:11 +0100691 if (clock_nb > 0) {
692 priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
693 GFP_KERNEL);
694 if (!priv->clocks)
695 return -ENOMEM;
696
697 for (i = 0; i < clock_nb; i++) {
698 err = clk_get_by_index(dev, i, &priv->clocks[i]);
699 if (err < 0)
700 break;
701
702 err = clk_enable(&priv->clocks[i]);
Eugeniy Paltsev1693a572018-02-06 17:12:09 +0300703 if (err && err != -ENOSYS && err != -ENOTSUPP) {
Patrice Chotardba1f9662017-11-29 09:06:11 +0100704 pr_err("failed to enable clock %d\n", i);
705 clk_free(&priv->clocks[i]);
706 goto clk_err;
707 }
708 priv->clock_count++;
709 }
710 } else if (clock_nb != -ENOENT) {
711 pr_err("failed to get clock phandle(%d)\n", clock_nb);
712 return clock_nb;
713 }
714#endif
Simon Glass75577ba2015-04-05 16:07:41 -0600715
Jacob Chen6ec922f2017-03-27 16:54:17 +0800716#if defined(CONFIG_DM_REGULATOR)
717 struct udevice *phy_supply;
718
719 ret = device_get_supply_regulator(dev, "phy-supply",
720 &phy_supply);
721 if (ret) {
722 debug("%s: No phy supply\n", dev->name);
723 } else {
724 ret = regulator_set_enable(phy_supply, true);
725 if (ret) {
726 puts("Error enabling phy supply\n");
727 return ret;
728 }
729 }
730#endif
731
Ley Foon Tan495c70f2018-06-14 18:45:23 +0800732 ret = reset_get_bulk(dev, &reset_bulk);
733 if (ret)
734 dev_warn(dev, "Can't get reset: %d\n", ret);
735 else
736 reset_deassert_bulk(&reset_bulk);
737
Bin Meng8b7ee662015-09-11 03:24:35 -0700738 /*
739 * If we are on PCI bus, either directly attached to a PCI root port,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700740 * or via a PCI bridge, fill in plat before we probe the hardware.
Bin Meng8b7ee662015-09-11 03:24:35 -0700741 */
Simon Glasse882a592021-08-01 18:54:34 -0600742 if (IS_ENABLED(CONFIG_PCI) && device_is_on_pci_bus(dev)) {
Bin Meng8b7ee662015-09-11 03:24:35 -0700743 dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase);
744 iobase &= PCI_BASE_ADDRESS_MEM_MASK;
Bin Meng6758a6c2016-02-02 05:58:00 -0800745 iobase = dm_pci_mem_to_phys(dev, iobase);
Bin Meng8b7ee662015-09-11 03:24:35 -0700746
747 pdata->iobase = iobase;
748 pdata->phy_interface = PHY_INTERFACE_MODE_RMII;
749 }
Bin Meng8b7ee662015-09-11 03:24:35 -0700750
Bin Mengf0dc73c2015-09-03 05:37:29 -0700751 debug("%s, iobase=%x, priv=%p\n", __func__, iobase, priv);
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200752 ioaddr = iobase;
753 priv->mac_regs_p = (struct eth_mac_regs *)ioaddr;
754 priv->dma_regs_p = (struct eth_dma_regs *)(ioaddr + DW_DMA_BASE_OFFSET);
Simon Glass75577ba2015-04-05 16:07:41 -0600755 priv->interface = pdata->phy_interface;
Alexey Brodkin6968ec92016-01-13 16:59:37 +0300756 priv->max_speed = pdata->max_speed;
Simon Glass75577ba2015-04-05 16:07:41 -0600757
Neil Armstrong5160b452021-02-24 15:02:39 +0100758#if IS_ENABLED(CONFIG_DM_MDIO)
759 ret = dw_dm_mdio_init(dev->name, dev);
760#else
Simon Goldschmidt4ee587e2019-07-12 21:07:03 +0200761 ret = dw_mdio_init(dev->name, dev);
Neil Armstrong5160b452021-02-24 15:02:39 +0100762#endif
Simon Goldschmidt4ee587e2019-07-12 21:07:03 +0200763 if (ret) {
764 err = ret;
765 goto mdio_err;
766 }
Simon Glass75577ba2015-04-05 16:07:41 -0600767 priv->bus = miiphy_get_dev_by_name(dev->name);
Baruch Siachd44f3d22023-10-25 11:08:44 +0300768 priv->dev = dev;
Simon Glass75577ba2015-04-05 16:07:41 -0600769
770 ret = dw_phy_init(priv, dev);
771 debug("%s, ret=%d\n", __func__, ret);
Simon Goldschmidt4ee587e2019-07-12 21:07:03 +0200772 if (!ret)
773 return 0;
Simon Glass75577ba2015-04-05 16:07:41 -0600774
Simon Goldschmidt4ee587e2019-07-12 21:07:03 +0200775 /* continue here for cleanup if no PHY found */
776 err = ret;
777 mdio_unregister(priv->bus);
778 mdio_free(priv->bus);
779mdio_err:
Patrice Chotardba1f9662017-11-29 09:06:11 +0100780
781#ifdef CONFIG_CLK
782clk_err:
783 ret = clk_release_all(priv->clocks, priv->clock_count);
784 if (ret)
785 pr_err("failed to disable all clocks\n");
786
Patrice Chotardba1f9662017-11-29 09:06:11 +0100787#endif
Simon Goldschmidt4ee587e2019-07-12 21:07:03 +0200788 return err;
Simon Glass75577ba2015-04-05 16:07:41 -0600789}
790
Bin Meng5d2459f2015-10-07 21:32:38 -0700791static int designware_eth_remove(struct udevice *dev)
792{
793 struct dw_eth_dev *priv = dev_get_priv(dev);
794
795 free(priv->phydev);
796 mdio_unregister(priv->bus);
797 mdio_free(priv->bus);
798
Patrice Chotardba1f9662017-11-29 09:06:11 +0100799#ifdef CONFIG_CLK
800 return clk_release_all(priv->clocks, priv->clock_count);
801#else
Bin Meng5d2459f2015-10-07 21:32:38 -0700802 return 0;
Patrice Chotardba1f9662017-11-29 09:06:11 +0100803#endif
Bin Meng5d2459f2015-10-07 21:32:38 -0700804}
805
Sjoerd Simonsb9e08d02017-01-11 11:46:07 +0100806const struct eth_ops designware_eth_ops = {
Simon Glass75577ba2015-04-05 16:07:41 -0600807 .start = designware_eth_start,
808 .send = designware_eth_send,
809 .recv = designware_eth_recv,
810 .free_pkt = designware_eth_free_pkt,
811 .stop = designware_eth_stop,
812 .write_hwaddr = designware_eth_write_hwaddr,
813};
814
Simon Glassd1998a92020-12-03 16:55:21 -0700815int designware_eth_of_to_plat(struct udevice *dev)
Simon Glass75577ba2015-04-05 16:07:41 -0600816{
Simon Glassc69cda22020-12-03 16:55:20 -0700817 struct dw_eth_pdata *dw_pdata = dev_get_plat(dev);
Simon Glassbcee8d62019-12-06 21:41:35 -0700818#if CONFIG_IS_ENABLED(DM_GPIO)
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100819 struct dw_eth_dev *priv = dev_get_priv(dev);
Alexey Brodkin66d027e2016-06-27 13:17:51 +0300820#endif
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100821 struct eth_pdata *pdata = &dw_pdata->eth_pdata;
Simon Glassbcee8d62019-12-06 21:41:35 -0700822#if CONFIG_IS_ENABLED(DM_GPIO)
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100823 int reset_flags = GPIOD_IS_OUT;
Alexey Brodkin66d027e2016-06-27 13:17:51 +0300824#endif
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100825 int ret = 0;
Simon Glass75577ba2015-04-05 16:07:41 -0600826
Philipp Tomsich15050f12017-09-11 22:04:13 +0200827 pdata->iobase = dev_read_addr(dev);
Marek BehĂșn123ca112022-04-07 00:33:01 +0200828 pdata->phy_interface = dev_read_phy_mode(dev);
Marek BehĂșnffb0f6f2022-04-07 00:33:03 +0200829 if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
Simon Glass75577ba2015-04-05 16:07:41 -0600830 return -EINVAL;
Simon Glass75577ba2015-04-05 16:07:41 -0600831
Philipp Tomsich15050f12017-09-11 22:04:13 +0200832 pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
Alexey Brodkin6968ec92016-01-13 16:59:37 +0300833
Simon Glassbcee8d62019-12-06 21:41:35 -0700834#if CONFIG_IS_ENABLED(DM_GPIO)
Philipp Tomsich7ad326a2017-06-07 18:46:01 +0200835 if (dev_read_bool(dev, "snps,reset-active-low"))
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100836 reset_flags |= GPIOD_ACTIVE_LOW;
837
838 ret = gpio_request_by_name(dev, "snps,reset-gpio", 0,
839 &priv->reset_gpio, reset_flags);
840 if (ret == 0) {
Philipp Tomsich7ad326a2017-06-07 18:46:01 +0200841 ret = dev_read_u32_array(dev, "snps,reset-delays-us",
842 dw_pdata->reset_delays, 3);
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100843 } else if (ret == -ENOENT) {
844 ret = 0;
845 }
Alexey Brodkin66d027e2016-06-27 13:17:51 +0300846#endif
Sjoerd Simons90b7fc92016-02-28 22:24:55 +0100847
848 return ret;
Simon Glass75577ba2015-04-05 16:07:41 -0600849}
850
851static const struct udevice_id designware_eth_ids[] = {
852 { .compatible = "allwinner,sun7i-a20-gmac" },
Beniamino Galvanicfe25562016-08-16 11:49:50 +0200853 { .compatible = "amlogic,meson6-dwmac" },
Michael Kurzb20b70f2017-01-22 16:04:27 +0100854 { .compatible = "st,stm32-dwmac" },
Eugeniy Paltsev2a723232019-10-07 19:10:50 +0300855 { .compatible = "snps,arc-dwmac-3.70a" },
Simon Glass75577ba2015-04-05 16:07:41 -0600856 { }
857};
858
Marek Vasut9f76f102015-07-25 18:42:34 +0200859U_BOOT_DRIVER(eth_designware) = {
Simon Glass75577ba2015-04-05 16:07:41 -0600860 .name = "eth_designware",
861 .id = UCLASS_ETH,
862 .of_match = designware_eth_ids,
Simon Glassd1998a92020-12-03 16:55:21 -0700863 .of_to_plat = designware_eth_of_to_plat,
Bin Meng8b7ee662015-09-11 03:24:35 -0700864 .bind = designware_eth_bind,
Simon Glass75577ba2015-04-05 16:07:41 -0600865 .probe = designware_eth_probe,
Bin Meng5d2459f2015-10-07 21:32:38 -0700866 .remove = designware_eth_remove,
Simon Glass75577ba2015-04-05 16:07:41 -0600867 .ops = &designware_eth_ops,
Simon Glass41575d82020-12-03 16:55:17 -0700868 .priv_auto = sizeof(struct dw_eth_dev),
Simon Glasscaa4daa2020-12-03 16:55:18 -0700869 .plat_auto = sizeof(struct dw_eth_pdata),
Simon Glass75577ba2015-04-05 16:07:41 -0600870 .flags = DM_FLAG_ALLOC_PRIV_DMA,
871};
Bin Meng8b7ee662015-09-11 03:24:35 -0700872
873static struct pci_device_id supported[] = {
874 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_EMAC) },
875 { }
876};
877
878U_BOOT_PCI_DEVICE(eth_designware, supported);