]>
git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/net/ftmac110.c
2 * Faraday 10/100Mbps Ethernet Controller
4 * (C) Copyright 2010 Faraday Technology
5 * Dante Su <dantesu@faraday-tech.com>
7 * SPDX-License-Identifier: GPL-2.0+
14 #include <asm/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_rxd
*rxd
;
61 struct ftmac110_txd
*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 __iomem
*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 __iomem
*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 __iomem
*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
].ct
[0] = 0;
219 /* 1-2. Init rx ring */
220 for (i
= 0; i
< CFG_RXDES_NUM
; ++i
) {
222 chip
->rxd
[i
].ct
[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER
);
226 /* 2. PHY status query */
227 maccr
= ftmac110_phyqry(dev
);
229 /* 3. Fix up the MACCR value */
230 chip
->maccr
= maccr
| MACCR_CRCAPD
| MACCR_RXALL
| MACCR_RXRUNT
231 | MACCR_RXEN
| MACCR_TXEN
| MACCR_RXDMAEN
| MACCR_TXDMAEN
;
233 /* 4. MAC address setup */
235 writel(a
[1] | (a
[0] << 8), ®s
->mac
[0]);
236 writel(a
[5] | (a
[4] << 8) | (a
[3] << 16)
237 | (a
[2] << 24), ®s
->mac
[1]);
239 /* 5. MAC registers setup */
240 writel(chip
->rxd_dma
, ®s
->rxba
);
241 writel(chip
->txd_dma
, ®s
->txba
);
242 /* interrupt at each tx/rx */
243 writel(ITC_DEFAULT
, ®s
->itc
);
244 /* no tx pool, rx poll = 1 normal cycle */
245 writel(APTC_DEFAULT
, ®s
->aptc
);
246 /* rx threshold = [6/8 fifo, 2/8 fifo] */
247 writel(DBLAC_DEFAULT
, ®s
->dblac
);
248 /* disable & clear all interrupt status */
250 writel(ISR_ALL
, ®s
->isr
);
251 writel(chip
->imr
, ®s
->imr
);
253 writel(chip
->maccr
, ®s
->maccr
);
258 static int ftmac110_probe(struct eth_device
*dev
, bd_t
*bis
)
260 debug("ftmac110: probe\n");
262 if (ftmac110_reset(dev
))
268 static void ftmac110_halt(struct eth_device
*dev
)
270 struct ftmac110_chip
*chip
= dev
->priv
;
271 struct ftmac110_regs __iomem
*regs
= chip
->regs
;
273 writel(0, ®s
->imr
);
274 writel(0, ®s
->maccr
);
276 debug("ftmac110: halt\n");
279 static int ftmac110_send(struct eth_device
*dev
, void *pkt
, int len
)
281 struct ftmac110_chip
*chip
= dev
->priv
;
282 struct ftmac110_regs __iomem
*regs
= chip
->regs
;
283 struct ftmac110_txd
*des
;
288 if (len
<= 0 || len
> CFG_XBUF_SIZE
) {
289 printf("ftmac110: bad tx pkt len(%d)\n", len
);
295 des
= &chip
->txd
[chip
->txd_idx
];
296 if (le32_to_cpu(des
->ct
[0]) & FTMAC110_TXCT0_OWNER
) {
297 /* kick-off Tx DMA */
298 writel(0xffffffff, ®s
->txpd
);
299 printf("ftmac110: out of txd\n");
303 memcpy(des
->vbuf
, (void *)pkt
, len
);
304 dma_map_single(des
->vbuf
, len
, DMA_TO_DEVICE
);
306 /* update len, fts and lts */
307 des
->ct
[1] &= cpu_to_le32(FTMAC110_TXCT1_END
);
308 des
->ct
[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len
)
309 | FTMAC110_TXCT1_FTS
| FTMAC110_TXCT1_LTS
);
311 /* set owner bit and clear others */
312 des
->ct
[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER
);
314 /* kick-off Tx DMA */
315 writel(0xffffffff, ®s
->txpd
);
317 chip
->txd_idx
= (chip
->txd_idx
+ 1) % CFG_TXDES_NUM
;
322 static int ftmac110_recv(struct eth_device
*dev
)
324 struct ftmac110_chip
*chip
= dev
->priv
;
325 struct ftmac110_rxd
*des
;
326 uint32_t ct0
, len
, rlen
= 0;
333 des
= &chip
->rxd
[chip
->rxd_idx
];
334 ct0
= le32_to_cpu(des
->ct
[0]);
335 if (ct0
& FTMAC110_RXCT0_OWNER
)
338 len
= FTMAC110_RXCT0_LEN(ct0
);
341 if (ct0
& FTMAC110_RXCT0_ERRMASK
) {
342 printf("ftmac110: rx error\n");
344 dma_map_single(buf
, len
, DMA_FROM_DEVICE
);
345 NetReceive(buf
, len
);
349 /* owned by hardware */
350 des
->ct
[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER
);
352 chip
->rxd_idx
= (chip
->rxd_idx
+ 1) % CFG_RXDES_NUM
;
358 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
360 static int ftmac110_mdio_read(
361 const char *devname
, uint8_t addr
, uint8_t reg
, uint16_t *value
)
364 struct eth_device
*dev
;
366 dev
= eth_get_dev_by_name(devname
);
368 printf("%s: no such device\n", devname
);
371 *value
= mdio_read(dev
, addr
, reg
);
377 static int ftmac110_mdio_write(
378 const char *devname
, uint8_t addr
, uint8_t reg
, uint16_t value
)
381 struct eth_device
*dev
;
383 dev
= eth_get_dev_by_name(devname
);
385 printf("%s: no such device\n", devname
);
388 mdio_write(dev
, addr
, reg
, value
);
394 #endif /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
396 int ftmac110_initialize(bd_t
*bis
)
399 struct eth_device
*dev
;
400 struct ftmac110_chip
*chip
;
402 dev
= malloc(sizeof(*dev
) + sizeof(*chip
));
404 panic("ftmac110: out of memory 1\n");
407 chip
= (struct ftmac110_chip
*)(dev
+ 1);
408 memset(dev
, 0, sizeof(*dev
) + sizeof(*chip
));
410 sprintf(dev
->name
, "FTMAC110#%d", card_nr
);
412 dev
->iobase
= CONFIG_FTMAC110_BASE
;
413 chip
->regs
= (void __iomem
*)dev
->iobase
;
415 dev
->init
= ftmac110_probe
;
416 dev
->halt
= ftmac110_halt
;
417 dev
->send
= ftmac110_send
;
418 dev
->recv
= ftmac110_recv
;
420 if (!eth_getenv_enetaddr_by_index("eth", card_nr
, dev
->enetaddr
))
421 eth_random_enetaddr(dev
->enetaddr
);
423 /* allocate tx descriptors (it must be 16 bytes aligned) */
424 chip
->txd
= dma_alloc_coherent(
425 sizeof(struct ftmac110_txd
) * CFG_TXDES_NUM
, &chip
->txd_dma
);
427 panic("ftmac110: out of memory 3\n");
429 sizeof(struct ftmac110_txd
) * CFG_TXDES_NUM
);
430 for (i
= 0; i
< CFG_TXDES_NUM
; ++i
) {
431 void *va
= memalign(ARCH_DMA_MINALIGN
, CFG_XBUF_SIZE
);
433 panic("ftmac110: out of memory 4\n");
434 chip
->txd
[i
].vbuf
= va
;
435 chip
->txd
[i
].buf
= cpu_to_le32(virt_to_phys(va
));
436 chip
->txd
[i
].ct
[1] = 0;
437 chip
->txd
[i
].ct
[0] = 0; /* owned by SW */
439 chip
->txd
[i
- 1].ct
[1] |= cpu_to_le32(FTMAC110_TXCT1_END
);
442 /* allocate rx descriptors (it must be 16 bytes aligned) */
443 chip
->rxd
= dma_alloc_coherent(
444 sizeof(struct ftmac110_rxd
) * CFG_RXDES_NUM
, &chip
->rxd_dma
);
446 panic("ftmac110: out of memory 4\n");
447 memset((void *)chip
->rxd
, 0,
448 sizeof(struct ftmac110_rxd
) * CFG_RXDES_NUM
);
449 for (i
= 0; i
< CFG_RXDES_NUM
; ++i
) {
450 void *va
= memalign(ARCH_DMA_MINALIGN
, CFG_XBUF_SIZE
+ 2);
452 panic("ftmac110: out of memory 5\n");
453 /* it needs to be exactly 2 bytes aligned */
454 va
= ((uint8_t *)va
+ 2);
455 chip
->rxd
[i
].vbuf
= va
;
456 chip
->rxd
[i
].buf
= cpu_to_le32(virt_to_phys(va
));
457 chip
->rxd
[i
].ct
[1] = cpu_to_le32(CFG_XBUF_SIZE
);
458 chip
->rxd
[i
].ct
[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER
);
460 chip
->rxd
[i
- 1].ct
[1] |= cpu_to_le32(FTMAC110_RXCT1_END
);
465 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
466 miiphy_register(dev
->name
, ftmac110_mdio_read
, ftmac110_mdio_write
);