]>
git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/net/ftmac110.c
2 * Faraday 10/100Mbps Ethernet Controller
4 * (C) Copyright 2013 Faraday Technology
5 * Dante Su <dantesu@faraday-tech.com>
7 * SPDX-License-Identifier: GPL-2.0+
14 #include <linux/errno.h>
16 #include <asm/dma-mapping.h>
18 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
24 #define CFG_RXDES_NUM 8
25 #define CFG_TXDES_NUM 2
26 #define CFG_XBUF_SIZE 1536
28 #define CFG_MDIORD_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */
29 #define CFG_MDIOWR_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */
30 #define CFG_LINKUP_TIMEOUT (CONFIG_SYS_HZ << 2) /* 4 sec */
33 * FTMAC110 DMA design issue
35 * Its DMA engine has a weird restriction that its Rx DMA engine
36 * accepts only 16-bits aligned address, 32-bits aligned is not
37 * acceptable. However this restriction does not apply to Tx DMA.
40 * (1) Tx DMA Buffer Address:
41 * 1 bytes aligned: Invalid
42 * 2 bytes aligned: O.K
43 * 4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)
44 * (2) Rx DMA Buffer Address:
45 * 1 bytes aligned: Invalid
46 * 2 bytes aligned: O.K
47 * 4 bytes aligned: Invalid
50 struct ftmac110_chip
{
57 struct ftmac110_desc
*rxd
;
61 struct ftmac110_desc
*txd
;
66 static int ftmac110_reset(struct eth_device
*dev
);
68 static uint16_t mdio_read(struct eth_device
*dev
,
69 uint8_t phyaddr
, uint8_t phyreg
)
71 struct ftmac110_chip
*chip
= dev
->priv
;
72 struct ftmac110_regs
*regs
= chip
->regs
;
74 uint16_t ret
= 0xffff;
77 | (phyaddr
<< PHYCR_ADDR_SHIFT
)
78 | (phyreg
<< PHYCR_REG_SHIFT
);
80 writel(tmp
, ®s
->phycr
);
82 for (ts
= get_timer(0); get_timer(ts
) < CFG_MDIORD_TIMEOUT
; ) {
83 tmp
= readl(®s
->phycr
);
90 printf("ftmac110: mdio read timeout\n");
92 ret
= (uint16_t)(tmp
& 0xffff);
97 static void mdio_write(struct eth_device
*dev
,
98 uint8_t phyaddr
, uint8_t phyreg
, uint16_t phydata
)
100 struct ftmac110_chip
*chip
= dev
->priv
;
101 struct ftmac110_regs
*regs
= chip
->regs
;
105 | (phyaddr
<< PHYCR_ADDR_SHIFT
)
106 | (phyreg
<< PHYCR_REG_SHIFT
);
108 writel(phydata
, ®s
->phydr
);
109 writel(tmp
, ®s
->phycr
);
111 for (ts
= get_timer(0); get_timer(ts
) < CFG_MDIOWR_TIMEOUT
; ) {
112 if (readl(®s
->phycr
) & PHYCR_WRITE
)
117 if (readl(®s
->phycr
) & PHYCR_WRITE
)
118 printf("ftmac110: mdio write timeout\n");
121 static uint32_t ftmac110_phyqry(struct eth_device
*dev
)
125 uint16_t pa
, tmp
, bmsr
, bmcr
;
126 struct ftmac110_chip
*chip
= dev
->priv
;
128 /* Default = 100Mbps Full */
129 maccr
= MACCR_100M
| MACCR_FD
;
131 /* 1. find the phy device */
132 for (pa
= 0; pa
< 32; ++pa
) {
133 tmp
= mdio_read(dev
, pa
, MII_PHYSID1
);
134 if (tmp
== 0xFFFF || tmp
== 0x0000)
140 puts("ftmac110: phy device not found!\n");
144 /* 2. wait until link-up & auto-negotiation complete */
146 bmcr
= mdio_read(dev
, chip
->phy_addr
, MII_BMCR
);
149 bmsr
= mdio_read(dev
, chip
->phy_addr
, MII_BMSR
);
150 chip
->lnkup
= (bmsr
& BMSR_LSTATUS
) ? 1 : 0;
153 if (!(bmcr
& BMCR_ANENABLE
) || (bmsr
& BMSR_ANEGCOMPLETE
))
155 } while (get_timer(ts
) < CFG_LINKUP_TIMEOUT
);
157 puts("ftmac110: link down\n");
160 if (!(bmcr
& BMCR_ANENABLE
))
161 puts("ftmac110: auto negotiation disabled\n");
162 else if (!(bmsr
& BMSR_ANEGCOMPLETE
))
163 puts("ftmac110: auto negotiation timeout\n");
165 /* 3. derive MACCR */
166 if ((bmcr
& BMCR_ANENABLE
) && (bmsr
& BMSR_ANEGCOMPLETE
)) {
167 tmp
= mdio_read(dev
, chip
->phy_addr
, MII_ADVERTISE
);
168 tmp
&= mdio_read(dev
, chip
->phy_addr
, MII_LPA
);
169 if (tmp
& LPA_100FULL
) /* 100Mbps full-duplex */
170 maccr
= MACCR_100M
| MACCR_FD
;
171 else if (tmp
& LPA_100HALF
) /* 100Mbps half-duplex */
173 else if (tmp
& LPA_10FULL
) /* 10Mbps full-duplex */
175 else if (tmp
& LPA_10HALF
) /* 10Mbps half-duplex */
178 if (bmcr
& BMCR_SPEED100
)
182 if (bmcr
& BMCR_FULLDPLX
)
187 printf("ftmac110: %d Mbps, %s\n",
188 (maccr
& MACCR_100M
) ? 100 : 10,
189 (maccr
& MACCR_FD
) ? "Full" : "half");
193 static int ftmac110_reset(struct eth_device
*dev
)
197 struct ftmac110_chip
*chip
= dev
->priv
;
198 struct ftmac110_regs
*regs
= chip
->regs
;
201 writel(MACCR_RESET
, ®s
->maccr
);
202 for (i
= get_timer(0); get_timer(i
) < 1000; ) {
203 if (readl(®s
->maccr
) & MACCR_RESET
)
207 if (readl(®s
->maccr
) & MACCR_RESET
) {
208 printf("ftmac110: reset failed\n");
212 /* 1-1. Init tx ring */
213 for (i
= 0; i
< CFG_TXDES_NUM
; ++i
) {
215 chip
->txd
[i
].ctrl
&= cpu_to_le64(FTMAC110_TXD_CLRMASK
);
219 /* 1-2. Init rx ring */
220 for (i
= 0; i
< CFG_RXDES_NUM
; ++i
) {
222 chip
->rxd
[i
].ctrl
&= cpu_to_le64(FTMAC110_RXD_CLRMASK
);
223 chip
->rxd
[i
].ctrl
|= cpu_to_le64(FTMAC110_RXD_OWNER
);
227 /* 2. PHY status query */
228 maccr
= ftmac110_phyqry(dev
);
230 /* 3. Fix up the MACCR value */
231 chip
->maccr
= maccr
| MACCR_CRCAPD
| MACCR_RXALL
| MACCR_RXRUNT
232 | MACCR_RXEN
| MACCR_TXEN
| MACCR_RXDMAEN
| MACCR_TXDMAEN
;
234 /* 4. MAC address setup */
236 writel(a
[1] | (a
[0] << 8), ®s
->mac
[0]);
237 writel(a
[5] | (a
[4] << 8) | (a
[3] << 16)
238 | (a
[2] << 24), ®s
->mac
[1]);
240 /* 5. MAC registers setup */
241 writel(chip
->rxd_dma
, ®s
->rxba
);
242 writel(chip
->txd_dma
, ®s
->txba
);
243 /* interrupt at each tx/rx */
244 writel(ITC_DEFAULT
, ®s
->itc
);
245 /* no tx pool, rx poll = 1 normal cycle */
246 writel(APTC_DEFAULT
, ®s
->aptc
);
247 /* rx threshold = [6/8 fifo, 2/8 fifo] */
248 writel(DBLAC_DEFAULT
, ®s
->dblac
);
249 /* disable & clear all interrupt status */
251 writel(ISR_ALL
, ®s
->isr
);
252 writel(chip
->imr
, ®s
->imr
);
254 writel(chip
->maccr
, ®s
->maccr
);
259 static int ftmac110_probe(struct eth_device
*dev
, bd_t
*bis
)
261 debug("ftmac110: probe\n");
263 if (ftmac110_reset(dev
))
269 static void ftmac110_halt(struct eth_device
*dev
)
271 struct ftmac110_chip
*chip
= dev
->priv
;
272 struct ftmac110_regs
*regs
= chip
->regs
;
274 writel(0, ®s
->imr
);
275 writel(0, ®s
->maccr
);
277 debug("ftmac110: halt\n");
280 static int ftmac110_send(struct eth_device
*dev
, void *pkt
, int len
)
282 struct ftmac110_chip
*chip
= dev
->priv
;
283 struct ftmac110_regs
*regs
= chip
->regs
;
284 struct ftmac110_desc
*txd
;
290 if (len
<= 0 || len
> CFG_XBUF_SIZE
) {
291 printf("ftmac110: bad tx pkt len(%d)\n", len
);
297 txd
= &chip
->txd
[chip
->txd_idx
];
298 ctrl
= le64_to_cpu(txd
->ctrl
);
299 if (ctrl
& FTMAC110_TXD_OWNER
) {
300 /* kick-off Tx DMA */
301 writel(0xffffffff, ®s
->txpd
);
302 printf("ftmac110: out of txd\n");
306 memcpy(txd
->vbuf
, (void *)pkt
, len
);
307 dma_map_single(txd
->vbuf
, len
, DMA_TO_DEVICE
);
309 /* clear control bits */
310 ctrl
&= FTMAC110_TXD_CLRMASK
;
311 /* set len, fts and lts */
312 ctrl
|= FTMAC110_TXD_LEN(len
) | FTMAC110_TXD_FTS
| FTMAC110_TXD_LTS
;
314 ctrl
|= FTMAC110_TXD_OWNER
;
315 /* write back to descriptor */
316 txd
->ctrl
= cpu_to_le64(ctrl
);
318 /* kick-off Tx DMA */
319 writel(0xffffffff, ®s
->txpd
);
321 chip
->txd_idx
= (chip
->txd_idx
+ 1) % CFG_TXDES_NUM
;
326 static int ftmac110_recv(struct eth_device
*dev
)
328 struct ftmac110_chip
*chip
= dev
->priv
;
329 struct ftmac110_desc
*rxd
;
330 uint32_t len
, rlen
= 0;
338 rxd
= &chip
->rxd
[chip
->rxd_idx
];
339 ctrl
= le64_to_cpu(rxd
->ctrl
);
340 if (ctrl
& FTMAC110_RXD_OWNER
)
343 len
= (uint32_t)FTMAC110_RXD_LEN(ctrl
);
346 if (ctrl
& FTMAC110_RXD_ERRMASK
) {
347 printf("ftmac110: rx error\n");
349 dma_map_single(buf
, len
, DMA_FROM_DEVICE
);
350 net_process_received_packet(buf
, len
);
354 /* owned by hardware */
355 ctrl
&= FTMAC110_RXD_CLRMASK
;
356 ctrl
|= FTMAC110_RXD_OWNER
;
357 rxd
->ctrl
|= cpu_to_le64(ctrl
);
359 chip
->rxd_idx
= (chip
->rxd_idx
+ 1) % CFG_RXDES_NUM
;
365 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
367 static int ftmac110_mdio_read(struct mii_dev
*bus
, int addr
, int devad
,
372 struct eth_device
*dev
;
374 dev
= eth_get_dev_by_name(bus
->name
);
376 printf("%s: no such device\n", bus
->name
);
379 value
= mdio_read(dev
, addr
, reg
);
387 static int ftmac110_mdio_write(struct mii_dev
*bus
, int addr
, int devad
,
391 struct eth_device
*dev
;
393 dev
= eth_get_dev_by_name(bus
->name
);
395 printf("%s: no such device\n", bus
->name
);
398 mdio_write(dev
, addr
, reg
, value
);
404 #endif /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
406 int ftmac110_initialize(bd_t
*bis
)
409 struct eth_device
*dev
;
410 struct ftmac110_chip
*chip
;
412 dev
= malloc(sizeof(*dev
) + sizeof(*chip
));
414 panic("ftmac110: out of memory 1\n");
417 chip
= (struct ftmac110_chip
*)(dev
+ 1);
418 memset(dev
, 0, sizeof(*dev
) + sizeof(*chip
));
420 sprintf(dev
->name
, "FTMAC110#%d", card_nr
);
422 dev
->iobase
= CONFIG_FTMAC110_BASE
;
423 chip
->regs
= (void __iomem
*)dev
->iobase
;
425 dev
->init
= ftmac110_probe
;
426 dev
->halt
= ftmac110_halt
;
427 dev
->send
= ftmac110_send
;
428 dev
->recv
= ftmac110_recv
;
430 /* allocate tx descriptors (it must be 16 bytes aligned) */
431 chip
->txd
= dma_alloc_coherent(
432 sizeof(struct ftmac110_desc
) * CFG_TXDES_NUM
, &chip
->txd_dma
);
434 panic("ftmac110: out of memory 3\n");
436 sizeof(struct ftmac110_desc
) * CFG_TXDES_NUM
);
437 for (i
= 0; i
< CFG_TXDES_NUM
; ++i
) {
438 void *va
= memalign(ARCH_DMA_MINALIGN
, CFG_XBUF_SIZE
);
441 panic("ftmac110: out of memory 4\n");
442 chip
->txd
[i
].vbuf
= va
;
443 chip
->txd
[i
].pbuf
= cpu_to_le32(virt_to_phys(va
));
444 chip
->txd
[i
].ctrl
= 0; /* owned by SW */
446 chip
->txd
[i
- 1].ctrl
|= cpu_to_le64(FTMAC110_TXD_END
);
449 /* allocate rx descriptors (it must be 16 bytes aligned) */
450 chip
->rxd
= dma_alloc_coherent(
451 sizeof(struct ftmac110_desc
) * CFG_RXDES_NUM
, &chip
->rxd_dma
);
453 panic("ftmac110: out of memory 4\n");
454 memset((void *)chip
->rxd
, 0,
455 sizeof(struct ftmac110_desc
) * CFG_RXDES_NUM
);
456 for (i
= 0; i
< CFG_RXDES_NUM
; ++i
) {
457 void *va
= memalign(ARCH_DMA_MINALIGN
, CFG_XBUF_SIZE
+ 2);
460 panic("ftmac110: out of memory 5\n");
461 /* it needs to be exactly 2 bytes aligned */
462 va
= ((uint8_t *)va
+ 2);
463 chip
->rxd
[i
].vbuf
= va
;
464 chip
->rxd
[i
].pbuf
= cpu_to_le32(virt_to_phys(va
));
465 chip
->rxd
[i
].ctrl
= cpu_to_le64(FTMAC110_RXD_OWNER
466 | FTMAC110_RXD_BUFSZ(CFG_XBUF_SIZE
));
468 chip
->rxd
[i
- 1].ctrl
|= cpu_to_le64(FTMAC110_RXD_END
);
473 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
475 struct mii_dev
*mdiodev
= mdio_alloc();
478 strncpy(mdiodev
->name
, dev
->name
, MDIO_NAME_LEN
);
479 mdiodev
->read
= ftmac110_mdio_read
;
480 mdiodev
->write
= ftmac110_mdio_write
;
482 retval
= mdio_register(mdiodev
);