blob: 16731674e44b935a9ecf431f2b6d8ea1387d92eb [file] [log] [blame]
Vipin KUMAR5b1b1882010-06-29 10:53:34 +05301/*
2 * (C) Copyright 2010
3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Vipin KUMAR5b1b1882010-06-29 10:53:34 +05306 */
7
8/*
Simon Glass64dcd252015-04-05 16:07:40 -06009 * Designware ethernet IP driver for U-Boot
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053010 */
11
12#include <common.h>
Simon Glass75577ba2015-04-05 16:07:41 -060013#include <dm.h>
Simon Glass64dcd252015-04-05 16:07:40 -060014#include <errno.h>
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053015#include <miiphy.h>
16#include <malloc.h>
Bin Meng8b7ee662015-09-11 03:24:35 -070017#include <pci.h>
Stefan Roeseef760252012-05-07 12:04:25 +020018#include <linux/compiler.h>
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053019#include <linux/err.h>
20#include <asm/io.h>
21#include "designware.h"
22
Simon Glass75577ba2015-04-05 16:07:41 -060023DECLARE_GLOBAL_DATA_PTR;
24
Alexey Brodkin92a190a2014-01-22 20:54:06 +040025static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
26{
27 struct eth_mac_regs *mac_p = bus->priv;
28 ulong start;
29 u16 miiaddr;
30 int timeout = CONFIG_MDIO_TIMEOUT;
31
32 miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
33 ((reg << MIIREGSHIFT) & MII_REGMSK);
34
35 writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
36
37 start = get_timer(0);
38 while (get_timer(start) < timeout) {
39 if (!(readl(&mac_p->miiaddr) & MII_BUSY))
40 return readl(&mac_p->miidata);
41 udelay(10);
42 };
43
Simon Glass64dcd252015-04-05 16:07:40 -060044 return -ETIMEDOUT;
Alexey Brodkin92a190a2014-01-22 20:54:06 +040045}
46
47static int dw_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
48 u16 val)
49{
50 struct eth_mac_regs *mac_p = bus->priv;
51 ulong start;
52 u16 miiaddr;
Simon Glass64dcd252015-04-05 16:07:40 -060053 int ret = -ETIMEDOUT, timeout = CONFIG_MDIO_TIMEOUT;
Alexey Brodkin92a190a2014-01-22 20:54:06 +040054
55 writel(val, &mac_p->miidata);
56 miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) |
57 ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE;
58
59 writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr);
60
61 start = get_timer(0);
62 while (get_timer(start) < timeout) {
63 if (!(readl(&mac_p->miiaddr) & MII_BUSY)) {
64 ret = 0;
65 break;
66 }
67 udelay(10);
68 };
69
70 return ret;
71}
72
Simon Glass64dcd252015-04-05 16:07:40 -060073static int dw_mdio_init(const char *name, struct eth_mac_regs *mac_regs_p)
Alexey Brodkin92a190a2014-01-22 20:54:06 +040074{
75 struct mii_dev *bus = mdio_alloc();
76
77 if (!bus) {
78 printf("Failed to allocate MDIO bus\n");
Simon Glass64dcd252015-04-05 16:07:40 -060079 return -ENOMEM;
Alexey Brodkin92a190a2014-01-22 20:54:06 +040080 }
81
82 bus->read = dw_mdio_read;
83 bus->write = dw_mdio_write;
Ben Whitten192bc692015-12-30 13:05:58 +000084 snprintf(bus->name, sizeof(bus->name), "%s", name);
Alexey Brodkin92a190a2014-01-22 20:54:06 +040085
86 bus->priv = (void *)mac_regs_p;
87
88 return mdio_register(bus);
89}
Vipin Kumar13edd172012-03-26 00:09:56 +000090
Simon Glass64dcd252015-04-05 16:07:40 -060091static void tx_descs_init(struct dw_eth_dev *priv)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053092{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +053093 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];
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200101 desc_p->dmamac_addr = (ulong)&txbuffs[idx * CONFIG_ETH_BUFSIZE];
102 desc_p->dmamac_next = (ulong)&desc_table_p[idx + 1];
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530103
104#if defined(CONFIG_DW_ALTDESCRIPTOR)
105 desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST |
Marek Vasut2b261092015-12-20 03:59:23 +0100106 DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS |
107 DESC_TXSTS_TXCHECKINSCTRL |
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530108 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 */
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200120 desc_p->dmamac_next = (ulong)&desc_table_p[0];
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530121
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400122 /* Flush all Tx buffer descriptors at once */
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200123 flush_dcache_range((ulong)priv->tx_mac_descrtable,
124 (ulong)priv->tx_mac_descrtable +
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400125 sizeof(priv->tx_mac_descrtable));
126
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530127 writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr);
Alexey Brodkin74cb7082014-01-13 13:28:38 +0400128 priv->tx_currdescnum = 0;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530129}
130
Simon Glass64dcd252015-04-05 16:07:40 -0600131static void rx_descs_init(struct dw_eth_dev *priv)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530132{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530133 struct eth_dma_regs *dma_p = priv->dma_regs_p;
134 struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
135 char *rxbuffs = &priv->rxbuffs[0];
136 struct dmamacdescr *desc_p;
137 u32 idx;
138
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400139 /* Before passing buffers to GMAC we need to make sure zeros
140 * written there right after "priv" structure allocation were
141 * flushed into RAM.
142 * Otherwise there's a chance to get some of them flushed in RAM when
143 * GMAC is already pushing data to RAM via DMA. This way incoming from
144 * GMAC data will be corrupted. */
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200145 flush_dcache_range((ulong)rxbuffs, (ulong)rxbuffs + RX_TOTAL_BUFSIZE);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400146
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530147 for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
148 desc_p = &desc_table_p[idx];
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200149 desc_p->dmamac_addr = (ulong)&rxbuffs[idx * CONFIG_ETH_BUFSIZE];
150 desc_p->dmamac_next = (ulong)&desc_table_p[idx + 1];
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530151
152 desc_p->dmamac_cntl =
Marek Vasut2b261092015-12-20 03:59:23 +0100153 (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) |
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530154 DESC_RXCTRL_RXCHAIN;
155
156 desc_p->txrx_status = DESC_RXSTS_OWNBYDMA;
157 }
158
159 /* Correcting the last pointer of the chain */
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200160 desc_p->dmamac_next = (ulong)&desc_table_p[0];
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530161
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400162 /* Flush all Rx buffer descriptors at once */
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200163 flush_dcache_range((ulong)priv->rx_mac_descrtable,
164 (ulong)priv->rx_mac_descrtable +
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400165 sizeof(priv->rx_mac_descrtable));
166
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530167 writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr);
Alexey Brodkin74cb7082014-01-13 13:28:38 +0400168 priv->rx_currdescnum = 0;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530169}
170
Simon Glass64dcd252015-04-05 16:07:40 -0600171static int _dw_write_hwaddr(struct dw_eth_dev *priv, u8 *mac_id)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530172{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530173 struct eth_mac_regs *mac_p = priv->mac_regs_p;
174 u32 macid_lo, macid_hi;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530175
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400176 macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
177 (mac_id[3] << 24);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530178 macid_hi = mac_id[4] + (mac_id[5] << 8);
179
180 writel(macid_hi, &mac_p->macaddr0hi);
181 writel(macid_lo, &mac_p->macaddr0lo);
182
183 return 0;
184}
185
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400186static void dw_adjust_link(struct eth_mac_regs *mac_p,
187 struct phy_device *phydev)
188{
189 u32 conf = readl(&mac_p->conf) | FRAMEBURSTENABLE | DISABLERXOWN;
190
191 if (!phydev->link) {
192 printf("%s: No link.\n", phydev->dev->name);
193 return;
194 }
195
196 if (phydev->speed != 1000)
197 conf |= MII_PORTSELECT;
Alexey Brodkinb884c3f2016-01-13 16:59:36 +0300198 else
199 conf &= ~MII_PORTSELECT;
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400200
201 if (phydev->speed == 100)
202 conf |= FES_100;
203
204 if (phydev->duplex)
205 conf |= FULLDPLXMODE;
206
207 writel(conf, &mac_p->conf);
208
209 printf("Speed: %d, %s duplex%s\n", phydev->speed,
210 (phydev->duplex) ? "full" : "half",
211 (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
212}
213
Simon Glass64dcd252015-04-05 16:07:40 -0600214static void _dw_eth_halt(struct dw_eth_dev *priv)
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400215{
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400216 struct eth_mac_regs *mac_p = priv->mac_regs_p;
217 struct eth_dma_regs *dma_p = priv->dma_regs_p;
218
219 writel(readl(&mac_p->conf) & ~(RXENABLE | TXENABLE), &mac_p->conf);
220 writel(readl(&dma_p->opmode) & ~(RXSTART | TXSTART), &dma_p->opmode);
221
222 phy_shutdown(priv->phydev);
223}
224
Simon Glass64dcd252015-04-05 16:07:40 -0600225static int _dw_eth_init(struct dw_eth_dev *priv, u8 *enetaddr)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530226{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530227 struct eth_mac_regs *mac_p = priv->mac_regs_p;
228 struct eth_dma_regs *dma_p = priv->dma_regs_p;
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400229 unsigned int start;
Simon Glass64dcd252015-04-05 16:07:40 -0600230 int ret;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530231
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400232 writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode);
Vipin Kumar13edd172012-03-26 00:09:56 +0000233
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400234 start = get_timer(0);
235 while (readl(&dma_p->busmode) & DMAMAC_SRST) {
Alexey Brodkin875143f2015-01-13 17:10:24 +0300236 if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT) {
237 printf("DMA reset timeout\n");
Simon Glass64dcd252015-04-05 16:07:40 -0600238 return -ETIMEDOUT;
Alexey Brodkin875143f2015-01-13 17:10:24 +0300239 }
Stefan Roeseef760252012-05-07 12:04:25 +0200240
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400241 mdelay(100);
242 };
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530243
Bin Mengf3edfd32015-06-15 18:40:19 +0800244 /*
245 * Soft reset above clears HW address registers.
246 * So we have to set it here once again.
247 */
248 _dw_write_hwaddr(priv, enetaddr);
249
Simon Glass64dcd252015-04-05 16:07:40 -0600250 rx_descs_init(priv);
251 tx_descs_init(priv);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530252
Ian Campbell49692c52014-05-08 22:26:35 +0100253 writel(FIXEDBURST | PRIORXTX_41 | DMA_PBL, &dma_p->busmode);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530254
Sonic Zhangd2279222015-01-29 14:38:50 +0800255#ifndef CONFIG_DW_MAC_FORCE_THRESHOLD_MODE
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400256 writel(readl(&dma_p->opmode) | FLUSHTXFIFO | STOREFORWARD,
257 &dma_p->opmode);
Sonic Zhangd2279222015-01-29 14:38:50 +0800258#else
259 writel(readl(&dma_p->opmode) | FLUSHTXFIFO,
260 &dma_p->opmode);
261#endif
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530262
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400263 writel(readl(&dma_p->opmode) | RXSTART | TXSTART, &dma_p->opmode);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530264
Sonic Zhang2ddaf132015-01-29 13:37:31 +0800265#ifdef CONFIG_DW_AXI_BURST_LEN
266 writel((CONFIG_DW_AXI_BURST_LEN & 0x1FF >> 1), &dma_p->axibus);
267#endif
268
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400269 /* Start up the PHY */
Simon Glass64dcd252015-04-05 16:07:40 -0600270 ret = phy_startup(priv->phydev);
271 if (ret) {
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400272 printf("Could not initialize PHY %s\n",
273 priv->phydev->dev->name);
Simon Glass64dcd252015-04-05 16:07:40 -0600274 return ret;
Vipin Kumar9afc1af2012-05-07 13:06:44 +0530275 }
276
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400277 dw_adjust_link(mac_p, priv->phydev);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530278
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400279 if (!priv->phydev->link)
Simon Glass64dcd252015-04-05 16:07:40 -0600280 return -EIO;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530281
Armando Viscontiaa510052012-03-26 00:09:55 +0000282 writel(readl(&mac_p->conf) | RXENABLE | TXENABLE, &mac_p->conf);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530283
284 return 0;
285}
286
Simon Glass64dcd252015-04-05 16:07:40 -0600287static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530288{
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530289 struct eth_dma_regs *dma_p = priv->dma_regs_p;
290 u32 desc_num = priv->tx_currdescnum;
291 struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200292 ulong desc_start = (ulong)desc_p;
293 ulong desc_end = desc_start +
Marek Vasut96cec172014-09-15 01:05:23 +0200294 roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200295 ulong data_start = desc_p->dmamac_addr;
296 ulong data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
Ian Campbell964ea7c2014-05-08 22:26:33 +0100297 /*
298 * Strictly we only need to invalidate the "txrx_status" field
299 * for the following check, but on some platforms we cannot
Marek Vasut96cec172014-09-15 01:05:23 +0200300 * invalidate only 4 bytes, so we flush the entire descriptor,
301 * which is 16 bytes in total. This is safe because the
302 * individual descriptors in the array are each aligned to
303 * ARCH_DMA_MINALIGN and padded appropriately.
Ian Campbell964ea7c2014-05-08 22:26:33 +0100304 */
Marek Vasut96cec172014-09-15 01:05:23 +0200305 invalidate_dcache_range(desc_start, desc_end);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400306
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530307 /* Check if the descriptor is owned by CPU */
308 if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) {
309 printf("CPU not owner of tx frame\n");
Simon Glass64dcd252015-04-05 16:07:40 -0600310 return -EPERM;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530311 }
312
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200313 memcpy((void *)data_start, packet, length);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530314
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400315 /* Flush data to be sent */
Marek Vasut96cec172014-09-15 01:05:23 +0200316 flush_dcache_range(data_start, data_end);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400317
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530318#if defined(CONFIG_DW_ALTDESCRIPTOR)
319 desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
Marek Vasut2b261092015-12-20 03:59:23 +0100320 desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) &
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530321 DESC_TXCTRL_SIZE1MASK;
322
323 desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
324 desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
325#else
Marek Vasut2b261092015-12-20 03:59:23 +0100326 desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) &
327 DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST |
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530328 DESC_TXCTRL_TXFIRST;
329
330 desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
331#endif
332
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400333 /* Flush modified buffer descriptor */
Marek Vasut96cec172014-09-15 01:05:23 +0200334 flush_dcache_range(desc_start, desc_end);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400335
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530336 /* Test the wrap-around condition. */
337 if (++desc_num >= CONFIG_TX_DESCR_NUM)
338 desc_num = 0;
339
340 priv->tx_currdescnum = desc_num;
341
342 /* Start the transmission */
343 writel(POLL_DATA, &dma_p->txpolldemand);
344
345 return 0;
346}
347
Simon Glass75577ba2015-04-05 16:07:41 -0600348static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530349{
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400350 u32 status, desc_num = priv->rx_currdescnum;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530351 struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
Simon Glass75577ba2015-04-05 16:07:41 -0600352 int length = -EAGAIN;
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200353 ulong desc_start = (ulong)desc_p;
354 ulong desc_end = desc_start +
Marek Vasut96cec172014-09-15 01:05:23 +0200355 roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200356 ulong data_start = desc_p->dmamac_addr;
357 ulong data_end;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530358
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400359 /* Invalidate entire buffer descriptor */
Marek Vasut96cec172014-09-15 01:05:23 +0200360 invalidate_dcache_range(desc_start, desc_end);
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400361
362 status = desc_p->txrx_status;
363
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530364 /* Check if the owner is the CPU */
365 if (!(status & DESC_RXSTS_OWNBYDMA)) {
366
Marek Vasut2b261092015-12-20 03:59:23 +0100367 length = (status & DESC_RXSTS_FRMLENMSK) >>
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530368 DESC_RXSTS_FRMLENSHFT;
369
Alexey Brodkin50b0df82014-01-22 20:49:09 +0400370 /* Invalidate received data */
Marek Vasut96cec172014-09-15 01:05:23 +0200371 data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
372 invalidate_dcache_range(data_start, data_end);
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200373 *packetp = (uchar *)(ulong)desc_p->dmamac_addr;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530374 }
375
Simon Glass75577ba2015-04-05 16:07:41 -0600376 return length;
377}
378
379static int _dw_free_pkt(struct dw_eth_dev *priv)
380{
381 u32 desc_num = priv->rx_currdescnum;
382 struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200383 ulong desc_start = (ulong)desc_p;
384 ulong desc_end = desc_start +
Simon Glass75577ba2015-04-05 16:07:41 -0600385 roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
386
387 /*
388 * Make the current descriptor valid again and go to
389 * the next one
390 */
391 desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA;
392
393 /* Flush only status field - others weren't changed */
394 flush_dcache_range(desc_start, desc_end);
395
396 /* Test the wrap-around condition. */
397 if (++desc_num >= CONFIG_RX_DESCR_NUM)
398 desc_num = 0;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530399 priv->rx_currdescnum = desc_num;
400
Simon Glass75577ba2015-04-05 16:07:41 -0600401 return 0;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530402}
403
Simon Glass64dcd252015-04-05 16:07:40 -0600404static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530405{
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400406 struct phy_device *phydev;
Alexey Brodkin6968ec92016-01-13 16:59:37 +0300407 int mask = 0xffffffff, ret;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530408
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400409#ifdef CONFIG_PHY_ADDR
410 mask = 1 << CONFIG_PHY_ADDR;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530411#endif
412
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400413 phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
414 if (!phydev)
Simon Glass64dcd252015-04-05 16:07:40 -0600415 return -ENODEV;
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530416
Ian Campbell15e82e52014-04-28 20:14:05 +0100417 phy_connect_dev(phydev, dev);
418
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400419 phydev->supported &= PHY_GBIT_FEATURES;
Alexey Brodkin6968ec92016-01-13 16:59:37 +0300420 if (priv->max_speed) {
421 ret = phy_set_supported(phydev, priv->max_speed);
422 if (ret)
423 return ret;
424 }
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400425 phydev->advertising = phydev->supported;
426
427 priv->phydev = phydev;
428 phy_config(phydev);
429
Simon Glass64dcd252015-04-05 16:07:40 -0600430 return 0;
431}
432
Simon Glass75577ba2015-04-05 16:07:41 -0600433#ifndef CONFIG_DM_ETH
Simon Glass64dcd252015-04-05 16:07:40 -0600434static int dw_eth_init(struct eth_device *dev, bd_t *bis)
435{
436 return _dw_eth_init(dev->priv, dev->enetaddr);
437}
438
439static int dw_eth_send(struct eth_device *dev, void *packet, int length)
440{
441 return _dw_eth_send(dev->priv, packet, length);
442}
443
444static int dw_eth_recv(struct eth_device *dev)
445{
Simon Glass75577ba2015-04-05 16:07:41 -0600446 uchar *packet;
447 int length;
448
449 length = _dw_eth_recv(dev->priv, &packet);
450 if (length == -EAGAIN)
451 return 0;
452 net_process_received_packet(packet, length);
453
454 _dw_free_pkt(dev->priv);
455
456 return 0;
Simon Glass64dcd252015-04-05 16:07:40 -0600457}
458
459static void dw_eth_halt(struct eth_device *dev)
460{
461 return _dw_eth_halt(dev->priv);
462}
463
464static int dw_write_hwaddr(struct eth_device *dev)
465{
466 return _dw_write_hwaddr(dev->priv, dev->enetaddr);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530467}
468
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400469int designware_initialize(ulong base_addr, u32 interface)
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530470{
471 struct eth_device *dev;
472 struct dw_eth_dev *priv;
473
474 dev = (struct eth_device *) malloc(sizeof(struct eth_device));
475 if (!dev)
476 return -ENOMEM;
477
478 /*
479 * Since the priv structure contains the descriptors which need a strict
480 * buswidth alignment, memalign is used to allocate memory
481 */
Ian Campbell1c848a22014-05-08 22:26:32 +0100482 priv = (struct dw_eth_dev *) memalign(ARCH_DMA_MINALIGN,
483 sizeof(struct dw_eth_dev));
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530484 if (!priv) {
485 free(dev);
486 return -ENOMEM;
487 }
488
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200489 if ((phys_addr_t)priv + sizeof(*priv) > (1ULL << 32)) {
490 printf("designware: buffers are outside DMA memory\n");
491 return -EINVAL;
492 }
493
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530494 memset(dev, 0, sizeof(struct eth_device));
495 memset(priv, 0, sizeof(struct dw_eth_dev));
496
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400497 sprintf(dev->name, "dwmac.%lx", base_addr);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530498 dev->iobase = (int)base_addr;
499 dev->priv = priv;
500
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530501 priv->dev = dev;
502 priv->mac_regs_p = (struct eth_mac_regs *)base_addr;
503 priv->dma_regs_p = (struct eth_dma_regs *)(base_addr +
504 DW_DMA_BASE_OFFSET);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530505
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530506 dev->init = dw_eth_init;
507 dev->send = dw_eth_send;
508 dev->recv = dw_eth_recv;
509 dev->halt = dw_eth_halt;
510 dev->write_hwaddr = dw_write_hwaddr;
511
512 eth_register(dev);
513
Alexey Brodkin92a190a2014-01-22 20:54:06 +0400514 priv->interface = interface;
515
516 dw_mdio_init(dev->name, priv->mac_regs_p);
517 priv->bus = miiphy_get_dev_by_name(dev->name);
518
Simon Glass64dcd252015-04-05 16:07:40 -0600519 return dw_phy_init(priv, dev);
Vipin KUMAR5b1b1882010-06-29 10:53:34 +0530520}
Simon Glass75577ba2015-04-05 16:07:41 -0600521#endif
522
523#ifdef CONFIG_DM_ETH
524static int designware_eth_start(struct udevice *dev)
525{
526 struct eth_pdata *pdata = dev_get_platdata(dev);
527
528 return _dw_eth_init(dev->priv, pdata->enetaddr);
529}
530
531static int designware_eth_send(struct udevice *dev, void *packet, int length)
532{
533 struct dw_eth_dev *priv = dev_get_priv(dev);
534
535 return _dw_eth_send(priv, packet, length);
536}
537
Simon Glassa1ca92e2015-07-06 16:47:49 -0600538static int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp)
Simon Glass75577ba2015-04-05 16:07:41 -0600539{
540 struct dw_eth_dev *priv = dev_get_priv(dev);
541
542 return _dw_eth_recv(priv, packetp);
543}
544
545static int designware_eth_free_pkt(struct udevice *dev, uchar *packet,
546 int length)
547{
548 struct dw_eth_dev *priv = dev_get_priv(dev);
549
550 return _dw_free_pkt(priv);
551}
552
553static void designware_eth_stop(struct udevice *dev)
554{
555 struct dw_eth_dev *priv = dev_get_priv(dev);
556
557 return _dw_eth_halt(priv);
558}
559
560static int designware_eth_write_hwaddr(struct udevice *dev)
561{
562 struct eth_pdata *pdata = dev_get_platdata(dev);
563 struct dw_eth_dev *priv = dev_get_priv(dev);
564
565 return _dw_write_hwaddr(priv, pdata->enetaddr);
566}
567
Bin Meng8b7ee662015-09-11 03:24:35 -0700568static int designware_eth_bind(struct udevice *dev)
569{
570#ifdef CONFIG_DM_PCI
571 static int num_cards;
572 char name[20];
573
574 /* Create a unique device name for PCI type devices */
575 if (device_is_on_pci_bus(dev)) {
576 sprintf(name, "eth_designware#%u", num_cards++);
577 device_set_name(dev, name);
578 }
579#endif
580
581 return 0;
582}
583
Simon Glass75577ba2015-04-05 16:07:41 -0600584static int designware_eth_probe(struct udevice *dev)
585{
586 struct eth_pdata *pdata = dev_get_platdata(dev);
587 struct dw_eth_dev *priv = dev_get_priv(dev);
Bin Mengf0dc73c2015-09-03 05:37:29 -0700588 u32 iobase = pdata->iobase;
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200589 ulong ioaddr;
Simon Glass75577ba2015-04-05 16:07:41 -0600590 int ret;
591
Bin Meng8b7ee662015-09-11 03:24:35 -0700592#ifdef CONFIG_DM_PCI
593 /*
594 * If we are on PCI bus, either directly attached to a PCI root port,
595 * or via a PCI bridge, fill in platdata before we probe the hardware.
596 */
597 if (device_is_on_pci_bus(dev)) {
Bin Meng8b7ee662015-09-11 03:24:35 -0700598 dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase);
599 iobase &= PCI_BASE_ADDRESS_MEM_MASK;
Bin Meng6758a6c2016-02-02 05:58:00 -0800600 iobase = dm_pci_mem_to_phys(dev, iobase);
Bin Meng8b7ee662015-09-11 03:24:35 -0700601
602 pdata->iobase = iobase;
603 pdata->phy_interface = PHY_INTERFACE_MODE_RMII;
604 }
605#endif
606
Bin Mengf0dc73c2015-09-03 05:37:29 -0700607 debug("%s, iobase=%x, priv=%p\n", __func__, iobase, priv);
Beniamino Galvani0e1a3e32016-05-08 08:30:15 +0200608 ioaddr = iobase;
609 priv->mac_regs_p = (struct eth_mac_regs *)ioaddr;
610 priv->dma_regs_p = (struct eth_dma_regs *)(ioaddr + DW_DMA_BASE_OFFSET);
Simon Glass75577ba2015-04-05 16:07:41 -0600611 priv->interface = pdata->phy_interface;
Alexey Brodkin6968ec92016-01-13 16:59:37 +0300612 priv->max_speed = pdata->max_speed;
Simon Glass75577ba2015-04-05 16:07:41 -0600613
614 dw_mdio_init(dev->name, priv->mac_regs_p);
615 priv->bus = miiphy_get_dev_by_name(dev->name);
616
617 ret = dw_phy_init(priv, dev);
618 debug("%s, ret=%d\n", __func__, ret);
619
620 return ret;
621}
622
Bin Meng5d2459f2015-10-07 21:32:38 -0700623static int designware_eth_remove(struct udevice *dev)
624{
625 struct dw_eth_dev *priv = dev_get_priv(dev);
626
627 free(priv->phydev);
628 mdio_unregister(priv->bus);
629 mdio_free(priv->bus);
630
631 return 0;
632}
633
Simon Glass75577ba2015-04-05 16:07:41 -0600634static const struct eth_ops designware_eth_ops = {
635 .start = designware_eth_start,
636 .send = designware_eth_send,
637 .recv = designware_eth_recv,
638 .free_pkt = designware_eth_free_pkt,
639 .stop = designware_eth_stop,
640 .write_hwaddr = designware_eth_write_hwaddr,
641};
642
643static int designware_eth_ofdata_to_platdata(struct udevice *dev)
644{
645 struct eth_pdata *pdata = dev_get_platdata(dev);
646 const char *phy_mode;
Alexey Brodkin6968ec92016-01-13 16:59:37 +0300647 const fdt32_t *cell;
Simon Glass75577ba2015-04-05 16:07:41 -0600648
649 pdata->iobase = dev_get_addr(dev);
650 pdata->phy_interface = -1;
651 phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
652 if (phy_mode)
653 pdata->phy_interface = phy_get_interface_by_name(phy_mode);
654 if (pdata->phy_interface == -1) {
655 debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
656 return -EINVAL;
657 }
658
Alexey Brodkin6968ec92016-01-13 16:59:37 +0300659 pdata->max_speed = 0;
660 cell = fdt_getprop(gd->fdt_blob, dev->of_offset, "max-speed", NULL);
661 if (cell)
662 pdata->max_speed = fdt32_to_cpu(*cell);
663
Simon Glass75577ba2015-04-05 16:07:41 -0600664 return 0;
665}
666
667static const struct udevice_id designware_eth_ids[] = {
668 { .compatible = "allwinner,sun7i-a20-gmac" },
Marek Vasutb9628592015-07-25 18:38:44 +0200669 { .compatible = "altr,socfpga-stmmac" },
Simon Glass75577ba2015-04-05 16:07:41 -0600670 { }
671};
672
Marek Vasut9f76f102015-07-25 18:42:34 +0200673U_BOOT_DRIVER(eth_designware) = {
Simon Glass75577ba2015-04-05 16:07:41 -0600674 .name = "eth_designware",
675 .id = UCLASS_ETH,
676 .of_match = designware_eth_ids,
677 .ofdata_to_platdata = designware_eth_ofdata_to_platdata,
Bin Meng8b7ee662015-09-11 03:24:35 -0700678 .bind = designware_eth_bind,
Simon Glass75577ba2015-04-05 16:07:41 -0600679 .probe = designware_eth_probe,
Bin Meng5d2459f2015-10-07 21:32:38 -0700680 .remove = designware_eth_remove,
Simon Glass75577ba2015-04-05 16:07:41 -0600681 .ops = &designware_eth_ops,
682 .priv_auto_alloc_size = sizeof(struct dw_eth_dev),
683 .platdata_auto_alloc_size = sizeof(struct eth_pdata),
684 .flags = DM_FLAG_ALLOC_PRIV_DMA,
685};
Bin Meng8b7ee662015-09-11 03:24:35 -0700686
687static struct pci_device_id supported[] = {
688 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_EMAC) },
689 { }
690};
691
692U_BOOT_PCI_DEVICE(eth_designware, supported);
Simon Glass75577ba2015-04-05 16:07:41 -0600693#endif