]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
1df49e27 WD |
2 | /* |
3 | * (C) Copyright 2002 | |
4 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
1df49e27 WD |
5 | */ |
6 | ||
7 | #include <common.h> | |
047a800d | 8 | #include <asm/io.h> |
5116aae1 | 9 | #include <cpu_func.h> |
1df49e27 | 10 | #include <malloc.h> |
047a800d | 11 | #include <miiphy.h> |
1df49e27 | 12 | #include <net.h> |
10efa024 | 13 | #include <netdev.h> |
1df49e27 | 14 | #include <pci.h> |
c05ed00a | 15 | #include <linux/delay.h> |
1df49e27 | 16 | |
aba283d8 | 17 | /* Ethernet chip registers. */ |
f3878f5c MV |
18 | #define SCB_STATUS 0 /* Rx/Command Unit Status *Word* */ |
19 | #define SCB_INT_ACK_BYTE 1 /* Rx/Command Unit STAT/ACK byte */ | |
20 | #define SCB_CMD 2 /* Rx/Command Unit Command *Word* */ | |
21 | #define SCB_INTR_CTL_BYTE 3 /* Rx/Command Unit Intr.Control Byte */ | |
22 | #define SCB_POINTER 4 /* General purpose pointer. */ | |
23 | #define SCB_PORT 8 /* Misc. commands and operands. */ | |
24 | #define SCB_FLASH 12 /* Flash memory control. */ | |
25 | #define SCB_EEPROM 14 /* EEPROM memory control. */ | |
26 | #define SCB_CTRL_MDI 16 /* MDI interface control. */ | |
27 | #define SCB_EARLY_RX 20 /* Early receive byte count. */ | |
28 | #define SCB_GEN_CONTROL 28 /* 82559 General Control Register */ | |
29 | #define SCB_GEN_STATUS 29 /* 82559 General Status register */ | |
1df49e27 | 30 | |
aba283d8 | 31 | /* 82559 SCB status word defnitions */ |
c570b2fd WD |
32 | #define SCB_STATUS_CX 0x8000 /* CU finished command (transmit) */ |
33 | #define SCB_STATUS_FR 0x4000 /* frame received */ | |
34 | #define SCB_STATUS_CNA 0x2000 /* CU left active state */ | |
35 | #define SCB_STATUS_RNR 0x1000 /* receiver left ready state */ | |
36 | #define SCB_STATUS_MDI 0x0800 /* MDI read/write cycle done */ | |
37 | #define SCB_STATUS_SWI 0x0400 /* software generated interrupt */ | |
38 | #define SCB_STATUS_FCP 0x0100 /* flow control pause interrupt */ | |
1df49e27 | 39 | |
c570b2fd | 40 | #define SCB_INTACK_MASK 0xFD00 /* all the above */ |
1df49e27 | 41 | |
c570b2fd WD |
42 | #define SCB_INTACK_TX (SCB_STATUS_CX | SCB_STATUS_CNA) |
43 | #define SCB_INTACK_RX (SCB_STATUS_FR | SCB_STATUS_RNR) | |
1df49e27 | 44 | |
aba283d8 | 45 | /* System control block commands */ |
1df49e27 | 46 | /* CU Commands */ |
c570b2fd WD |
47 | #define CU_NOP 0x0000 |
48 | #define CU_START 0x0010 | |
49 | #define CU_RESUME 0x0020 | |
50 | #define CU_STATSADDR 0x0040 /* Load Dump Statistics ctrs addr */ | |
51 | #define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */ | |
52 | #define CU_ADDR_LOAD 0x0060 /* Base address to add to CU commands */ | |
53 | #define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */ | |
1df49e27 WD |
54 | |
55 | /* RUC Commands */ | |
c570b2fd WD |
56 | #define RUC_NOP 0x0000 |
57 | #define RUC_START 0x0001 | |
58 | #define RUC_RESUME 0x0002 | |
59 | #define RUC_ABORT 0x0004 | |
60 | #define RUC_ADDR_LOAD 0x0006 /* (seems not to clear on acceptance) */ | |
61 | #define RUC_RESUMENR 0x0007 | |
62 | ||
63 | #define CU_CMD_MASK 0x00f0 | |
64 | #define RU_CMD_MASK 0x0007 | |
65 | ||
66 | #define SCB_M 0x0100 /* 0 = enable interrupt, 1 = disable */ | |
67 | #define SCB_SWI 0x0200 /* 1 - cause device to interrupt */ | |
68 | ||
69 | #define CU_STATUS_MASK 0x00C0 | |
70 | #define RU_STATUS_MASK 0x003C | |
71 | ||
db9f1818 MV |
72 | #define RU_STATUS_IDLE (0 << 2) |
73 | #define RU_STATUS_SUS (1 << 2) | |
74 | #define RU_STATUS_NORES (2 << 2) | |
75 | #define RU_STATUS_READY (4 << 2) | |
76 | #define RU_STATUS_NO_RBDS_SUS ((1 << 2) | (8 << 2)) | |
77 | #define RU_STATUS_NO_RBDS_NORES ((2 << 2) | (8 << 2)) | |
78 | #define RU_STATUS_NO_RBDS_READY ((4 << 2) | (8 << 2)) | |
1df49e27 | 79 | |
aba283d8 | 80 | /* 82559 Port interface commands. */ |
1df49e27 WD |
81 | #define I82559_RESET 0x00000000 /* Software reset */ |
82 | #define I82559_SELFTEST 0x00000001 /* 82559 Selftest command */ | |
83 | #define I82559_SELECTIVE_RESET 0x00000002 | |
84 | #define I82559_DUMP 0x00000003 | |
85 | #define I82559_DUMP_WAKEUP 0x00000007 | |
86 | ||
aba283d8 | 87 | /* 82559 Eeprom interface. */ |
1df49e27 WD |
88 | #define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ |
89 | #define EE_CS 0x02 /* EEPROM chip select. */ | |
90 | #define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ | |
91 | #define EE_WRITE_0 0x01 | |
92 | #define EE_WRITE_1 0x05 | |
93 | #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ | |
94 | #define EE_ENB (0x4800 | EE_CS) | |
95 | #define EE_CMD_BITS 3 | |
96 | #define EE_DATA_BITS 16 | |
97 | ||
aba283d8 | 98 | /* The EEPROM commands include the alway-set leading bit. */ |
a6c06ec8 MV |
99 | #define EE_EWENB_CMD(addr_len) (4 << (addr_len)) |
100 | #define EE_WRITE_CMD(addr_len) (5 << (addr_len)) | |
101 | #define EE_READ_CMD(addr_len) (6 << (addr_len)) | |
102 | #define EE_ERASE_CMD(addr_len) (7 << (addr_len)) | |
1df49e27 | 103 | |
aba283d8 | 104 | /* Receive frame descriptors. */ |
f3878f5c | 105 | struct eepro100_rxfd { |
d47cf87d MV |
106 | u16 status; |
107 | u16 control; | |
108 | u32 link; /* struct eepro100_rxfd * */ | |
109 | u32 rx_buf_addr; /* void * */ | |
110 | u32 count; | |
1df49e27 | 111 | |
d47cf87d | 112 | u8 data[PKTSIZE_ALIGN]; |
1df49e27 WD |
113 | }; |
114 | ||
115 | #define RFD_STATUS_C 0x8000 /* completion of received frame */ | |
c570b2fd WD |
116 | #define RFD_STATUS_OK 0x2000 /* frame received with no errors */ |
117 | ||
118 | #define RFD_CONTROL_EL 0x8000 /* 1=last RFD in RFA */ | |
119 | #define RFD_CONTROL_S 0x4000 /* 1=suspend RU after receiving frame */ | |
120 | #define RFD_CONTROL_H 0x0010 /* 1=RFD is a header RFD */ | |
121 | #define RFD_CONTROL_SF 0x0008 /* 0=simplified, 1=flexible mode */ | |
122 | ||
123 | #define RFD_COUNT_MASK 0x3fff | |
124 | #define RFD_COUNT_F 0x4000 | |
125 | #define RFD_COUNT_EOF 0x8000 | |
126 | ||
127 | #define RFD_RX_CRC 0x0800 /* crc error */ | |
128 | #define RFD_RX_ALIGNMENT 0x0400 /* alignment error */ | |
129 | #define RFD_RX_RESOURCE 0x0200 /* out of space, no resources */ | |
130 | #define RFD_RX_DMA_OVER 0x0100 /* DMA overrun */ | |
131 | #define RFD_RX_SHORT 0x0080 /* short frame error */ | |
132 | #define RFD_RX_LENGTH 0x0020 | |
133 | #define RFD_RX_ERROR 0x0010 /* receive error */ | |
134 | #define RFD_RX_NO_ADR_MATCH 0x0004 /* no address match */ | |
135 | #define RFD_RX_IA_MATCH 0x0002 /* individual address does not match */ | |
136 | #define RFD_RX_TCO 0x0001 /* TCO indication */ | |
1df49e27 | 137 | |
aba283d8 | 138 | /* Transmit frame descriptors */ |
d47cf87d MV |
139 | struct eepro100_txfd { /* Transmit frame descriptor set. */ |
140 | u16 status; | |
141 | u16 command; | |
142 | u32 link; /* void * */ | |
143 | u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ | |
144 | s32 count; | |
145 | ||
146 | u32 tx_buf_addr0; /* void *, frame to be transmitted. */ | |
147 | s32 tx_buf_size0; /* Length of Tx frame. */ | |
148 | u32 tx_buf_addr1; /* void *, frame to be transmitted. */ | |
149 | s32 tx_buf_size1; /* Length of Tx frame. */ | |
1df49e27 WD |
150 | }; |
151 | ||
f3878f5c MV |
152 | #define TXCB_CMD_TRANSMIT 0x0004 /* transmit command */ |
153 | #define TXCB_CMD_SF 0x0008 /* 0=simplified, 1=flexible mode */ | |
154 | #define TXCB_CMD_NC 0x0010 /* 0=CRC insert by controller */ | |
155 | #define TXCB_CMD_I 0x2000 /* generate interrupt on completion */ | |
156 | #define TXCB_CMD_S 0x4000 /* suspend on completion */ | |
157 | #define TXCB_CMD_EL 0x8000 /* last command block in CBL */ | |
1df49e27 | 158 | |
f3878f5c MV |
159 | #define TXCB_COUNT_MASK 0x3fff |
160 | #define TXCB_COUNT_EOF 0x8000 | |
1df49e27 | 161 | |
aba283d8 | 162 | /* The Speedo3 Rx and Tx frame/buffer descriptors. */ |
d47cf87d MV |
163 | struct descriptor { /* A generic descriptor. */ |
164 | u16 status; | |
165 | u16 command; | |
166 | u32 link; /* struct descriptor * */ | |
1df49e27 WD |
167 | |
168 | unsigned char params[0]; | |
169 | }; | |
170 | ||
6e7df1d1 TR |
171 | #define CFG_SYS_CMD_SUSPEND 0x4000 |
172 | #define CFG_SYS_CMD_IAS 0x0001 /* individual address setup */ | |
173 | #define CFG_SYS_CMD_CONFIGURE 0x0002 /* configure */ | |
1df49e27 | 174 | |
6e7df1d1 TR |
175 | #define CFG_SYS_STATUS_C 0x8000 |
176 | #define CFG_SYS_STATUS_OK 0x2000 | |
1df49e27 | 177 | |
aba283d8 | 178 | /* Misc. */ |
c570b2fd | 179 | #define NUM_RX_DESC PKTBUFSRX |
aba283d8 | 180 | #define NUM_TX_DESC 1 /* Number of TX descriptors */ |
1df49e27 WD |
181 | |
182 | #define TOUT_LOOP 1000000 | |
183 | ||
1df49e27 WD |
184 | /* |
185 | * The parameters for a CmdConfigure operation. | |
186 | * There are so many options that it would be difficult to document | |
187 | * each bit. We mostly use the default or recommended settings. | |
188 | */ | |
1df49e27 WD |
189 | static const char i82558_config_cmd[] = { |
190 | 22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */ | |
191 | 0, 0x2E, 0, 0x60, 0x08, 0x88, | |
192 | 0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */ | |
193 | 0x31, 0x05, | |
194 | }; | |
195 | ||
bd159c61 | 196 | struct eepro100_priv { |
fb8307e5 MV |
197 | /* RX descriptor ring */ |
198 | struct eepro100_rxfd rx_ring[NUM_RX_DESC]; | |
199 | /* TX descriptor ring */ | |
200 | struct eepro100_txfd tx_ring[NUM_TX_DESC]; | |
201 | /* RX descriptor ring pointer */ | |
202 | int rx_next; | |
8835103e | 203 | u16 rx_stat; |
fb8307e5 MV |
204 | /* TX descriptor ring pointer */ |
205 | int tx_next; | |
206 | int tx_threshold; | |
af8ecdf7 | 207 | struct udevice *devno; |
389da974 MV |
208 | char *name; |
209 | void __iomem *iobase; | |
210 | u8 *enetaddr; | |
bd159c61 MV |
211 | }; |
212 | ||
af8ecdf7 MV |
213 | #define bus_to_phys(dev, a) dm_pci_mem_to_phys((dev), (a)) |
214 | #define phys_to_bus(dev, a) dm_pci_phys_to_mem((dev), (a)) | |
1df49e27 | 215 | |
389da974 | 216 | static int INW(struct eepro100_priv *priv, u_long addr) |
1df49e27 | 217 | { |
389da974 | 218 | return le16_to_cpu(readw(addr + priv->iobase)); |
1df49e27 WD |
219 | } |
220 | ||
389da974 | 221 | static void OUTW(struct eepro100_priv *priv, int command, u_long addr) |
1df49e27 | 222 | { |
389da974 | 223 | writew(cpu_to_le16(command), addr + priv->iobase); |
1df49e27 WD |
224 | } |
225 | ||
389da974 | 226 | static void OUTL(struct eepro100_priv *priv, int command, u_long addr) |
1df49e27 | 227 | { |
389da974 | 228 | writel(cpu_to_le32(command), addr + priv->iobase); |
1df49e27 WD |
229 | } |
230 | ||
07d38a17 | 231 | #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) |
389da974 | 232 | static int INL(struct eepro100_priv *priv, u_long addr) |
a912733e | 233 | { |
389da974 | 234 | return le32_to_cpu(readl(addr + priv->iobase)); |
a912733e WD |
235 | } |
236 | ||
389da974 | 237 | static int get_phyreg(struct eepro100_priv *priv, unsigned char addr, |
773af836 | 238 | unsigned char reg, unsigned short *value) |
a912733e | 239 | { |
63ff004c | 240 | int timeout = 50; |
389da974 | 241 | int cmd; |
a912733e | 242 | |
63ff004c MB |
243 | /* read requested data */ |
244 | cmd = (2 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16); | |
389da974 | 245 | OUTL(priv, cmd, SCB_CTRL_MDI); |
c570b2fd | 246 | |
a912733e | 247 | do { |
63ff004c | 248 | udelay(1000); |
389da974 | 249 | cmd = INL(priv, SCB_CTRL_MDI); |
63ff004c MB |
250 | } while (!(cmd & (1 << 28)) && (--timeout)); |
251 | ||
252 | if (timeout == 0) | |
253 | return -1; | |
a912733e | 254 | |
db9f1818 | 255 | *value = (unsigned short)(cmd & 0xffff); |
c570b2fd | 256 | |
a912733e WD |
257 | return 0; |
258 | } | |
259 | ||
389da974 | 260 | static int set_phyreg(struct eepro100_priv *priv, unsigned char addr, |
773af836 | 261 | unsigned char reg, unsigned short value) |
a912733e | 262 | { |
63ff004c | 263 | int timeout = 50; |
389da974 | 264 | int cmd; |
a912733e | 265 | |
63ff004c MB |
266 | /* write requested data */ |
267 | cmd = (1 << 26) | ((addr & 0x1f) << 21) | ((reg & 0x1f) << 16); | |
389da974 | 268 | OUTL(priv, cmd | value, SCB_CTRL_MDI); |
a912733e | 269 | |
389da974 | 270 | while (!(INL(priv, SCB_CTRL_MDI) & (1 << 28)) && (--timeout)) |
63ff004c MB |
271 | udelay(1000); |
272 | ||
273 | if (timeout == 0) | |
274 | return -1; | |
a912733e WD |
275 | |
276 | return 0; | |
277 | } | |
a912733e | 278 | |
aba283d8 MV |
279 | /* |
280 | * Check if given phyaddr is valid, i.e. there is a PHY connected. | |
63ff004c MB |
281 | * Do this by checking model value field from ID2 register. |
282 | */ | |
389da974 | 283 | static int verify_phyaddr(struct eepro100_priv *priv, unsigned char addr) |
63ff004c | 284 | { |
389da974 MV |
285 | unsigned short value, model; |
286 | int ret; | |
63ff004c MB |
287 | |
288 | /* read id2 register */ | |
389da974 MV |
289 | ret = get_phyreg(priv, addr, MII_PHYSID2, &value); |
290 | if (ret) { | |
291 | printf("%s: mii read timeout!\n", priv->name); | |
292 | return ret; | |
63ff004c MB |
293 | } |
294 | ||
295 | /* get model */ | |
389da974 MV |
296 | model = (value >> 4) & 0x003f; |
297 | if (!model) { | |
298 | printf("%s: no PHY at address %d\n", priv->name, addr); | |
299 | return -EINVAL; | |
63ff004c MB |
300 | } |
301 | ||
389da974 | 302 | return 0; |
63ff004c MB |
303 | } |
304 | ||
5a49f174 JH |
305 | static int eepro100_miiphy_read(struct mii_dev *bus, int addr, int devad, |
306 | int reg) | |
63ff004c | 307 | { |
39daab23 | 308 | struct eepro100_priv *priv = bus->priv; |
5a49f174 | 309 | unsigned short value = 0; |
389da974 | 310 | int ret; |
63ff004c | 311 | |
389da974 MV |
312 | ret = verify_phyaddr(priv, addr); |
313 | if (ret) | |
314 | return ret; | |
63ff004c | 315 | |
389da974 MV |
316 | ret = get_phyreg(priv, addr, reg, &value); |
317 | if (ret) { | |
5a49f174 | 318 | printf("%s: mii read timeout!\n", bus->name); |
389da974 | 319 | return ret; |
63ff004c MB |
320 | } |
321 | ||
5a49f174 | 322 | return value; |
63ff004c MB |
323 | } |
324 | ||
5a49f174 JH |
325 | static int eepro100_miiphy_write(struct mii_dev *bus, int addr, int devad, |
326 | int reg, u16 value) | |
63ff004c | 327 | { |
39daab23 | 328 | struct eepro100_priv *priv = bus->priv; |
389da974 | 329 | int ret; |
63ff004c | 330 | |
389da974 MV |
331 | ret = verify_phyaddr(priv, addr); |
332 | if (ret) | |
333 | return ret; | |
63ff004c | 334 | |
389da974 MV |
335 | ret = set_phyreg(priv, addr, reg, value); |
336 | if (ret) { | |
5a49f174 | 337 | printf("%s: mii write timeout!\n", bus->name); |
389da974 | 338 | return ret; |
63ff004c MB |
339 | } |
340 | ||
341 | return 0; | |
342 | } | |
07d38a17 | 343 | #endif |
63ff004c | 344 | |
389da974 | 345 | static void init_rx_ring(struct eepro100_priv *priv) |
1df49e27 | 346 | { |
fb8307e5 | 347 | struct eepro100_rxfd *rx_ring = priv->rx_ring; |
1df49e27 WD |
348 | int i; |
349 | ||
047a800d MV |
350 | for (i = 0; i < NUM_RX_DESC; i++) { |
351 | rx_ring[i].status = 0; | |
352 | rx_ring[i].control = (i == NUM_RX_DESC - 1) ? | |
353 | cpu_to_le16 (RFD_CONTROL_S) : 0; | |
354 | rx_ring[i].link = | |
389da974 | 355 | cpu_to_le32(phys_to_bus(priv->devno, |
fa9e1210 | 356 | (u32)&rx_ring[(i + 1) % |
047a800d MV |
357 | NUM_RX_DESC])); |
358 | rx_ring[i].rx_buf_addr = 0xffffffff; | |
359 | rx_ring[i].count = cpu_to_le32(PKTSIZE_ALIGN << 16); | |
1df49e27 WD |
360 | } |
361 | ||
047a800d MV |
362 | flush_dcache_range((unsigned long)rx_ring, |
363 | (unsigned long)rx_ring + | |
364 | (sizeof(*rx_ring) * NUM_RX_DESC)); | |
1df49e27 | 365 | |
fb8307e5 | 366 | priv->rx_next = 0; |
047a800d | 367 | } |
1df49e27 | 368 | |
389da974 | 369 | static void purge_tx_ring(struct eepro100_priv *priv) |
1df49e27 | 370 | { |
fb8307e5 MV |
371 | struct eepro100_txfd *tx_ring = priv->tx_ring; |
372 | ||
373 | priv->tx_next = 0; | |
374 | priv->tx_threshold = 0x01208000; | |
047a800d | 375 | memset(tx_ring, 0, sizeof(*tx_ring) * NUM_TX_DESC); |
1df49e27 | 376 | |
047a800d MV |
377 | flush_dcache_range((unsigned long)tx_ring, |
378 | (unsigned long)tx_ring + | |
379 | (sizeof(*tx_ring) * NUM_TX_DESC)); | |
380 | } | |
1df49e27 | 381 | |
047a800d | 382 | /* Wait for the chip get the command. */ |
389da974 | 383 | static int wait_for_eepro100(struct eepro100_priv *priv) |
047a800d MV |
384 | { |
385 | int i; | |
1df49e27 | 386 | |
389da974 | 387 | for (i = 0; INW(priv, SCB_CMD) & (CU_CMD_MASK | RU_CMD_MASK); i++) { |
047a800d MV |
388 | if (i >= TOUT_LOOP) |
389 | return 0; | |
1df49e27 WD |
390 | } |
391 | ||
047a800d | 392 | return 1; |
1df49e27 WD |
393 | } |
394 | ||
389da974 | 395 | static int eepro100_txcmd_send(struct eepro100_priv *priv, |
95655b92 MV |
396 | struct eepro100_txfd *desc) |
397 | { | |
398 | u16 rstat; | |
399 | int i = 0; | |
400 | ||
5116aae1 MV |
401 | flush_dcache_range((unsigned long)desc, |
402 | (unsigned long)desc + sizeof(*desc)); | |
403 | ||
389da974 | 404 | if (!wait_for_eepro100(priv)) |
95655b92 MV |
405 | return -ETIMEDOUT; |
406 | ||
389da974 MV |
407 | OUTL(priv, phys_to_bus(priv->devno, (u32)desc), SCB_POINTER); |
408 | OUTW(priv, SCB_M | CU_START, SCB_CMD); | |
95655b92 MV |
409 | |
410 | while (true) { | |
5116aae1 MV |
411 | invalidate_dcache_range((unsigned long)desc, |
412 | (unsigned long)desc + sizeof(*desc)); | |
95655b92 | 413 | rstat = le16_to_cpu(desc->status); |
6e7df1d1 | 414 | if (rstat & CFG_SYS_STATUS_C) |
95655b92 MV |
415 | break; |
416 | ||
417 | if (i++ >= TOUT_LOOP) { | |
389da974 | 418 | printf("%s: Tx error buffer not ready\n", priv->name); |
95655b92 MV |
419 | return -EINVAL; |
420 | } | |
421 | } | |
422 | ||
5116aae1 MV |
423 | invalidate_dcache_range((unsigned long)desc, |
424 | (unsigned long)desc + sizeof(*desc)); | |
95655b92 MV |
425 | rstat = le16_to_cpu(desc->status); |
426 | ||
6e7df1d1 | 427 | if (!(rstat & CFG_SYS_STATUS_OK)) { |
95655b92 MV |
428 | printf("TX error status = 0x%08X\n", rstat); |
429 | return -EIO; | |
430 | } | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
047a800d | 435 | /* SROM Read. */ |
389da974 | 436 | static int read_eeprom(struct eepro100_priv *priv, int location, int addr_len) |
047a800d MV |
437 | { |
438 | unsigned short retval = 0; | |
a6c06ec8 | 439 | int read_cmd = location | EE_READ_CMD(addr_len); |
047a800d MV |
440 | int i; |
441 | ||
389da974 MV |
442 | OUTW(priv, EE_ENB & ~EE_CS, SCB_EEPROM); |
443 | OUTW(priv, EE_ENB, SCB_EEPROM); | |
047a800d MV |
444 | |
445 | /* Shift the read command bits out. */ | |
446 | for (i = 12; i >= 0; i--) { | |
447 | short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; | |
448 | ||
389da974 | 449 | OUTW(priv, EE_ENB | dataval, SCB_EEPROM); |
047a800d | 450 | udelay(1); |
389da974 | 451 | OUTW(priv, EE_ENB | dataval | EE_SHIFT_CLK, SCB_EEPROM); |
047a800d MV |
452 | udelay(1); |
453 | } | |
389da974 | 454 | OUTW(priv, EE_ENB, SCB_EEPROM); |
047a800d MV |
455 | |
456 | for (i = 15; i >= 0; i--) { | |
389da974 | 457 | OUTW(priv, EE_ENB | EE_SHIFT_CLK, SCB_EEPROM); |
047a800d MV |
458 | udelay(1); |
459 | retval = (retval << 1) | | |
389da974 MV |
460 | !!(INW(priv, SCB_EEPROM) & EE_DATA_READ); |
461 | OUTW(priv, EE_ENB, SCB_EEPROM); | |
047a800d MV |
462 | udelay(1); |
463 | } | |
464 | ||
465 | /* Terminate the EEPROM access. */ | |
389da974 | 466 | OUTW(priv, EE_ENB & ~EE_CS, SCB_EEPROM); |
047a800d MV |
467 | return retval; |
468 | } | |
469 | ||
66fed730 | 470 | #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) |
389da974 | 471 | static int eepro100_initialize_mii(struct eepro100_priv *priv) |
66fed730 MV |
472 | { |
473 | /* register mii command access routines */ | |
474 | struct mii_dev *mdiodev; | |
475 | int ret; | |
476 | ||
477 | mdiodev = mdio_alloc(); | |
478 | if (!mdiodev) | |
479 | return -ENOMEM; | |
480 | ||
e7444a19 | 481 | strlcpy(mdiodev->name, priv->name, MDIO_NAME_LEN); |
66fed730 MV |
482 | mdiodev->read = eepro100_miiphy_read; |
483 | mdiodev->write = eepro100_miiphy_write; | |
39daab23 | 484 | mdiodev->priv = priv; |
66fed730 MV |
485 | |
486 | ret = mdio_register(mdiodev); | |
487 | if (ret < 0) { | |
488 | mdio_free(mdiodev); | |
489 | return ret; | |
490 | } | |
491 | ||
492 | return 0; | |
493 | } | |
494 | #else | |
389da974 | 495 | static int eepro100_initialize_mii(struct eepro100_priv *priv) |
66fed730 MV |
496 | { |
497 | return 0; | |
498 | } | |
499 | #endif | |
500 | ||
047a800d | 501 | static struct pci_device_id supported[] = { |
3a15684d MV |
502 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557) }, |
503 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559) }, | |
504 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER) }, | |
505 | { } | |
047a800d MV |
506 | }; |
507 | ||
43b73835 | 508 | static void eepro100_get_hwaddr(struct eepro100_priv *priv) |
047a800d MV |
509 | { |
510 | u16 sum = 0; | |
511 | int i, j; | |
389da974 | 512 | int addr_len = read_eeprom(priv, 0, 6) == 0xffff ? 8 : 6; |
047a800d MV |
513 | |
514 | for (j = 0, i = 0; i < 0x40; i++) { | |
389da974 | 515 | u16 value = read_eeprom(priv, i, addr_len); |
047a800d MV |
516 | |
517 | sum += value; | |
518 | if (i < 3) { | |
389da974 MV |
519 | priv->enetaddr[j++] = value; |
520 | priv->enetaddr[j++] = value >> 8; | |
047a800d MV |
521 | } |
522 | } | |
523 | ||
524 | if (sum != 0xBABA) { | |
389da974 | 525 | memset(priv->enetaddr, 0, ETH_ALEN); |
047a800d | 526 | debug("%s: Invalid EEPROM checksum %#4.4x, check settings before activating this device!\n", |
389da974 | 527 | priv->name, sum); |
047a800d MV |
528 | } |
529 | } | |
530 | ||
8835103e | 531 | static int eepro100_init_common(struct eepro100_priv *priv) |
1df49e27 | 532 | { |
fb8307e5 MV |
533 | struct eepro100_rxfd *rx_ring = priv->rx_ring; |
534 | struct eepro100_txfd *tx_ring = priv->tx_ring; | |
95655b92 MV |
535 | struct eepro100_txfd *ias_cmd, *cfg_cmd; |
536 | int ret, status = -1; | |
1df49e27 | 537 | int tx_cur; |
1df49e27 | 538 | |
aba283d8 | 539 | /* Reset the ethernet controller */ |
389da974 | 540 | OUTL(priv, I82559_SELECTIVE_RESET, SCB_PORT); |
07e11146 | 541 | udelay(20); |
1df49e27 | 542 | |
389da974 | 543 | OUTL(priv, I82559_RESET, SCB_PORT); |
07e11146 | 544 | udelay(20); |
1df49e27 | 545 | |
389da974 | 546 | if (!wait_for_eepro100(priv)) { |
db9f1818 | 547 | printf("Error: Can not reset ethernet controller.\n"); |
f3878f5c | 548 | goto done; |
1df49e27 | 549 | } |
389da974 MV |
550 | OUTL(priv, 0, SCB_POINTER); |
551 | OUTW(priv, SCB_M | RUC_ADDR_LOAD, SCB_CMD); | |
1df49e27 | 552 | |
389da974 | 553 | if (!wait_for_eepro100(priv)) { |
db9f1818 | 554 | printf("Error: Can not reset ethernet controller.\n"); |
f3878f5c | 555 | goto done; |
1df49e27 | 556 | } |
389da974 MV |
557 | OUTL(priv, 0, SCB_POINTER); |
558 | OUTW(priv, SCB_M | CU_ADDR_LOAD, SCB_CMD); | |
1df49e27 | 559 | |
aba283d8 | 560 | /* Initialize Rx and Tx rings. */ |
389da974 MV |
561 | init_rx_ring(priv); |
562 | purge_tx_ring(priv); | |
1df49e27 | 563 | |
aba283d8 | 564 | /* Tell the adapter where the RX ring is located. */ |
389da974 | 565 | if (!wait_for_eepro100(priv)) { |
db9f1818 | 566 | printf("Error: Can not reset ethernet controller.\n"); |
f3878f5c | 567 | goto done; |
1df49e27 WD |
568 | } |
569 | ||
5116aae1 | 570 | /* RX ring cache was already flushed in init_rx_ring() */ |
fb8307e5 | 571 | OUTL(priv, phys_to_bus(priv->devno, (u32)&rx_ring[priv->rx_next]), |
fa9e1210 | 572 | SCB_POINTER); |
389da974 | 573 | OUTW(priv, SCB_M | RUC_START, SCB_CMD); |
1df49e27 WD |
574 | |
575 | /* Send the Configure frame */ | |
fb8307e5 MV |
576 | tx_cur = priv->tx_next; |
577 | priv->tx_next = ((priv->tx_next + 1) % NUM_TX_DESC); | |
1df49e27 | 578 | |
95655b92 | 579 | cfg_cmd = &tx_ring[tx_cur]; |
6e7df1d1 TR |
580 | cfg_cmd->command = cpu_to_le16(CFG_SYS_CMD_SUSPEND | |
581 | CFG_SYS_CMD_CONFIGURE); | |
1df49e27 | 582 | cfg_cmd->status = 0; |
389da974 | 583 | cfg_cmd->link = cpu_to_le32(phys_to_bus(priv->devno, |
fb8307e5 | 584 | (u32)&tx_ring[priv->tx_next])); |
1df49e27 | 585 | |
95655b92 | 586 | memcpy(((struct descriptor *)cfg_cmd)->params, i82558_config_cmd, |
773af836 | 587 | sizeof(i82558_config_cmd)); |
1df49e27 | 588 | |
389da974 | 589 | ret = eepro100_txcmd_send(priv, cfg_cmd); |
95655b92 MV |
590 | if (ret) { |
591 | if (ret == -ETIMEDOUT) | |
6e7df1d1 | 592 | printf("Error---CFG_SYS_CMD_CONFIGURE: Can not reset ethernet controller.\n"); |
f3878f5c | 593 | goto done; |
1df49e27 WD |
594 | } |
595 | ||
aba283d8 | 596 | /* Send the Individual Address Setup frame */ |
fb8307e5 MV |
597 | tx_cur = priv->tx_next; |
598 | priv->tx_next = ((priv->tx_next + 1) % NUM_TX_DESC); | |
1df49e27 | 599 | |
95655b92 | 600 | ias_cmd = &tx_ring[tx_cur]; |
6e7df1d1 TR |
601 | ias_cmd->command = cpu_to_le16(CFG_SYS_CMD_SUSPEND | |
602 | CFG_SYS_CMD_IAS); | |
1df49e27 | 603 | ias_cmd->status = 0; |
389da974 | 604 | ias_cmd->link = cpu_to_le32(phys_to_bus(priv->devno, |
fb8307e5 | 605 | (u32)&tx_ring[priv->tx_next])); |
1df49e27 | 606 | |
389da974 | 607 | memcpy(((struct descriptor *)ias_cmd)->params, priv->enetaddr, 6); |
1df49e27 | 608 | |
389da974 | 609 | ret = eepro100_txcmd_send(priv, ias_cmd); |
95655b92 MV |
610 | if (ret) { |
611 | if (ret == -ETIMEDOUT) | |
612 | printf("Error: Can not reset ethernet controller.\n"); | |
f3878f5c | 613 | goto done; |
1df49e27 WD |
614 | } |
615 | ||
422b1a01 | 616 | status = 0; |
1df49e27 | 617 | |
f3878f5c | 618 | done: |
1df49e27 WD |
619 | return status; |
620 | } | |
621 | ||
8835103e MV |
622 | static int eepro100_send_common(struct eepro100_priv *priv, |
623 | void *packet, int length) | |
1df49e27 | 624 | { |
fb8307e5 | 625 | struct eepro100_txfd *tx_ring = priv->tx_ring; |
5116aae1 | 626 | struct eepro100_txfd *desc; |
95655b92 | 627 | int ret, status = -1; |
1df49e27 WD |
628 | int tx_cur; |
629 | ||
630 | if (length <= 0) { | |
389da974 | 631 | printf("%s: bad packet size: %d\n", priv->name, length); |
f3878f5c | 632 | goto done; |
1df49e27 WD |
633 | } |
634 | ||
fb8307e5 MV |
635 | tx_cur = priv->tx_next; |
636 | priv->tx_next = (priv->tx_next + 1) % NUM_TX_DESC; | |
1df49e27 | 637 | |
5116aae1 MV |
638 | desc = &tx_ring[tx_cur]; |
639 | desc->command = cpu_to_le16(TXCB_CMD_TRANSMIT | TXCB_CMD_SF | | |
640 | TXCB_CMD_S | TXCB_CMD_EL); | |
641 | desc->status = 0; | |
fb8307e5 | 642 | desc->count = cpu_to_le32(priv->tx_threshold); |
389da974 | 643 | desc->link = cpu_to_le32(phys_to_bus(priv->devno, |
fb8307e5 | 644 | (u32)&tx_ring[priv->tx_next])); |
389da974 | 645 | desc->tx_desc_addr = cpu_to_le32(phys_to_bus(priv->devno, |
fa9e1210 | 646 | (u32)&desc->tx_buf_addr0)); |
389da974 | 647 | desc->tx_buf_addr0 = cpu_to_le32(phys_to_bus(priv->devno, |
fa9e1210 | 648 | (u_long)packet)); |
5116aae1 | 649 | desc->tx_buf_size0 = cpu_to_le32(length); |
1df49e27 | 650 | |
389da974 | 651 | ret = eepro100_txcmd_send(priv, &tx_ring[tx_cur]); |
95655b92 MV |
652 | if (ret) { |
653 | if (ret == -ETIMEDOUT) | |
654 | printf("%s: Tx error ethernet controller not ready.\n", | |
389da974 | 655 | priv->name); |
f3878f5c | 656 | goto done; |
1df49e27 WD |
657 | } |
658 | ||
659 | status = length; | |
660 | ||
f3878f5c | 661 | done: |
1df49e27 WD |
662 | return status; |
663 | } | |
664 | ||
8835103e | 665 | static int eepro100_recv_common(struct eepro100_priv *priv, uchar **packetp) |
1df49e27 | 666 | { |
fb8307e5 | 667 | struct eepro100_rxfd *rx_ring = priv->rx_ring; |
5116aae1 | 668 | struct eepro100_rxfd *desc; |
8835103e MV |
669 | int length; |
670 | u16 status; | |
1df49e27 | 671 | |
8835103e MV |
672 | priv->rx_stat = INW(priv, SCB_STATUS); |
673 | OUTW(priv, priv->rx_stat & SCB_STATUS_RNR, SCB_STATUS); | |
1df49e27 | 674 | |
8835103e MV |
675 | desc = &rx_ring[priv->rx_next]; |
676 | invalidate_dcache_range((unsigned long)desc, | |
677 | (unsigned long)desc + sizeof(*desc)); | |
678 | status = le16_to_cpu(desc->status); | |
679 | ||
680 | if (!(status & RFD_STATUS_C)) | |
681 | return 0; | |
682 | ||
683 | /* Valid frame status. */ | |
684 | if (status & RFD_STATUS_OK) { | |
685 | /* A valid frame received. */ | |
686 | length = le32_to_cpu(desc->count) & 0x3fff; | |
687 | /* Pass the packet up to the protocol layers. */ | |
688 | *packetp = desc->data; | |
689 | return length; | |
690 | } | |
1df49e27 | 691 | |
8835103e MV |
692 | /* There was an error. */ |
693 | printf("RX error status = 0x%08X\n", status); | |
694 | return -EINVAL; | |
695 | } | |
1df49e27 | 696 | |
8835103e MV |
697 | static void eepro100_free_pkt_common(struct eepro100_priv *priv) |
698 | { | |
699 | struct eepro100_rxfd *rx_ring = priv->rx_ring; | |
700 | struct eepro100_rxfd *desc; | |
701 | int rx_prev; | |
1df49e27 | 702 | |
8835103e | 703 | desc = &rx_ring[priv->rx_next]; |
1df49e27 | 704 | |
8835103e MV |
705 | desc->control = cpu_to_le16(RFD_CONTROL_S); |
706 | desc->status = 0; | |
707 | desc->count = cpu_to_le32(PKTSIZE_ALIGN << 16); | |
708 | flush_dcache_range((unsigned long)desc, | |
709 | (unsigned long)desc + sizeof(*desc)); | |
1df49e27 | 710 | |
8835103e MV |
711 | rx_prev = (priv->rx_next + NUM_RX_DESC - 1) % NUM_RX_DESC; |
712 | desc = &rx_ring[rx_prev]; | |
713 | desc->control = 0; | |
714 | flush_dcache_range((unsigned long)desc, | |
715 | (unsigned long)desc + sizeof(*desc)); | |
1df49e27 | 716 | |
8835103e MV |
717 | /* Update entry information. */ |
718 | priv->rx_next = (priv->rx_next + 1) % NUM_RX_DESC; | |
1df49e27 | 719 | |
8835103e MV |
720 | if (!(priv->rx_stat & SCB_STATUS_RNR)) |
721 | return; | |
1df49e27 | 722 | |
8835103e | 723 | printf("%s: Receiver is not ready, restart it !\n", priv->name); |
1df49e27 | 724 | |
8835103e MV |
725 | /* Reinitialize Rx ring. */ |
726 | init_rx_ring(priv); | |
1df49e27 | 727 | |
8835103e MV |
728 | if (!wait_for_eepro100(priv)) { |
729 | printf("Error: Can not restart ethernet controller.\n"); | |
730 | return; | |
1df49e27 WD |
731 | } |
732 | ||
8835103e MV |
733 | /* RX ring cache was already flushed in init_rx_ring() */ |
734 | OUTL(priv, phys_to_bus(priv->devno, (u32)&rx_ring[priv->rx_next]), | |
735 | SCB_POINTER); | |
736 | OUTW(priv, SCB_M | RUC_START, SCB_CMD); | |
1df49e27 WD |
737 | } |
738 | ||
8835103e | 739 | static void eepro100_halt_common(struct eepro100_priv *priv) |
1df49e27 | 740 | { |
aba283d8 | 741 | /* Reset the ethernet controller */ |
389da974 | 742 | OUTL(priv, I82559_SELECTIVE_RESET, SCB_PORT); |
07e11146 | 743 | udelay(20); |
1df49e27 | 744 | |
389da974 | 745 | OUTL(priv, I82559_RESET, SCB_PORT); |
07e11146 | 746 | udelay(20); |
1df49e27 | 747 | |
389da974 | 748 | if (!wait_for_eepro100(priv)) { |
db9f1818 | 749 | printf("Error: Can not reset ethernet controller.\n"); |
f3878f5c | 750 | goto done; |
1df49e27 | 751 | } |
389da974 MV |
752 | OUTL(priv, 0, SCB_POINTER); |
753 | OUTW(priv, SCB_M | RUC_ADDR_LOAD, SCB_CMD); | |
1df49e27 | 754 | |
389da974 | 755 | if (!wait_for_eepro100(priv)) { |
db9f1818 | 756 | printf("Error: Can not reset ethernet controller.\n"); |
f3878f5c | 757 | goto done; |
1df49e27 | 758 | } |
389da974 MV |
759 | OUTL(priv, 0, SCB_POINTER); |
760 | OUTW(priv, SCB_M | CU_ADDR_LOAD, SCB_CMD); | |
1df49e27 | 761 | |
f3878f5c | 762 | done: |
1df49e27 WD |
763 | return; |
764 | } | |
765 | ||
af8ecdf7 MV |
766 | static int eepro100_start(struct udevice *dev) |
767 | { | |
c69cda25 | 768 | struct eth_pdata *plat = dev_get_plat(dev); |
af8ecdf7 MV |
769 | struct eepro100_priv *priv = dev_get_priv(dev); |
770 | ||
771 | memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr)); | |
772 | ||
773 | return eepro100_init_common(priv); | |
774 | } | |
775 | ||
776 | static void eepro100_stop(struct udevice *dev) | |
777 | { | |
778 | struct eepro100_priv *priv = dev_get_priv(dev); | |
779 | ||
780 | eepro100_halt_common(priv); | |
781 | } | |
782 | ||
783 | static int eepro100_send(struct udevice *dev, void *packet, int length) | |
784 | { | |
785 | struct eepro100_priv *priv = dev_get_priv(dev); | |
786 | int ret; | |
787 | ||
788 | ret = eepro100_send_common(priv, packet, length); | |
789 | ||
790 | return ret ? 0 : -ETIMEDOUT; | |
791 | } | |
792 | ||
793 | static int eepro100_recv(struct udevice *dev, int flags, uchar **packetp) | |
794 | { | |
795 | struct eepro100_priv *priv = dev_get_priv(dev); | |
796 | ||
797 | return eepro100_recv_common(priv, packetp); | |
798 | } | |
799 | ||
800 | static int eepro100_free_pkt(struct udevice *dev, uchar *packet, int length) | |
801 | { | |
802 | struct eepro100_priv *priv = dev_get_priv(dev); | |
803 | ||
804 | eepro100_free_pkt_common(priv); | |
805 | ||
806 | return 0; | |
807 | } | |
808 | ||
809 | static int eepro100_read_rom_hwaddr(struct udevice *dev) | |
810 | { | |
811 | struct eepro100_priv *priv = dev_get_priv(dev); | |
812 | ||
813 | eepro100_get_hwaddr(priv); | |
814 | ||
815 | return 0; | |
816 | } | |
817 | ||
818 | static int eepro100_bind(struct udevice *dev) | |
819 | { | |
820 | static int card_number; | |
821 | char name[16]; | |
822 | ||
823 | sprintf(name, "eepro100#%u", card_number++); | |
824 | ||
825 | return device_set_name(dev, name); | |
826 | } | |
827 | ||
828 | static int eepro100_probe(struct udevice *dev) | |
829 | { | |
c69cda25 | 830 | struct eth_pdata *plat = dev_get_plat(dev); |
af8ecdf7 MV |
831 | struct eepro100_priv *priv = dev_get_priv(dev); |
832 | u16 command, status; | |
833 | u32 iobase; | |
834 | int ret; | |
835 | ||
836 | dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase); | |
837 | iobase &= ~0xf; | |
838 | ||
839 | debug("eepro100: Intel i82559 PCI EtherExpressPro @0x%x\n", iobase); | |
840 | ||
841 | priv->devno = dev; | |
842 | priv->enetaddr = plat->enetaddr; | |
843 | priv->iobase = (void __iomem *)bus_to_phys(dev, iobase); | |
844 | ||
845 | command = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; | |
846 | dm_pci_write_config16(dev, PCI_COMMAND, command); | |
847 | dm_pci_read_config16(dev, PCI_COMMAND, &status); | |
848 | if ((status & command) != command) { | |
849 | printf("eepro100: Couldn't enable IO access or Bus Mastering\n"); | |
850 | return -EINVAL; | |
851 | } | |
852 | ||
853 | ret = eepro100_initialize_mii(priv); | |
854 | if (ret) | |
855 | return ret; | |
856 | ||
857 | dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x20); | |
858 | ||
859 | return 0; | |
860 | } | |
861 | ||
862 | static const struct eth_ops eepro100_ops = { | |
863 | .start = eepro100_start, | |
864 | .send = eepro100_send, | |
865 | .recv = eepro100_recv, | |
866 | .stop = eepro100_stop, | |
867 | .free_pkt = eepro100_free_pkt, | |
868 | .read_rom_hwaddr = eepro100_read_rom_hwaddr, | |
869 | }; | |
870 | ||
871 | U_BOOT_DRIVER(eth_eepro100) = { | |
872 | .name = "eth_eepro100", | |
873 | .id = UCLASS_ETH, | |
874 | .bind = eepro100_bind, | |
875 | .probe = eepro100_probe, | |
876 | .ops = &eepro100_ops, | |
41575d8e | 877 | .priv_auto = sizeof(struct eepro100_priv), |
caa4daa2 | 878 | .plat_auto = sizeof(struct eth_pdata), |
af8ecdf7 MV |
879 | }; |
880 | ||
881 | U_BOOT_PCI_DEVICE(eth_eepro100, supported); |