]>
Commit | Line | Data |
---|---|---|
c960b13e TC |
1 | /* |
2 | * Altera 10/100/1000 triple speed ethernet mac driver | |
3 | * | |
4 | * Copyright (C) 2008 Altera Corporation. | |
5 | * Copyright (C) 2010 Thomas Chou <[email protected]> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | */ | |
c960b13e | 11 | #include <common.h> |
1eb69ae4 | 12 | #include <cpu_func.h> |
96fa1e43 TC |
13 | #include <dm.h> |
14 | #include <errno.h> | |
15 | #include <fdt_support.h> | |
16 | #include <memalign.h> | |
17 | #include <miiphy.h> | |
c960b13e | 18 | #include <net.h> |
c960b13e TC |
19 | #include <asm/cache.h> |
20 | #include <asm/dma-mapping.h> | |
96fa1e43 | 21 | #include <asm/io.h> |
c960b13e TC |
22 | #include "altera_tse.h" |
23 | ||
96fa1e43 | 24 | DECLARE_GLOBAL_DATA_PTR; |
c960b13e | 25 | |
96fa1e43 TC |
26 | static inline void alt_sgdma_construct_descriptor( |
27 | struct alt_sgdma_descriptor *desc, | |
28 | struct alt_sgdma_descriptor *next, | |
29 | void *read_addr, | |
30 | void *write_addr, | |
2cd0a52e | 31 | u16 length_or_eop, |
c960b13e TC |
32 | int generate_eop, |
33 | int read_fixed, | |
96fa1e43 | 34 | int write_fixed_or_sop) |
c960b13e | 35 | { |
2cd0a52e | 36 | u8 val; |
96fa1e43 | 37 | |
c960b13e TC |
38 | /* |
39 | * Mark the "next" descriptor as "not" owned by hardware. This prevents | |
96fa1e43 | 40 | * The SGDMA controller from continuing to process the chain. |
c960b13e | 41 | */ |
96fa1e43 TC |
42 | next->descriptor_control = next->descriptor_control & |
43 | ~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK; | |
c960b13e | 44 | |
96fa1e43 TC |
45 | memset(desc, 0, sizeof(struct alt_sgdma_descriptor)); |
46 | desc->source = virt_to_phys(read_addr); | |
47 | desc->destination = virt_to_phys(write_addr); | |
48 | desc->next = virt_to_phys(next); | |
49 | desc->bytes_to_transfer = length_or_eop; | |
c960b13e TC |
50 | |
51 | /* | |
52 | * Set the descriptor control block as follows: | |
53 | * - Set "owned by hardware" bit | |
54 | * - Optionally set "generate EOP" bit | |
55 | * - Optionally set the "read from fixed address" bit | |
56 | * - Optionally set the "write to fixed address bit (which serves | |
57 | * serves as a "generate SOP" control bit in memory-to-stream mode). | |
58 | * - Set the 4-bit atlantic channel, if specified | |
59 | * | |
60 | * Note this step is performed after all other descriptor information | |
61 | * has been filled out so that, if the controller already happens to be | |
62 | * pointing at this descriptor, it will not run (via the "owned by | |
63 | * hardware" bit) until all other descriptor has been set up. | |
64 | */ | |
96fa1e43 TC |
65 | val = ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK; |
66 | if (generate_eop) | |
67 | val |= ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK; | |
68 | if (read_fixed) | |
69 | val |= ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK; | |
70 | if (write_fixed_or_sop) | |
71 | val |= ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK; | |
72 | desc->descriptor_control = val; | |
c960b13e TC |
73 | } |
74 | ||
96fa1e43 | 75 | static int alt_sgdma_wait_transfer(struct alt_sgdma_registers *regs) |
c960b13e | 76 | { |
96fa1e43 TC |
77 | int status; |
78 | ulong ctime; | |
c960b13e | 79 | |
96fa1e43 TC |
80 | /* Wait for the descriptor (chain) to complete */ |
81 | ctime = get_timer(0); | |
82 | while (1) { | |
83 | status = readl(®s->status); | |
84 | if (!(status & ALT_SGDMA_STATUS_BUSY_MSK)) | |
85 | break; | |
86 | if (get_timer(ctime) > ALT_TSE_SGDMA_BUSY_TIMEOUT) { | |
87 | status = -ETIMEDOUT; | |
88 | debug("sgdma timeout\n"); | |
c960b13e | 89 | break; |
96fa1e43 | 90 | } |
c960b13e TC |
91 | } |
92 | ||
c960b13e | 93 | /* Clear Run */ |
96fa1e43 TC |
94 | writel(0, ®s->control); |
95 | /* Clear status */ | |
96 | writel(0xff, ®s->status); | |
c960b13e | 97 | |
96fa1e43 | 98 | return status; |
c960b13e TC |
99 | } |
100 | ||
96fa1e43 TC |
101 | static int alt_sgdma_start_transfer(struct alt_sgdma_registers *regs, |
102 | struct alt_sgdma_descriptor *desc) | |
c960b13e | 103 | { |
2cd0a52e | 104 | u32 val; |
c960b13e TC |
105 | |
106 | /* Point the controller at the descriptor */ | |
96fa1e43 | 107 | writel(virt_to_phys(desc), ®s->next_descriptor_pointer); |
c960b13e TC |
108 | |
109 | /* | |
110 | * Set up SGDMA controller to: | |
111 | * - Disable interrupt generation | |
112 | * - Run once a valid descriptor is written to controller | |
113 | * - Stop on an error with any particular descriptor | |
114 | */ | |
96fa1e43 TC |
115 | val = ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK; |
116 | writel(val, ®s->control); | |
c960b13e | 117 | |
c960b13e TC |
118 | return 0; |
119 | } | |
120 | ||
96fa1e43 TC |
121 | static void tse_adjust_link(struct altera_tse_priv *priv, |
122 | struct phy_device *phydev) | |
c960b13e | 123 | { |
96fa1e43 | 124 | struct alt_tse_mac *mac_dev = priv->mac_dev; |
2cd0a52e | 125 | u32 refvar; |
c960b13e | 126 | |
96fa1e43 TC |
127 | if (!phydev->link) { |
128 | debug("%s: No link.\n", phydev->dev->name); | |
129 | return; | |
130 | } | |
131 | ||
132 | refvar = readl(&mac_dev->command_config); | |
c960b13e | 133 | |
96fa1e43 | 134 | if (phydev->duplex) |
c960b13e TC |
135 | refvar |= ALTERA_TSE_CMD_HD_ENA_MSK; |
136 | else | |
137 | refvar &= ~ALTERA_TSE_CMD_HD_ENA_MSK; | |
138 | ||
96fa1e43 | 139 | switch (phydev->speed) { |
c960b13e TC |
140 | case 1000: |
141 | refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK; | |
142 | refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; | |
143 | break; | |
144 | case 100: | |
145 | refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; | |
146 | refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; | |
147 | break; | |
148 | case 10: | |
149 | refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; | |
150 | refvar |= ALTERA_TSE_CMD_ENA_10_MSK; | |
151 | break; | |
152 | } | |
96fa1e43 | 153 | writel(refvar, &mac_dev->command_config); |
c960b13e TC |
154 | } |
155 | ||
38fa4aca | 156 | static int altera_tse_send_sgdma(struct udevice *dev, void *packet, int length) |
c960b13e | 157 | { |
96fa1e43 TC |
158 | struct altera_tse_priv *priv = dev_get_priv(dev); |
159 | struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; | |
96fa1e43 | 160 | |
96fa1e43 TC |
161 | alt_sgdma_construct_descriptor( |
162 | tx_desc, | |
163 | tx_desc + 1, | |
164 | packet, /* read addr */ | |
165 | NULL, /* write addr */ | |
c960b13e | 166 | length, /* length or EOP ,will change for each tx */ |
96fa1e43 TC |
167 | 1, /* gen eop */ |
168 | 0, /* read fixed */ | |
169 | 1 /* write fixed or sop */ | |
c960b13e | 170 | ); |
c960b13e TC |
171 | |
172 | /* send the packet */ | |
96fa1e43 TC |
173 | alt_sgdma_start_transfer(priv->sgdma_tx, tx_desc); |
174 | alt_sgdma_wait_transfer(priv->sgdma_tx); | |
175 | debug("sent %d bytes\n", tx_desc->actual_bytes_transferred); | |
176 | ||
177 | return tx_desc->actual_bytes_transferred; | |
c960b13e TC |
178 | } |
179 | ||
38fa4aca TC |
180 | static int altera_tse_recv_sgdma(struct udevice *dev, int flags, |
181 | uchar **packetp) | |
c960b13e | 182 | { |
96fa1e43 TC |
183 | struct altera_tse_priv *priv = dev_get_priv(dev); |
184 | struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; | |
185 | int packet_length; | |
c960b13e | 186 | |
96fa1e43 | 187 | if (rx_desc->descriptor_status & |
c960b13e | 188 | ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { |
577662f0 | 189 | alt_sgdma_wait_transfer(priv->sgdma_rx); |
c960b13e | 190 | packet_length = rx_desc->actual_bytes_transferred; |
96fa1e43 TC |
191 | debug("recv %d bytes\n", packet_length); |
192 | *packetp = priv->rx_buf; | |
70d52f9a JF |
193 | |
194 | return packet_length; | |
c960b13e TC |
195 | } |
196 | ||
96fa1e43 | 197 | return -EAGAIN; |
c960b13e TC |
198 | } |
199 | ||
38fa4aca TC |
200 | static int altera_tse_free_pkt_sgdma(struct udevice *dev, uchar *packet, |
201 | int length) | |
c960b13e | 202 | { |
96fa1e43 TC |
203 | struct altera_tse_priv *priv = dev_get_priv(dev); |
204 | struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; | |
96fa1e43 | 205 | |
96fa1e43 TC |
206 | alt_sgdma_construct_descriptor( |
207 | rx_desc, | |
208 | rx_desc + 1, | |
209 | NULL, /* read addr */ | |
210 | priv->rx_buf, /* write addr */ | |
211 | 0, /* length or EOP */ | |
212 | 0, /* gen eop */ | |
213 | 0, /* read fixed */ | |
214 | 0 /* write fixed or sop */ | |
215 | ); | |
216 | ||
217 | /* setup the sgdma */ | |
218 | alt_sgdma_start_transfer(priv->sgdma_rx, rx_desc); | |
219 | debug("recv setup\n"); | |
220 | ||
221 | return 0; | |
c960b13e TC |
222 | } |
223 | ||
acd71c32 TC |
224 | static void altera_tse_stop_mac(struct altera_tse_priv *priv) |
225 | { | |
226 | struct alt_tse_mac *mac_dev = priv->mac_dev; | |
227 | u32 status; | |
228 | ulong ctime; | |
229 | ||
230 | /* reset the mac */ | |
231 | writel(ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config); | |
232 | ctime = get_timer(0); | |
233 | while (1) { | |
234 | status = readl(&mac_dev->command_config); | |
235 | if (!(status & ALTERA_TSE_CMD_SW_RESET_MSK)) | |
236 | break; | |
237 | if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) { | |
238 | debug("Reset mac timeout\n"); | |
239 | break; | |
240 | } | |
241 | } | |
242 | } | |
243 | ||
38fa4aca | 244 | static void altera_tse_stop_sgdma(struct udevice *dev) |
c960b13e | 245 | { |
96fa1e43 | 246 | struct altera_tse_priv *priv = dev_get_priv(dev); |
96fa1e43 TC |
247 | struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; |
248 | struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; | |
249 | struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; | |
96fa1e43 | 250 | int ret; |
c960b13e TC |
251 | |
252 | /* clear rx desc & wait for sgdma to complete */ | |
253 | rx_desc->descriptor_control = 0; | |
96fa1e43 TC |
254 | writel(0, &rx_sgdma->control); |
255 | ret = alt_sgdma_wait_transfer(rx_sgdma); | |
256 | if (ret == -ETIMEDOUT) | |
257 | writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, | |
258 | &rx_sgdma->control); | |
259 | ||
260 | writel(0, &tx_sgdma->control); | |
261 | ret = alt_sgdma_wait_transfer(tx_sgdma); | |
262 | if (ret == -ETIMEDOUT) | |
263 | writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, | |
264 | &tx_sgdma->control); | |
c960b13e TC |
265 | } |
266 | ||
e3e87260 TC |
267 | static void msgdma_reset(struct msgdma_csr *csr) |
268 | { | |
269 | u32 status; | |
270 | ulong ctime; | |
271 | ||
272 | /* Reset mSGDMA */ | |
273 | writel(MSGDMA_CSR_STAT_MASK, &csr->status); | |
274 | writel(MSGDMA_CSR_CTL_RESET, &csr->control); | |
275 | ctime = get_timer(0); | |
276 | while (1) { | |
277 | status = readl(&csr->status); | |
278 | if (!(status & MSGDMA_CSR_STAT_RESETTING)) | |
279 | break; | |
280 | if (get_timer(ctime) > ALT_TSE_SW_RESET_TIMEOUT) { | |
281 | debug("Reset msgdma timeout\n"); | |
282 | break; | |
283 | } | |
284 | } | |
285 | /* Clear status */ | |
286 | writel(MSGDMA_CSR_STAT_MASK, &csr->status); | |
287 | } | |
288 | ||
289 | static u32 msgdma_wait(struct msgdma_csr *csr) | |
290 | { | |
291 | u32 status; | |
292 | ulong ctime; | |
293 | ||
294 | /* Wait for the descriptor to complete */ | |
295 | ctime = get_timer(0); | |
296 | while (1) { | |
297 | status = readl(&csr->status); | |
298 | if (!(status & MSGDMA_CSR_STAT_BUSY)) | |
299 | break; | |
300 | if (get_timer(ctime) > ALT_TSE_SGDMA_BUSY_TIMEOUT) { | |
301 | debug("sgdma timeout\n"); | |
302 | break; | |
303 | } | |
304 | } | |
305 | /* Clear status */ | |
306 | writel(MSGDMA_CSR_STAT_MASK, &csr->status); | |
307 | ||
308 | return status; | |
309 | } | |
310 | ||
311 | static int altera_tse_send_msgdma(struct udevice *dev, void *packet, | |
312 | int length) | |
313 | { | |
314 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
315 | struct msgdma_extended_desc *desc = priv->tx_desc; | |
316 | u32 tx_buf = virt_to_phys(packet); | |
317 | u32 status; | |
318 | ||
319 | writel(tx_buf, &desc->read_addr_lo); | |
320 | writel(0, &desc->read_addr_hi); | |
321 | writel(0, &desc->write_addr_lo); | |
322 | writel(0, &desc->write_addr_hi); | |
323 | writel(length, &desc->len); | |
324 | writel(0, &desc->burst_seq_num); | |
325 | writel(MSGDMA_DESC_TX_STRIDE, &desc->stride); | |
326 | writel(MSGDMA_DESC_CTL_TX_SINGLE, &desc->control); | |
327 | status = msgdma_wait(priv->sgdma_tx); | |
328 | debug("sent %d bytes, status %08x\n", length, status); | |
329 | ||
330 | return 0; | |
331 | } | |
332 | ||
333 | static int altera_tse_recv_msgdma(struct udevice *dev, int flags, | |
334 | uchar **packetp) | |
335 | { | |
336 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
337 | struct msgdma_csr *csr = priv->sgdma_rx; | |
338 | struct msgdma_response *resp = priv->rx_resp; | |
339 | u32 level, length, status; | |
340 | ||
341 | level = readl(&csr->resp_fill_level); | |
342 | if (level & 0xffff) { | |
343 | length = readl(&resp->bytes_transferred); | |
344 | status = readl(&resp->status); | |
345 | debug("recv %d bytes, status %08x\n", length, status); | |
346 | *packetp = priv->rx_buf; | |
347 | ||
348 | return length; | |
349 | } | |
350 | ||
351 | return -EAGAIN; | |
352 | } | |
353 | ||
354 | static int altera_tse_free_pkt_msgdma(struct udevice *dev, uchar *packet, | |
355 | int length) | |
356 | { | |
357 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
358 | struct msgdma_extended_desc *desc = priv->rx_desc; | |
359 | u32 rx_buf = virt_to_phys(priv->rx_buf); | |
360 | ||
361 | writel(0, &desc->read_addr_lo); | |
362 | writel(0, &desc->read_addr_hi); | |
363 | writel(rx_buf, &desc->write_addr_lo); | |
364 | writel(0, &desc->write_addr_hi); | |
365 | writel(PKTSIZE_ALIGN, &desc->len); | |
366 | writel(0, &desc->burst_seq_num); | |
367 | writel(MSGDMA_DESC_RX_STRIDE, &desc->stride); | |
368 | writel(MSGDMA_DESC_CTL_RX_SINGLE, &desc->control); | |
369 | debug("recv setup\n"); | |
370 | ||
371 | return 0; | |
372 | } | |
373 | ||
374 | static void altera_tse_stop_msgdma(struct udevice *dev) | |
375 | { | |
376 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
377 | ||
378 | msgdma_reset(priv->sgdma_rx); | |
379 | msgdma_reset(priv->sgdma_tx); | |
380 | } | |
381 | ||
96fa1e43 | 382 | static int tse_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) |
c960b13e | 383 | { |
96fa1e43 TC |
384 | struct altera_tse_priv *priv = bus->priv; |
385 | struct alt_tse_mac *mac_dev = priv->mac_dev; | |
2cd0a52e | 386 | u32 value; |
c960b13e TC |
387 | |
388 | /* set mdio address */ | |
96fa1e43 | 389 | writel(addr, &mac_dev->mdio_phy1_addr); |
c960b13e | 390 | /* get the data */ |
96fa1e43 | 391 | value = readl(&mac_dev->mdio_phy1[reg]); |
c960b13e | 392 | |
96fa1e43 | 393 | return value & 0xffff; |
c960b13e TC |
394 | } |
395 | ||
96fa1e43 TC |
396 | static int tse_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, |
397 | u16 val) | |
c960b13e | 398 | { |
96fa1e43 TC |
399 | struct altera_tse_priv *priv = bus->priv; |
400 | struct alt_tse_mac *mac_dev = priv->mac_dev; | |
c960b13e TC |
401 | |
402 | /* set mdio address */ | |
96fa1e43 TC |
403 | writel(addr, &mac_dev->mdio_phy1_addr); |
404 | /* set the data */ | |
405 | writel(val, &mac_dev->mdio_phy1[reg]); | |
c960b13e TC |
406 | |
407 | return 0; | |
408 | } | |
409 | ||
96fa1e43 | 410 | static int tse_mdio_init(const char *name, struct altera_tse_priv *priv) |
c960b13e | 411 | { |
96fa1e43 | 412 | struct mii_dev *bus = mdio_alloc(); |
c960b13e | 413 | |
96fa1e43 TC |
414 | if (!bus) { |
415 | printf("Failed to allocate MDIO bus\n"); | |
416 | return -ENOMEM; | |
c960b13e TC |
417 | } |
418 | ||
96fa1e43 TC |
419 | bus->read = tse_mdio_read; |
420 | bus->write = tse_mdio_write; | |
192bc694 | 421 | snprintf(bus->name, sizeof(bus->name), "%s", name); |
c960b13e | 422 | |
96fa1e43 | 423 | bus->priv = (void *)priv; |
15eb1069 | 424 | |
96fa1e43 | 425 | return mdio_register(bus); |
c960b13e TC |
426 | } |
427 | ||
96fa1e43 | 428 | static int tse_phy_init(struct altera_tse_priv *priv, void *dev) |
c960b13e | 429 | { |
96fa1e43 TC |
430 | struct phy_device *phydev; |
431 | unsigned int mask = 0xffffffff; | |
c960b13e | 432 | |
96fa1e43 TC |
433 | if (priv->phyaddr) |
434 | mask = 1 << priv->phyaddr; | |
c960b13e | 435 | |
96fa1e43 TC |
436 | phydev = phy_find_by_mask(priv->bus, mask, priv->interface); |
437 | if (!phydev) | |
438 | return -ENODEV; | |
c960b13e | 439 | |
96fa1e43 | 440 | phy_connect_dev(phydev, dev); |
c960b13e | 441 | |
96fa1e43 TC |
442 | phydev->supported &= PHY_GBIT_FEATURES; |
443 | phydev->advertising = phydev->supported; | |
c960b13e | 444 | |
96fa1e43 TC |
445 | priv->phydev = phydev; |
446 | phy_config(phydev); | |
c960b13e | 447 | |
96fa1e43 | 448 | return 0; |
c960b13e TC |
449 | } |
450 | ||
96fa1e43 | 451 | static int altera_tse_write_hwaddr(struct udevice *dev) |
c960b13e | 452 | { |
96fa1e43 TC |
453 | struct altera_tse_priv *priv = dev_get_priv(dev); |
454 | struct alt_tse_mac *mac_dev = priv->mac_dev; | |
455 | struct eth_pdata *pdata = dev_get_platdata(dev); | |
456 | u8 *hwaddr = pdata->enetaddr; | |
2cd0a52e | 457 | u32 mac_lo, mac_hi; |
96fa1e43 TC |
458 | |
459 | mac_lo = (hwaddr[3] << 24) | (hwaddr[2] << 16) | | |
460 | (hwaddr[1] << 8) | hwaddr[0]; | |
461 | mac_hi = (hwaddr[5] << 8) | hwaddr[4]; | |
462 | debug("Set MAC address to 0x%04x%08x\n", mac_hi, mac_lo); | |
463 | ||
464 | writel(mac_lo, &mac_dev->mac_addr_0); | |
465 | writel(mac_hi, &mac_dev->mac_addr_1); | |
466 | writel(mac_lo, &mac_dev->supp_mac_addr_0_0); | |
467 | writel(mac_hi, &mac_dev->supp_mac_addr_0_1); | |
468 | writel(mac_lo, &mac_dev->supp_mac_addr_1_0); | |
469 | writel(mac_hi, &mac_dev->supp_mac_addr_1_1); | |
470 | writel(mac_lo, &mac_dev->supp_mac_addr_2_0); | |
471 | writel(mac_hi, &mac_dev->supp_mac_addr_2_1); | |
472 | writel(mac_lo, &mac_dev->supp_mac_addr_3_0); | |
473 | writel(mac_hi, &mac_dev->supp_mac_addr_3_1); | |
c960b13e | 474 | |
6c7c4447 TC |
475 | return 0; |
476 | } | |
477 | ||
38fa4aca TC |
478 | static int altera_tse_send(struct udevice *dev, void *packet, int length) |
479 | { | |
480 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
481 | unsigned long tx_buf = (unsigned long)packet; | |
482 | ||
483 | flush_dcache_range(tx_buf, tx_buf + length); | |
484 | ||
485 | return priv->ops->send(dev, packet, length); | |
486 | } | |
487 | ||
488 | static int altera_tse_recv(struct udevice *dev, int flags, uchar **packetp) | |
489 | { | |
490 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
491 | ||
492 | return priv->ops->recv(dev, flags, packetp); | |
493 | } | |
494 | ||
495 | static int altera_tse_free_pkt(struct udevice *dev, uchar *packet, | |
496 | int length) | |
497 | { | |
498 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
499 | unsigned long rx_buf = (unsigned long)priv->rx_buf; | |
500 | ||
501 | invalidate_dcache_range(rx_buf, rx_buf + PKTSIZE_ALIGN); | |
502 | ||
503 | return priv->ops->free_pkt(dev, packet, length); | |
504 | } | |
505 | ||
506 | static void altera_tse_stop(struct udevice *dev) | |
507 | { | |
508 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
509 | ||
510 | priv->ops->stop(dev); | |
511 | altera_tse_stop_mac(priv); | |
512 | } | |
513 | ||
96fa1e43 | 514 | static int altera_tse_start(struct udevice *dev) |
c960b13e | 515 | { |
96fa1e43 TC |
516 | struct altera_tse_priv *priv = dev_get_priv(dev); |
517 | struct alt_tse_mac *mac_dev = priv->mac_dev; | |
2cd0a52e | 518 | u32 val; |
96fa1e43 | 519 | int ret; |
c960b13e TC |
520 | |
521 | /* need to create sgdma */ | |
c960b13e | 522 | debug("Configuring rx desc\n"); |
96fa1e43 | 523 | altera_tse_free_pkt(dev, priv->rx_buf, PKTSIZE_ALIGN); |
c960b13e TC |
524 | /* start TSE */ |
525 | debug("Configuring TSE Mac\n"); | |
526 | /* Initialize MAC registers */ | |
96fa1e43 TC |
527 | writel(PKTSIZE_ALIGN, &mac_dev->max_frame_length); |
528 | writel(priv->rx_fifo_depth - 16, &mac_dev->rx_sel_empty_threshold); | |
529 | writel(0, &mac_dev->rx_sel_full_threshold); | |
530 | writel(priv->tx_fifo_depth - 16, &mac_dev->tx_sel_empty_threshold); | |
531 | writel(0, &mac_dev->tx_sel_full_threshold); | |
532 | writel(8, &mac_dev->rx_almost_empty_threshold); | |
533 | writel(8, &mac_dev->rx_almost_full_threshold); | |
534 | writel(8, &mac_dev->tx_almost_empty_threshold); | |
535 | writel(3, &mac_dev->tx_almost_full_threshold); | |
c960b13e TC |
536 | |
537 | /* NO Shift */ | |
96fa1e43 TC |
538 | writel(0, &mac_dev->rx_cmd_stat); |
539 | writel(0, &mac_dev->tx_cmd_stat); | |
c960b13e TC |
540 | |
541 | /* enable MAC */ | |
96fa1e43 TC |
542 | val = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK; |
543 | writel(val, &mac_dev->command_config); | |
544 | ||
545 | /* Start up the PHY */ | |
546 | ret = phy_startup(priv->phydev); | |
547 | if (ret) { | |
548 | debug("Could not initialize PHY %s\n", | |
549 | priv->phydev->dev->name); | |
550 | return ret; | |
551 | } | |
c960b13e | 552 | |
96fa1e43 | 553 | tse_adjust_link(priv, priv->phydev); |
c960b13e | 554 | |
96fa1e43 TC |
555 | if (!priv->phydev->link) |
556 | return -EIO; | |
c960b13e | 557 | |
96fa1e43 | 558 | return 0; |
c960b13e TC |
559 | } |
560 | ||
38fa4aca TC |
561 | static const struct tse_ops tse_sgdma_ops = { |
562 | .send = altera_tse_send_sgdma, | |
563 | .recv = altera_tse_recv_sgdma, | |
564 | .free_pkt = altera_tse_free_pkt_sgdma, | |
565 | .stop = altera_tse_stop_sgdma, | |
566 | }; | |
567 | ||
e3e87260 TC |
568 | static const struct tse_ops tse_msgdma_ops = { |
569 | .send = altera_tse_send_msgdma, | |
570 | .recv = altera_tse_recv_msgdma, | |
571 | .free_pkt = altera_tse_free_pkt_msgdma, | |
572 | .stop = altera_tse_stop_msgdma, | |
573 | }; | |
574 | ||
96fa1e43 | 575 | static int altera_tse_probe(struct udevice *dev) |
c960b13e | 576 | { |
96fa1e43 TC |
577 | struct eth_pdata *pdata = dev_get_platdata(dev); |
578 | struct altera_tse_priv *priv = dev_get_priv(dev); | |
75199d6f | 579 | void *blob = (void *)gd->fdt_blob; |
e160f7d4 | 580 | int node = dev_of_offset(dev); |
96fa1e43 TC |
581 | const char *list, *end; |
582 | const fdt32_t *cell; | |
583 | void *base, *desc_mem = NULL; | |
584 | unsigned long addr, size; | |
75199d6f | 585 | int parent, addrc, sizec; |
96fa1e43 TC |
586 | int len, idx; |
587 | int ret; | |
c960b13e | 588 | |
38fa4aca TC |
589 | priv->dma_type = dev_get_driver_data(dev); |
590 | if (priv->dma_type == ALT_SGDMA) | |
591 | priv->ops = &tse_sgdma_ops; | |
e3e87260 TC |
592 | else |
593 | priv->ops = &tse_msgdma_ops; | |
96fa1e43 | 594 | /* |
75199d6f TC |
595 | * decode regs. there are multiple reg tuples, and they need to |
596 | * match with reg-names. | |
96fa1e43 | 597 | */ |
75199d6f | 598 | parent = fdt_parent_offset(blob, node); |
eed36609 | 599 | fdt_support_default_count_cells(blob, parent, &addrc, &sizec); |
96fa1e43 TC |
600 | list = fdt_getprop(blob, node, "reg-names", &len); |
601 | if (!list) | |
602 | return -ENOENT; | |
603 | end = list + len; | |
604 | cell = fdt_getprop(blob, node, "reg", &len); | |
605 | if (!cell) | |
606 | return -ENOENT; | |
607 | idx = 0; | |
608 | while (list < end) { | |
609 | addr = fdt_translate_address((void *)blob, | |
610 | node, cell + idx); | |
75199d6f | 611 | size = fdt_addr_to_cpu(cell[idx + addrc]); |
e2b259f7 | 612 | base = map_physmem(addr, size, MAP_NOCACHE); |
96fa1e43 TC |
613 | len = strlen(list); |
614 | if (strcmp(list, "control_port") == 0) | |
615 | priv->mac_dev = base; | |
616 | else if (strcmp(list, "rx_csr") == 0) | |
617 | priv->sgdma_rx = base; | |
e3e87260 TC |
618 | else if (strcmp(list, "rx_desc") == 0) |
619 | priv->rx_desc = base; | |
620 | else if (strcmp(list, "rx_resp") == 0) | |
621 | priv->rx_resp = base; | |
96fa1e43 TC |
622 | else if (strcmp(list, "tx_csr") == 0) |
623 | priv->sgdma_tx = base; | |
e3e87260 TC |
624 | else if (strcmp(list, "tx_desc") == 0) |
625 | priv->tx_desc = base; | |
96fa1e43 TC |
626 | else if (strcmp(list, "s1") == 0) |
627 | desc_mem = base; | |
75199d6f | 628 | idx += addrc + sizec; |
96fa1e43 TC |
629 | list += (len + 1); |
630 | } | |
631 | /* decode fifo depth */ | |
632 | priv->rx_fifo_depth = fdtdec_get_int(blob, node, | |
633 | "rx-fifo-depth", 0); | |
634 | priv->tx_fifo_depth = fdtdec_get_int(blob, node, | |
635 | "tx-fifo-depth", 0); | |
636 | /* decode phy */ | |
637 | addr = fdtdec_get_int(blob, node, | |
638 | "phy-handle", 0); | |
639 | addr = fdt_node_offset_by_phandle(blob, addr); | |
640 | priv->phyaddr = fdtdec_get_int(blob, addr, | |
641 | "reg", 0); | |
642 | /* init desc */ | |
38fa4aca TC |
643 | if (priv->dma_type == ALT_SGDMA) { |
644 | len = sizeof(struct alt_sgdma_descriptor) * 4; | |
645 | if (!desc_mem) { | |
646 | desc_mem = dma_alloc_coherent(len, &addr); | |
647 | if (!desc_mem) | |
648 | return -ENOMEM; | |
649 | } | |
650 | memset(desc_mem, 0, len); | |
651 | priv->tx_desc = desc_mem; | |
652 | priv->rx_desc = priv->tx_desc + | |
653 | 2 * sizeof(struct alt_sgdma_descriptor); | |
96fa1e43 | 654 | } |
96fa1e43 TC |
655 | /* allocate recv packet buffer */ |
656 | priv->rx_buf = malloc_cache_aligned(PKTSIZE_ALIGN); | |
657 | if (!priv->rx_buf) | |
658 | return -ENOMEM; | |
c960b13e | 659 | |
96fa1e43 TC |
660 | /* stop controller */ |
661 | debug("Reset TSE & SGDMAs\n"); | |
662 | altera_tse_stop(dev); | |
c960b13e | 663 | |
96fa1e43 TC |
664 | /* start the phy */ |
665 | priv->interface = pdata->phy_interface; | |
666 | tse_mdio_init(dev->name, priv); | |
667 | priv->bus = miiphy_get_dev_by_name(dev->name); | |
c960b13e | 668 | |
96fa1e43 | 669 | ret = tse_phy_init(priv, dev); |
b962ac79 | 670 | |
96fa1e43 TC |
671 | return ret; |
672 | } | |
c960b13e | 673 | |
96fa1e43 TC |
674 | static int altera_tse_ofdata_to_platdata(struct udevice *dev) |
675 | { | |
676 | struct eth_pdata *pdata = dev_get_platdata(dev); | |
677 | const char *phy_mode; | |
678 | ||
679 | pdata->phy_interface = -1; | |
e160f7d4 SG |
680 | phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", |
681 | NULL); | |
96fa1e43 TC |
682 | if (phy_mode) |
683 | pdata->phy_interface = phy_get_interface_by_name(phy_mode); | |
684 | if (pdata->phy_interface == -1) { | |
685 | debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); | |
686 | return -EINVAL; | |
c960b13e | 687 | } |
96fa1e43 TC |
688 | |
689 | return 0; | |
c960b13e | 690 | } |
96fa1e43 TC |
691 | |
692 | static const struct eth_ops altera_tse_ops = { | |
693 | .start = altera_tse_start, | |
694 | .send = altera_tse_send, | |
695 | .recv = altera_tse_recv, | |
696 | .free_pkt = altera_tse_free_pkt, | |
697 | .stop = altera_tse_stop, | |
698 | .write_hwaddr = altera_tse_write_hwaddr, | |
699 | }; | |
700 | ||
701 | static const struct udevice_id altera_tse_ids[] = { | |
e3e87260 | 702 | { .compatible = "altr,tse-msgdma-1.0", .data = ALT_MSGDMA }, |
38fa4aca TC |
703 | { .compatible = "altr,tse-1.0", .data = ALT_SGDMA }, |
704 | {} | |
96fa1e43 TC |
705 | }; |
706 | ||
707 | U_BOOT_DRIVER(altera_tse) = { | |
708 | .name = "altera_tse", | |
709 | .id = UCLASS_ETH, | |
710 | .of_match = altera_tse_ids, | |
711 | .ops = &altera_tse_ops, | |
712 | .ofdata_to_platdata = altera_tse_ofdata_to_platdata, | |
713 | .platdata_auto_alloc_size = sizeof(struct eth_pdata), | |
714 | .priv_auto_alloc_size = sizeof(struct altera_tse_priv), | |
715 | .probe = altera_tse_probe, | |
716 | }; |