3 * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
5 * SPDX-License-Identifier: GPL-2.0+
9 * Designware ethernet IP driver for u-boot
15 #include <linux/compiler.h>
16 #include <linux/err.h>
18 #include "designware.h"
20 static int configure_phy(struct eth_device
*dev
);
22 static void tx_descs_init(struct eth_device
*dev
)
24 struct dw_eth_dev
*priv
= dev
->priv
;
25 struct eth_dma_regs
*dma_p
= priv
->dma_regs_p
;
26 struct dmamacdescr
*desc_table_p
= &priv
->tx_mac_descrtable
[0];
27 char *txbuffs
= &priv
->txbuffs
[0];
28 struct dmamacdescr
*desc_p
;
31 for (idx
= 0; idx
< CONFIG_TX_DESCR_NUM
; idx
++) {
32 desc_p
= &desc_table_p
[idx
];
33 desc_p
->dmamac_addr
= &txbuffs
[idx
* CONFIG_ETH_BUFSIZE
];
34 desc_p
->dmamac_next
= &desc_table_p
[idx
+ 1];
36 #if defined(CONFIG_DW_ALTDESCRIPTOR)
37 desc_p
->txrx_status
&= ~(DESC_TXSTS_TXINT
| DESC_TXSTS_TXLAST
|
38 DESC_TXSTS_TXFIRST
| DESC_TXSTS_TXCRCDIS
| \
39 DESC_TXSTS_TXCHECKINSCTRL
| \
40 DESC_TXSTS_TXRINGEND
| DESC_TXSTS_TXPADDIS
);
42 desc_p
->txrx_status
|= DESC_TXSTS_TXCHAIN
;
43 desc_p
->dmamac_cntl
= 0;
44 desc_p
->txrx_status
&= ~(DESC_TXSTS_MSK
| DESC_TXSTS_OWNBYDMA
);
46 desc_p
->dmamac_cntl
= DESC_TXCTRL_TXCHAIN
;
47 desc_p
->txrx_status
= 0;
51 /* Correcting the last pointer of the chain */
52 desc_p
->dmamac_next
= &desc_table_p
[0];
54 writel((ulong
)&desc_table_p
[0], &dma_p
->txdesclistaddr
);
57 static void rx_descs_init(struct eth_device
*dev
)
59 struct dw_eth_dev
*priv
= dev
->priv
;
60 struct eth_dma_regs
*dma_p
= priv
->dma_regs_p
;
61 struct dmamacdescr
*desc_table_p
= &priv
->rx_mac_descrtable
[0];
62 char *rxbuffs
= &priv
->rxbuffs
[0];
63 struct dmamacdescr
*desc_p
;
66 for (idx
= 0; idx
< CONFIG_RX_DESCR_NUM
; idx
++) {
67 desc_p
= &desc_table_p
[idx
];
68 desc_p
->dmamac_addr
= &rxbuffs
[idx
* CONFIG_ETH_BUFSIZE
];
69 desc_p
->dmamac_next
= &desc_table_p
[idx
+ 1];
72 (MAC_MAX_FRAME_SZ
& DESC_RXCTRL_SIZE1MASK
) | \
75 desc_p
->txrx_status
= DESC_RXSTS_OWNBYDMA
;
78 /* Correcting the last pointer of the chain */
79 desc_p
->dmamac_next
= &desc_table_p
[0];
81 writel((ulong
)&desc_table_p
[0], &dma_p
->rxdesclistaddr
);
84 static void descs_init(struct eth_device
*dev
)
90 static int mac_reset(struct eth_device
*dev
)
92 struct dw_eth_dev
*priv
= dev
->priv
;
93 struct eth_mac_regs
*mac_p
= priv
->mac_regs_p
;
94 struct eth_dma_regs
*dma_p
= priv
->dma_regs_p
;
97 int timeout
= CONFIG_MACRESET_TIMEOUT
;
99 writel(DMAMAC_SRST
, &dma_p
->busmode
);
101 if (priv
->interface
!= PHY_INTERFACE_MODE_RGMII
)
102 writel(MII_PORTSELECT
, &mac_p
->conf
);
104 start
= get_timer(0);
105 while (get_timer(start
) < timeout
) {
106 if (!(readl(&dma_p
->busmode
) & DMAMAC_SRST
))
109 /* Try again after 10usec */
116 static int dw_write_hwaddr(struct eth_device
*dev
)
118 struct dw_eth_dev
*priv
= dev
->priv
;
119 struct eth_mac_regs
*mac_p
= priv
->mac_regs_p
;
120 u32 macid_lo
, macid_hi
;
121 u8
*mac_id
= &dev
->enetaddr
[0];
123 macid_lo
= mac_id
[0] + (mac_id
[1] << 8) + \
124 (mac_id
[2] << 16) + (mac_id
[3] << 24);
125 macid_hi
= mac_id
[4] + (mac_id
[5] << 8);
127 writel(macid_hi
, &mac_p
->macaddr0hi
);
128 writel(macid_lo
, &mac_p
->macaddr0lo
);
133 static int dw_eth_init(struct eth_device
*dev
, bd_t
*bis
)
135 struct dw_eth_dev
*priv
= dev
->priv
;
136 struct eth_mac_regs
*mac_p
= priv
->mac_regs_p
;
137 struct eth_dma_regs
*dma_p
= priv
->dma_regs_p
;
140 if (priv
->phy_configured
!= 1)
143 /* Print link status only once */
144 if (!priv
->link_printed
) {
145 printf("ENET Speed is %d Mbps - %s duplex connection\n",
146 priv
->speed
, (priv
->duplex
== HALF
) ? "HALF" : "FULL");
147 priv
->link_printed
= 1;
150 /* Reset ethernet hardware */
151 if (mac_reset(dev
) < 0)
154 /* Resore the HW MAC address as it has been lost during MAC reset */
155 dw_write_hwaddr(dev
);
157 writel(FIXEDBURST
| PRIORXTX_41
| BURST_16
,
160 writel(readl(&dma_p
->opmode
) | FLUSHTXFIFO
| STOREFORWARD
|
161 TXSECONDFRAME
, &dma_p
->opmode
);
163 conf
= FRAMEBURSTENABLE
| DISABLERXOWN
;
165 if (priv
->speed
!= 1000)
166 conf
|= MII_PORTSELECT
;
168 if ((priv
->interface
!= PHY_INTERFACE_MODE_MII
) &&
169 (priv
->interface
!= PHY_INTERFACE_MODE_GMII
)) {
171 if (priv
->speed
== 100)
175 if (priv
->duplex
== FULL
)
176 conf
|= FULLDPLXMODE
;
178 writel(conf
, &mac_p
->conf
);
183 * Start/Enable xfer at dma as well as mac level
185 writel(readl(&dma_p
->opmode
) | RXSTART
, &dma_p
->opmode
);
186 writel(readl(&dma_p
->opmode
) | TXSTART
, &dma_p
->opmode
);
188 writel(readl(&mac_p
->conf
) | RXENABLE
| TXENABLE
, &mac_p
->conf
);
193 static int dw_eth_send(struct eth_device
*dev
, void *packet
, int length
)
195 struct dw_eth_dev
*priv
= dev
->priv
;
196 struct eth_dma_regs
*dma_p
= priv
->dma_regs_p
;
197 u32 desc_num
= priv
->tx_currdescnum
;
198 struct dmamacdescr
*desc_p
= &priv
->tx_mac_descrtable
[desc_num
];
200 /* Check if the descriptor is owned by CPU */
201 if (desc_p
->txrx_status
& DESC_TXSTS_OWNBYDMA
) {
202 printf("CPU not owner of tx frame\n");
206 memcpy((void *)desc_p
->dmamac_addr
, packet
, length
);
208 #if defined(CONFIG_DW_ALTDESCRIPTOR)
209 desc_p
->txrx_status
|= DESC_TXSTS_TXFIRST
| DESC_TXSTS_TXLAST
;
210 desc_p
->dmamac_cntl
|= (length
<< DESC_TXCTRL_SIZE1SHFT
) & \
211 DESC_TXCTRL_SIZE1MASK
;
213 desc_p
->txrx_status
&= ~(DESC_TXSTS_MSK
);
214 desc_p
->txrx_status
|= DESC_TXSTS_OWNBYDMA
;
216 desc_p
->dmamac_cntl
|= ((length
<< DESC_TXCTRL_SIZE1SHFT
) & \
217 DESC_TXCTRL_SIZE1MASK
) | DESC_TXCTRL_TXLAST
| \
220 desc_p
->txrx_status
= DESC_TXSTS_OWNBYDMA
;
223 /* Test the wrap-around condition. */
224 if (++desc_num
>= CONFIG_TX_DESCR_NUM
)
227 priv
->tx_currdescnum
= desc_num
;
229 /* Start the transmission */
230 writel(POLL_DATA
, &dma_p
->txpolldemand
);
235 static int dw_eth_recv(struct eth_device
*dev
)
237 struct dw_eth_dev
*priv
= dev
->priv
;
238 u32 desc_num
= priv
->rx_currdescnum
;
239 struct dmamacdescr
*desc_p
= &priv
->rx_mac_descrtable
[desc_num
];
241 u32 status
= desc_p
->txrx_status
;
244 /* Check if the owner is the CPU */
245 if (!(status
& DESC_RXSTS_OWNBYDMA
)) {
247 length
= (status
& DESC_RXSTS_FRMLENMSK
) >> \
248 DESC_RXSTS_FRMLENSHFT
;
250 NetReceive(desc_p
->dmamac_addr
, length
);
253 * Make the current descriptor valid again and go to
256 desc_p
->txrx_status
|= DESC_RXSTS_OWNBYDMA
;
258 /* Test the wrap-around condition. */
259 if (++desc_num
>= CONFIG_RX_DESCR_NUM
)
263 priv
->rx_currdescnum
= desc_num
;
268 static void dw_eth_halt(struct eth_device
*dev
)
270 struct dw_eth_dev
*priv
= dev
->priv
;
273 priv
->tx_currdescnum
= priv
->rx_currdescnum
= 0;
276 static int eth_mdio_read(struct eth_device
*dev
, u8 addr
, u8 reg
, u16
*val
)
278 struct dw_eth_dev
*priv
= dev
->priv
;
279 struct eth_mac_regs
*mac_p
= priv
->mac_regs_p
;
282 int timeout
= CONFIG_MDIO_TIMEOUT
;
284 miiaddr
= ((addr
<< MIIADDRSHIFT
) & MII_ADDRMSK
) | \
285 ((reg
<< MIIREGSHIFT
) & MII_REGMSK
);
287 writel(miiaddr
| MII_CLKRANGE_150_250M
| MII_BUSY
, &mac_p
->miiaddr
);
289 start
= get_timer(0);
290 while (get_timer(start
) < timeout
) {
291 if (!(readl(&mac_p
->miiaddr
) & MII_BUSY
)) {
292 *val
= readl(&mac_p
->miidata
);
296 /* Try again after 10usec */
303 static int eth_mdio_write(struct eth_device
*dev
, u8 addr
, u8 reg
, u16 val
)
305 struct dw_eth_dev
*priv
= dev
->priv
;
306 struct eth_mac_regs
*mac_p
= priv
->mac_regs_p
;
309 int ret
= -1, timeout
= CONFIG_MDIO_TIMEOUT
;
312 writel(val
, &mac_p
->miidata
);
313 miiaddr
= ((addr
<< MIIADDRSHIFT
) & MII_ADDRMSK
) | \
314 ((reg
<< MIIREGSHIFT
) & MII_REGMSK
) | MII_WRITE
;
316 writel(miiaddr
| MII_CLKRANGE_150_250M
| MII_BUSY
, &mac_p
->miiaddr
);
318 start
= get_timer(0);
319 while (get_timer(start
) < timeout
) {
320 if (!(readl(&mac_p
->miiaddr
) & MII_BUSY
)) {
325 /* Try again after 10usec */
329 /* Needed as a fix for ST-Phy */
330 eth_mdio_read(dev
, addr
, reg
, &value
);
335 #if defined(CONFIG_DW_SEARCH_PHY)
336 static int find_phy(struct eth_device
*dev
)
342 eth_mdio_read(dev
, phy_addr
, MII_BMCR
, &ctrl
);
343 oldctrl
= ctrl
& BMCR_ANENABLE
;
345 ctrl
^= BMCR_ANENABLE
;
346 eth_mdio_write(dev
, phy_addr
, MII_BMCR
, ctrl
);
347 eth_mdio_read(dev
, phy_addr
, MII_BMCR
, &ctrl
);
348 ctrl
&= BMCR_ANENABLE
;
350 if (ctrl
== oldctrl
) {
353 ctrl
^= BMCR_ANENABLE
;
354 eth_mdio_write(dev
, phy_addr
, MII_BMCR
, ctrl
);
358 } while (phy_addr
< 32);
364 static int dw_reset_phy(struct eth_device
*dev
)
366 struct dw_eth_dev
*priv
= dev
->priv
;
369 int timeout
= CONFIG_PHYRESET_TIMEOUT
;
370 u32 phy_addr
= priv
->address
;
372 eth_mdio_write(dev
, phy_addr
, MII_BMCR
, BMCR_RESET
);
374 start
= get_timer(0);
375 while (get_timer(start
) < timeout
) {
376 eth_mdio_read(dev
, phy_addr
, MII_BMCR
, &ctrl
);
377 if (!(ctrl
& BMCR_RESET
))
380 /* Try again after 10usec */
384 if (get_timer(start
) >= CONFIG_PHYRESET_TIMEOUT
)
387 #ifdef CONFIG_PHY_RESET_DELAY
388 udelay(CONFIG_PHY_RESET_DELAY
);
394 * Add weak default function for board specific PHY configuration
396 int __weak
designware_board_phy_init(struct eth_device
*dev
, int phy_addr
,
397 int (*mii_write
)(struct eth_device
*, u8
, u8
, u16
),
398 int dw_reset_phy(struct eth_device
*))
403 static int configure_phy(struct eth_device
*dev
)
405 struct dw_eth_dev
*priv
= dev
->priv
;
408 #if defined(CONFIG_DW_AUTONEG)
414 #if defined(CONFIG_DW_SEARCH_PHY)
415 phy_addr
= find_phy(dev
);
417 priv
->address
= phy_addr
;
421 phy_addr
= priv
->address
;
425 * Some boards need board specific PHY initialization. This is
426 * after the main driver init code but before the auto negotiation
429 if (designware_board_phy_init(dev
, phy_addr
,
430 eth_mdio_write
, dw_reset_phy
) < 0)
433 if (dw_reset_phy(dev
) < 0)
436 #if defined(CONFIG_DW_AUTONEG)
437 /* Set Auto-Neg Advertisement capabilities to 10/100 half/full */
438 eth_mdio_write(dev
, phy_addr
, MII_ADVERTISE
, 0x1E1);
440 bmcr
= BMCR_ANENABLE
| BMCR_ANRESTART
;
442 bmcr
= BMCR_SPEED100
| BMCR_FULLDPLX
;
444 #if defined(CONFIG_DW_SPEED10M)
445 bmcr
&= ~BMCR_SPEED100
;
447 #if defined(CONFIG_DW_DUPLEXHALF)
448 bmcr
&= ~BMCR_FULLDPLX
;
451 if (eth_mdio_write(dev
, phy_addr
, MII_BMCR
, bmcr
) < 0)
454 /* Read the phy status register and populate priv structure */
455 #if defined(CONFIG_DW_AUTONEG)
456 timeout
= CONFIG_AUTONEG_TIMEOUT
;
457 start
= get_timer(0);
458 puts("Waiting for PHY auto negotiation to complete");
459 while (get_timer(start
) < timeout
) {
460 eth_mdio_read(dev
, phy_addr
, MII_BMSR
, &bmsr
);
461 if (bmsr
& BMSR_ANEGCOMPLETE
) {
462 priv
->phy_configured
= 1;
466 /* Print dot all 1s to show progress */
467 if ((get_timer(start
) % 1000) == 0)
470 /* Try again after 1msec */
474 if (!(bmsr
& BMSR_ANEGCOMPLETE
))
479 priv
->phy_configured
= 1;
482 priv
->speed
= miiphy_speed(dev
->name
, phy_addr
);
483 priv
->duplex
= miiphy_duplex(dev
->name
, phy_addr
);
488 #if defined(CONFIG_MII)
489 static int dw_mii_read(const char *devname
, u8 addr
, u8 reg
, u16
*val
)
491 struct eth_device
*dev
;
493 dev
= eth_get_dev_by_name(devname
);
495 eth_mdio_read(dev
, addr
, reg
, val
);
500 static int dw_mii_write(const char *devname
, u8 addr
, u8 reg
, u16 val
)
502 struct eth_device
*dev
;
504 dev
= eth_get_dev_by_name(devname
);
506 eth_mdio_write(dev
, addr
, reg
, val
);
512 int designware_initialize(u32 id
, ulong base_addr
, u32 phy_addr
, u32 interface
)
514 struct eth_device
*dev
;
515 struct dw_eth_dev
*priv
;
517 dev
= (struct eth_device
*) malloc(sizeof(struct eth_device
));
522 * Since the priv structure contains the descriptors which need a strict
523 * buswidth alignment, memalign is used to allocate memory
525 priv
= (struct dw_eth_dev
*) memalign(16, sizeof(struct dw_eth_dev
));
531 memset(dev
, 0, sizeof(struct eth_device
));
532 memset(priv
, 0, sizeof(struct dw_eth_dev
));
534 sprintf(dev
->name
, "mii%d", id
);
535 dev
->iobase
= (int)base_addr
;
538 eth_getenv_enetaddr_by_index("eth", id
, &dev
->enetaddr
[0]);
541 priv
->mac_regs_p
= (struct eth_mac_regs
*)base_addr
;
542 priv
->dma_regs_p
= (struct eth_dma_regs
*)(base_addr
+
544 priv
->address
= phy_addr
;
545 priv
->phy_configured
= 0;
546 priv
->interface
= interface
;
548 dev
->init
= dw_eth_init
;
549 dev
->send
= dw_eth_send
;
550 dev
->recv
= dw_eth_recv
;
551 dev
->halt
= dw_eth_halt
;
552 dev
->write_hwaddr
= dw_write_hwaddr
;
556 #if defined(CONFIG_MII)
557 miiphy_register(dev
->name
, dw_mii_read
, dw_mii_write
);