]> git.ipfire.org Git - people/ms/u-boot.git/blame - drivers/net/designware.c
net/designware - switch driver to phylib usage
[people/ms/u-boot.git] / drivers / net / designware.c
CommitLineData
5b1b1883
VK
1/*
2 * (C) Copyright 2010
3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
4 *
1a459660 5 * SPDX-License-Identifier: GPL-2.0+
5b1b1883
VK
6 */
7
8/*
9 * Designware ethernet IP driver for u-boot
10 */
11
12#include <common.h>
13#include <miiphy.h>
14#include <malloc.h>
ef76025a 15#include <linux/compiler.h>
5b1b1883
VK
16#include <linux/err.h>
17#include <asm/io.h>
18#include "designware.h"
19
92a190aa
AB
20#if !defined(CONFIG_PHYLIB)
21# error "DesignWare Ether MAC requires PHYLIB - missing CONFIG_PHYLIB"
22#endif
23
24static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
25{
26 struct eth_mac_regs *mac_p = bus->priv;
27 ulong start;
28 u16 miiaddr;
29 int timeout = CONFIG_MDIO_TIMEOUT;
30
31 miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
32 ((reg << MIIREGSHIFT) & MII_REGMSK);
33
34 writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
35
36 start = get_timer(0);
37 while (get_timer(start) < timeout) {
38 if (!(readl(&mac_p->miiaddr) & MII_BUSY))
39 return readl(&mac_p->miidata);
40 udelay(10);
41 };
42
43 return -1;
44}
45
46static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
47 u16 val)
48{
49 struct eth_mac_regs *mac_p = bus->priv;
50 ulong start;
51 u16 miiaddr;
52 int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
53
54 writel(val, &mac_p->miidata);
55 miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
56 ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE;
57
58 writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
59
60 start = get_timer(0);
61 while (get_timer(start) < timeout) {
62 if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
63 ret = 0;
64 break;
65 }
66 udelay(10);
67 };
68
69 return ret;
70}
71
72static int dw_mdio_init(char *name, struct eth_mac_regs *mac_regs_p)
73{
74 struct mii_dev *bus = mdio_alloc();
75
76 if (!bus) {
77 printf("Failed to allocate MDIO bus\n");
78 return -1;
79 }
80
81 bus->read = dw_mdio_read;
82 bus->write = dw_mdio_write;
83 sprintf(bus->name, name);
84
85 bus->priv = (void *)mac_regs_p;
86
87 return mdio_register(bus);
88}
13edd170 89
5b1b1883
VK
90static void tx_descs_init(struct eth_device *dev)
91{
92 struct dw_eth_dev *priv = dev->priv;
93 struct eth_dma_regs *dma_p = priv->dma_regs_p;
94 struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
95 char *txbuffs = &priv->txbuffs[0];
96 struct dmamacdescr *desc_p;
97 u32 idx;
98
99 for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
100 desc_p = &desc_table_p[idx];
101 desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE];
102 desc_p->dmamac_next = &desc_table_p[idx + 1];
103
104#if defined(CONFIG_DW_ALTDESCRIPTOR)
105 desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
106 DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \
107 DESC_TXSTS_TXCHECKINSCTRL | \
108 DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS);
109
110 desc_p->txrx_status |= DESC_TXSTS_TXCHAIN;
111 desc_p->dmamac_cntl = 0;
112 desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA);
113#else
114 desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN;
115 desc_p->txrx_status = 0;
116#endif
117 }
118
119 /* Correcting the last pointer of the chain */
120 desc_p->dmamac_next = &desc_table_p[0];
121
122 writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
74cb708d 123 priv->tx_currdescnum = 0;
5b1b1883
VK
124}
125
126static void rx_descs_init(struct eth_device *dev)
127{
128 struct dw_eth_dev *priv = dev->priv;
129 struct eth_dma_regs *dma_p = priv->dma_regs_p;
130 struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
131 char *rxbuffs = &priv->rxbuffs[0];
132 struct dmamacdescr *desc_p;
133 u32 idx;
134
135 for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
136 desc_p = &desc_table_p[idx];
137 desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE];
138 desc_p->dmamac_next = &desc_table_p[idx + 1];
139
140 desc_p->dmamac_cntl =
141 (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \
142 DESC_RXCTRL_RXCHAIN;
143
144 desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
145 }
146
147 /* Correcting the last pointer of the chain */
148 desc_p->dmamac_next = &desc_table_p[0];
149
150 writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
74cb708d 151 priv->rx_currdescnum = 0;
5b1b1883
VK
152}
153
92a190aa 154static int dw_write_hwaddr(struct eth_device *dev)
5b1b1883 155{
92a190aa
AB
156 struct dw_eth_dev *priv = dev->priv;
157 struct eth_mac_regs *mac_p = priv->mac_regs_p;
158 u32 macid_lo, macid_hi;
159 u8 *mac_id = &dev->enetaddr[0];
160
161 macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
162 (mac_id[3] << 24);
163 macid_hi = mac_id[4] + (mac_id[5] << 8);
164
165 writel(macid_hi, &mac_p->macaddr0hi);
166 writel(macid_lo, &mac_p->macaddr0lo);
167
168 return 0;
5b1b1883
VK
169}
170
92a190aa
AB
171static void dw_adjust_link(struct eth_mac_regs *mac_p,
172 struct phy_device *phydev)
5b1b1883 173{
92a190aa 174 u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN;
5b1b1883 175
92a190aa
AB
176 if (!phydev->link) {
177 printf("%s: No link.\n", phydev->dev->name);
178 return;
179 }
5b1b1883 180
92a190aa
AB
181 if (phydev->speed != 1000)
182 conf |= MII_PORTSELECT;
7091915a 183
92a190aa
AB
184 if (phydev->speed == 100)
185 conf |= FES_100;
5b1b1883 186
92a190aa
AB
187 if (phydev->duplex)
188 conf |= FULLDPLXMODE;
cafabe19 189
92a190aa 190 writel(conf, &mac_p->conf);
5b1b1883 191
92a190aa
AB
192 printf("Speed: %d, %s duplex%s\n", phydev->speed,
193 (phydev->duplex) ? "full" : "half",
194 (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
5b1b1883
VK
195}
196
92a190aa 197static void dw_eth_halt(struct eth_device *dev)
5b1b1883
VK
198{
199 struct dw_eth_dev *priv = dev->priv;
200 struct eth_mac_regs *mac_p = priv->mac_regs_p;
92a190aa 201 struct eth_dma_regs *dma_p = priv->dma_regs_p;
5b1b1883 202
92a190aa
AB
203 writel(readl(&mac_p->conf) & ~(RXENABLE | TXENABLE), &mac_p->conf);
204 writel(readl(&dma_p->opmode) & ~(RXSTART | TXSTART), &dma_p->opmode);
5b1b1883 205
92a190aa 206 phy_shutdown(priv->phydev);
5b1b1883
VK
207}
208
209static int dw_eth_init(struct eth_device *dev, bd_t *bis)
210{
211 struct dw_eth_dev *priv = dev->priv;
212 struct eth_mac_regs *mac_p = priv->mac_regs_p;
213 struct eth_dma_regs *dma_p = priv->dma_regs_p;
92a190aa 214 unsigned int start;
5b1b1883 215
92a190aa 216 writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode);
13edd170 217
92a190aa
AB
218 start = get_timer(0);
219 while (readl(&dma_p->busmode) & DMAMAC_SRST) {
220 if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT)
221 return -1;
ef76025a 222
92a190aa
AB
223 mdelay(100);
224 };
5b1b1883 225
92a190aa
AB
226 /* Soft reset above clears HW address registers.
227 * So we have to set it here once again */
c7f6dbe7
VK
228 dw_write_hwaddr(dev);
229
92a190aa
AB
230 rx_descs_init(dev);
231 tx_descs_init(dev);
5b1b1883 232
92a190aa 233 writel(FIXEDBURST | PRIORXTX_41 | BURST_16, &dma_p->busmode);
5b1b1883 234
92a190aa
AB
235 writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD,
236 &dma_p->opmode);
5b1b1883 237
92a190aa 238 writel(readl(&dma_p->opmode) | RXSTART | TXSTART, &dma_p->opmode);
9afc1af0 239
92a190aa
AB
240 /* Start up the PHY */
241 if (phy_startup(priv->phydev)) {
242 printf("Could not initialize PHY %s\n",
243 priv->phydev->dev->name);
244 return -1;
9afc1af0
VK
245 }
246
92a190aa 247 dw_adjust_link(mac_p, priv->phydev);
5b1b1883 248
92a190aa
AB
249 if (!priv->phydev->link)
250 return -1;
5b1b1883 251
aa51005c 252 writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
5b1b1883
VK
253
254 return 0;
255}
256
10cbe3b6 257static int dw_eth_send(struct eth_device *dev, void *packet, int length)
5b1b1883
VK
258{
259 struct dw_eth_dev *priv = dev->priv;
260 struct eth_dma_regs *dma_p = priv->dma_regs_p;
261 u32 desc_num = priv->tx_currdescnum;
262 struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
263
264 /* Check if the descriptor is owned by CPU */
265 if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
266 printf("CPU not owner of tx frame\n");
267 return -1;
268 }
269
10cbe3b6 270 memcpy((void *)desc_p->dmamac_addr, packet, length);
5b1b1883
VK
271
272#if defined(CONFIG_DW_ALTDESCRIPTOR)
273 desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
274 desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \
275 DESC_TXCTRL_SIZE1MASK;
276
277 desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
278 desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
279#else
280 desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \
281 DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \
282 DESC_TXCTRL_TXFIRST;
283
284 desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
285#endif
286
287 /* Test the wrap-around condition. */
288 if (++desc_num >= CONFIG_TX_DESCR_NUM)
289 desc_num = 0;
290
291 priv->tx_currdescnum = desc_num;
292
293 /* Start the transmission */
294 writel(POLL_DATA, &dma_p->txpolldemand);
295
296 return 0;
297}
298
299static int dw_eth_recv(struct eth_device *dev)
300{
301 struct dw_eth_dev *priv = dev->priv;
302 u32 desc_num = priv->rx_currdescnum;
303 struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
304
305 u32 status = desc_p->txrx_status;
306 int length = 0;
307
308 /* Check if the owner is the CPU */
309 if (!(status & DESC_RXSTS_OWNBYDMA)) {
310
311 length = (status & DESC_RXSTS_FRMLENMSK) >> \
312 DESC_RXSTS_FRMLENSHFT;
313
314 NetReceive(desc_p->dmamac_addr, length);
315
316 /*
317 * Make the current descriptor valid again and go to
318 * the next one
319 */
320 desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
321
322 /* Test the wrap-around condition. */
323 if (++desc_num >= CONFIG_RX_DESCR_NUM)
324 desc_num = 0;
325 }
326
327 priv->rx_currdescnum = desc_num;
328
329 return length;
330}
331
92a190aa 332static int dw_phy_init(struct eth_device *dev)
5b1b1883
VK
333{
334 struct dw_eth_dev *priv = dev->priv;
92a190aa
AB
335 struct phy_device *phydev;
336 int mask = 0xffffffff;
cafabe19 337
92a190aa
AB
338#ifdef CONFIG_PHY_ADDR
339 mask = 1 << CONFIG_PHY_ADDR;
5b1b1883
VK
340#endif
341
92a190aa
AB
342 phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
343 if (!phydev)
5b1b1883
VK
344 return -1;
345
92a190aa
AB
346 phydev->supported &= PHY_GBIT_FEATURES;
347 phydev->advertising = phydev->supported;
5b1b1883 348
92a190aa
AB
349 priv->phydev = phydev;
350 phy_config(phydev);
ef76025a 351
92a190aa 352 return 1;
5b1b1883 353}
5b1b1883 354
92a190aa 355int designware_initialize(ulong base_addr, u32 interface)
5b1b1883
VK
356{
357 struct eth_device *dev;
358 struct dw_eth_dev *priv;
359
360 dev = (struct eth_device *) malloc(sizeof(struct eth_device));
361 if (!dev)
362 return -ENOMEM;
363
364 /*
365 * Since the priv structure contains the descriptors which need a strict
366 * buswidth alignment, memalign is used to allocate memory
367 */
368 priv = (struct dw_eth_dev *) memalign(16, sizeof(struct dw_eth_dev));
369 if (!priv) {
370 free(dev);
371 return -ENOMEM;
372 }
373
374 memset(dev, 0, sizeof(struct eth_device));
375 memset(priv, 0, sizeof(struct dw_eth_dev));
376
92a190aa 377 sprintf(dev->name, "dwmac.%lx", base_addr);
5b1b1883
VK
378 dev->iobase = (int)base_addr;
379 dev->priv = priv;
380
5b1b1883
VK
381 priv->dev = dev;
382 priv->mac_regs_p = (struct eth_mac_regs *)base_addr;
383 priv->dma_regs_p = (struct eth_dma_regs *)(base_addr +
384 DW_DMA_BASE_OFFSET);
5b1b1883 385
5b1b1883
VK
386 dev->init = dw_eth_init;
387 dev->send = dw_eth_send;
388 dev->recv = dw_eth_recv;
389 dev->halt = dw_eth_halt;
390 dev->write_hwaddr = dw_write_hwaddr;
391
392 eth_register(dev);
393
92a190aa
AB
394 priv->interface = interface;
395
396 dw_mdio_init(dev->name, priv->mac_regs_p);
397 priv->bus = miiphy_get_dev_by_name(dev->name);
398
399 return dw_phy_init(dev);
5b1b1883 400}