blob: 01434543873b24761b460402fdb7aab0619fb2e9 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dave Liu7737d5c2006-11-03 12:11:15 -06002/*
Haiying Wanga52d2f82011-02-11 01:25:30 -06003 * Copyright (C) 2006-2011 Freescale Semiconductor, Inc.
Dave Liu7737d5c2006-11-03 12:11:15 -06004 *
5 * Dave Liu <daveliu@freescale.com>
Dave Liu7737d5c2006-11-03 12:11:15 -06006 */
7
Masahiro Yamadab5bf5cb2016-09-21 11:28:53 +09008#include <common.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -06009#include <log.h>
Masahiro Yamadab5bf5cb2016-09-21 11:28:53 +090010#include <net.h>
11#include <malloc.h>
Simon Glassc05ed002020-05-10 11:40:11 -060012#include <linux/delay.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090013#include <linux/errno.h>
Masahiro Yamadab5bf5cb2016-09-21 11:28:53 +090014#include <asm/io.h>
15#include <linux/immap_qe.h>
Dave Liu7737d5c2006-11-03 12:11:15 -060016#include "uccf.h"
17#include "uec.h"
18#include "uec_phy.h"
David Saadad5d28fe2008-03-31 02:37:38 -070019#include "miiphy.h"
Qianyu Gong2459afb2016-02-18 13:01:59 +080020#include <fsl_qe.h>
Andy Fleming865ff852011-04-13 00:37:12 -050021#include <phy.h>
Dave Liu7737d5c2006-11-03 12:11:15 -060022
Richard Retanubun1a951932009-07-01 14:03:15 -040023/* Default UTBIPAR SMI address */
24#ifndef CONFIG_UTBIPAR_INIT_TBIPA
25#define CONFIG_UTBIPAR_INIT_TBIPA 0x1F
26#endif
27
Haiying Wang8e552582009-06-04 16:12:41 -040028static uec_info_t uec_info[] = {
Dave Liu7737d5c2006-11-03 12:11:15 -060029#ifdef CONFIG_UEC_ETH1
Haiying Wang8e552582009-06-04 16:12:41 -040030 STD_UEC_INFO(1), /* UEC1 */
Dave Liu7737d5c2006-11-03 12:11:15 -060031#endif
32#ifdef CONFIG_UEC_ETH2
Haiying Wang8e552582009-06-04 16:12:41 -040033 STD_UEC_INFO(2), /* UEC2 */
Dave Liu7737d5c2006-11-03 12:11:15 -060034#endif
Joakim Tjernlundccf21c32007-12-06 16:43:40 +010035#ifdef CONFIG_UEC_ETH3
Haiying Wang8e552582009-06-04 16:12:41 -040036 STD_UEC_INFO(3), /* UEC3 */
Joakim Tjernlundccf21c32007-12-06 16:43:40 +010037#endif
David Saada24656652008-01-15 10:40:24 +020038#ifdef CONFIG_UEC_ETH4
Haiying Wang8e552582009-06-04 16:12:41 -040039 STD_UEC_INFO(4), /* UEC4 */
David Saada24656652008-01-15 10:40:24 +020040#endif
richardretanubunc68a05f2008-09-29 18:28:23 -040041#ifdef CONFIG_UEC_ETH5
Haiying Wang8e552582009-06-04 16:12:41 -040042 STD_UEC_INFO(5), /* UEC5 */
richardretanubunc68a05f2008-09-29 18:28:23 -040043#endif
44#ifdef CONFIG_UEC_ETH6
Haiying Wang8e552582009-06-04 16:12:41 -040045 STD_UEC_INFO(6), /* UEC6 */
richardretanubunc68a05f2008-09-29 18:28:23 -040046#endif
Haiying Wang8e552582009-06-04 16:12:41 -040047#ifdef CONFIG_UEC_ETH7
48 STD_UEC_INFO(7), /* UEC7 */
Haiying Wang7211fbf2009-05-21 15:34:14 -040049#endif
Haiying Wang8e552582009-06-04 16:12:41 -040050#ifdef CONFIG_UEC_ETH8
51 STD_UEC_INFO(8), /* UEC8 */
52#endif
richardretanubunc68a05f2008-09-29 18:28:23 -040053};
Joakim Tjernlundccf21c32007-12-06 16:43:40 +010054
Haiying Wang8e552582009-06-04 16:12:41 -040055#define MAXCONTROLLERS (8)
David Saadad5d28fe2008-03-31 02:37:38 -070056
57static struct eth_device *devlist[MAXCONTROLLERS];
58
Dave Liu7737d5c2006-11-03 12:11:15 -060059static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode)
60{
61 uec_t *uec_regs;
62 u32 maccfg1;
63
64 if (!uec) {
65 printf("%s: uec not initial\n", __FUNCTION__);
66 return -EINVAL;
67 }
68 uec_regs = uec->uec_regs;
69
70 maccfg1 = in_be32(&uec_regs->maccfg1);
71
72 if (mode & COMM_DIR_TX) {
73 maccfg1 |= MACCFG1_ENABLE_TX;
74 out_be32(&uec_regs->maccfg1, maccfg1);
75 uec->mac_tx_enabled = 1;
76 }
77
78 if (mode & COMM_DIR_RX) {
79 maccfg1 |= MACCFG1_ENABLE_RX;
80 out_be32(&uec_regs->maccfg1, maccfg1);
81 uec->mac_rx_enabled = 1;
82 }
83
84 return 0;
85}
86
87static int uec_mac_disable(uec_private_t *uec, comm_dir_e mode)
88{
89 uec_t *uec_regs;
90 u32 maccfg1;
91
92 if (!uec) {
93 printf("%s: uec not initial\n", __FUNCTION__);
94 return -EINVAL;
95 }
96 uec_regs = uec->uec_regs;
97
98 maccfg1 = in_be32(&uec_regs->maccfg1);
99
100 if (mode & COMM_DIR_TX) {
101 maccfg1 &= ~MACCFG1_ENABLE_TX;
102 out_be32(&uec_regs->maccfg1, maccfg1);
103 uec->mac_tx_enabled = 0;
104 }
105
106 if (mode & COMM_DIR_RX) {
107 maccfg1 &= ~MACCFG1_ENABLE_RX;
108 out_be32(&uec_regs->maccfg1, maccfg1);
109 uec->mac_rx_enabled = 0;
110 }
111
112 return 0;
113}
114
115static int uec_graceful_stop_tx(uec_private_t *uec)
116{
117 ucc_fast_t *uf_regs;
118 u32 cecr_subblock;
119 u32 ucce;
120
121 if (!uec || !uec->uccf) {
122 printf("%s: No handle passed.\n", __FUNCTION__);
123 return -EINVAL;
124 }
125
126 uf_regs = uec->uccf->uf_regs;
127
128 /* Clear the grace stop event */
129 out_be32(&uf_regs->ucce, UCCE_GRA);
130
131 /* Issue host command */
132 cecr_subblock =
133 ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
134 qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
135 (u8)QE_CR_PROTOCOL_ETHERNET, 0);
136
137 /* Wait for command to complete */
138 do {
139 ucce = in_be32(&uf_regs->ucce);
140 } while (! (ucce & UCCE_GRA));
141
142 uec->grace_stopped_tx = 1;
143
144 return 0;
145}
146
147static int uec_graceful_stop_rx(uec_private_t *uec)
148{
149 u32 cecr_subblock;
150 u8 ack;
151
152 if (!uec) {
153 printf("%s: No handle passed.\n", __FUNCTION__);
154 return -EINVAL;
155 }
156
157 if (!uec->p_rx_glbl_pram) {
158 printf("%s: No init rx global parameter\n", __FUNCTION__);
159 return -EINVAL;
160 }
161
162 /* Clear acknowledge bit */
163 ack = uec->p_rx_glbl_pram->rxgstpack;
164 ack &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX;
165 uec->p_rx_glbl_pram->rxgstpack = ack;
166
167 /* Keep issuing cmd and checking ack bit until it is asserted */
168 do {
169 /* Issue host command */
170 cecr_subblock =
171 ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
172 qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
173 (u8)QE_CR_PROTOCOL_ETHERNET, 0);
174 ack = uec->p_rx_glbl_pram->rxgstpack;
175 } while (! (ack & GRACEFUL_STOP_ACKNOWLEDGE_RX ));
176
177 uec->grace_stopped_rx = 1;
178
179 return 0;
180}
181
182static int uec_restart_tx(uec_private_t *uec)
183{
184 u32 cecr_subblock;
185
186 if (!uec || !uec->uec_info) {
187 printf("%s: No handle passed.\n", __FUNCTION__);
188 return -EINVAL;
189 }
190
191 cecr_subblock =
192 ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
193 qe_issue_cmd(QE_RESTART_TX, cecr_subblock,
194 (u8)QE_CR_PROTOCOL_ETHERNET, 0);
195
196 uec->grace_stopped_tx = 0;
197
198 return 0;
199}
200
201static int uec_restart_rx(uec_private_t *uec)
202{
203 u32 cecr_subblock;
204
205 if (!uec || !uec->uec_info) {
206 printf("%s: No handle passed.\n", __FUNCTION__);
207 return -EINVAL;
208 }
209
210 cecr_subblock =
211 ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num);
212 qe_issue_cmd(QE_RESTART_RX, cecr_subblock,
213 (u8)QE_CR_PROTOCOL_ETHERNET, 0);
214
215 uec->grace_stopped_rx = 0;
216
217 return 0;
218}
219
220static int uec_open(uec_private_t *uec, comm_dir_e mode)
221{
222 ucc_fast_private_t *uccf;
223
224 if (!uec || !uec->uccf) {
225 printf("%s: No handle passed.\n", __FUNCTION__);
226 return -EINVAL;
227 }
228 uccf = uec->uccf;
229
230 /* check if the UCC number is in range. */
231 if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) {
232 printf("%s: ucc_num out of range.\n", __FUNCTION__);
233 return -EINVAL;
234 }
235
236 /* Enable MAC */
237 uec_mac_enable(uec, mode);
238
239 /* Enable UCC fast */
240 ucc_fast_enable(uccf, mode);
241
242 /* RISC microcode start */
243 if ((mode & COMM_DIR_TX) && uec->grace_stopped_tx) {
244 uec_restart_tx(uec);
245 }
246 if ((mode & COMM_DIR_RX) && uec->grace_stopped_rx) {
247 uec_restart_rx(uec);
248 }
249
250 return 0;
251}
252
253static int uec_stop(uec_private_t *uec, comm_dir_e mode)
254{
Dave Liu7737d5c2006-11-03 12:11:15 -0600255 if (!uec || !uec->uccf) {
256 printf("%s: No handle passed.\n", __FUNCTION__);
257 return -EINVAL;
258 }
Dave Liu7737d5c2006-11-03 12:11:15 -0600259
260 /* check if the UCC number is in range. */
261 if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) {
262 printf("%s: ucc_num out of range.\n", __FUNCTION__);
263 return -EINVAL;
264 }
265 /* Stop any transmissions */
266 if ((mode & COMM_DIR_TX) && !uec->grace_stopped_tx) {
267 uec_graceful_stop_tx(uec);
268 }
269 /* Stop any receptions */
270 if ((mode & COMM_DIR_RX) && !uec->grace_stopped_rx) {
271 uec_graceful_stop_rx(uec);
272 }
273
274 /* Disable the UCC fast */
275 ucc_fast_disable(uec->uccf, mode);
276
277 /* Disable the MAC */
278 uec_mac_disable(uec, mode);
279
280 return 0;
281}
282
283static int uec_set_mac_duplex(uec_private_t *uec, int duplex)
284{
285 uec_t *uec_regs;
286 u32 maccfg2;
287
288 if (!uec) {
289 printf("%s: uec not initial\n", __FUNCTION__);
290 return -EINVAL;
291 }
292 uec_regs = uec->uec_regs;
293
294 if (duplex == DUPLEX_HALF) {
295 maccfg2 = in_be32(&uec_regs->maccfg2);
296 maccfg2 &= ~MACCFG2_FDX;
297 out_be32(&uec_regs->maccfg2, maccfg2);
298 }
299
300 if (duplex == DUPLEX_FULL) {
301 maccfg2 = in_be32(&uec_regs->maccfg2);
302 maccfg2 |= MACCFG2_FDX;
303 out_be32(&uec_regs->maccfg2, maccfg2);
304 }
305
306 return 0;
307}
308
Heiko Schocher582c55a2010-01-20 09:04:28 +0100309static int uec_set_mac_if_mode(uec_private_t *uec,
Andy Fleming865ff852011-04-13 00:37:12 -0500310 phy_interface_t if_mode, int speed)
Dave Liu7737d5c2006-11-03 12:11:15 -0600311{
Andy Fleming865ff852011-04-13 00:37:12 -0500312 phy_interface_t enet_if_mode;
Dave Liu7737d5c2006-11-03 12:11:15 -0600313 uec_t *uec_regs;
314 u32 upsmr;
315 u32 maccfg2;
316
317 if (!uec) {
318 printf("%s: uec not initial\n", __FUNCTION__);
319 return -EINVAL;
320 }
321
Dave Liu7737d5c2006-11-03 12:11:15 -0600322 uec_regs = uec->uec_regs;
323 enet_if_mode = if_mode;
324
325 maccfg2 = in_be32(&uec_regs->maccfg2);
326 maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
327
328 upsmr = in_be32(&uec->uccf->uf_regs->upsmr);
329 upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM);
330
Heiko Schocher582c55a2010-01-20 09:04:28 +0100331 switch (speed) {
Andy Fleming865ff852011-04-13 00:37:12 -0500332 case SPEED_10:
Dave Liu7737d5c2006-11-03 12:11:15 -0600333 maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
Heiko Schocher582c55a2010-01-20 09:04:28 +0100334 switch (enet_if_mode) {
Andy Fleming865ff852011-04-13 00:37:12 -0500335 case PHY_INTERFACE_MODE_MII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100336 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500337 case PHY_INTERFACE_MODE_RGMII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100338 upsmr |= (UPSMR_RPM | UPSMR_R10M);
339 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500340 case PHY_INTERFACE_MODE_RMII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100341 upsmr |= (UPSMR_R10M | UPSMR_RMM);
342 break;
343 default:
344 return -EINVAL;
345 break;
346 }
Dave Liu7737d5c2006-11-03 12:11:15 -0600347 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500348 case SPEED_100:
Dave Liu7737d5c2006-11-03 12:11:15 -0600349 maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
Heiko Schocher582c55a2010-01-20 09:04:28 +0100350 switch (enet_if_mode) {
Andy Fleming865ff852011-04-13 00:37:12 -0500351 case PHY_INTERFACE_MODE_MII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100352 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500353 case PHY_INTERFACE_MODE_RGMII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100354 upsmr |= UPSMR_RPM;
355 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500356 case PHY_INTERFACE_MODE_RMII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100357 upsmr |= UPSMR_RMM;
358 break;
359 default:
360 return -EINVAL;
361 break;
362 }
Dave Liu7737d5c2006-11-03 12:11:15 -0600363 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500364 case SPEED_1000:
Haiying Wange8efef72009-06-04 16:12:42 -0400365 maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
Heiko Schocher582c55a2010-01-20 09:04:28 +0100366 switch (enet_if_mode) {
Andy Fleming865ff852011-04-13 00:37:12 -0500367 case PHY_INTERFACE_MODE_GMII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100368 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500369 case PHY_INTERFACE_MODE_TBI:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100370 upsmr |= UPSMR_TBIM;
371 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500372 case PHY_INTERFACE_MODE_RTBI:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100373 upsmr |= (UPSMR_RPM | UPSMR_TBIM);
374 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500375 case PHY_INTERFACE_MODE_RGMII_RXID:
376 case PHY_INTERFACE_MODE_RGMII_TXID:
377 case PHY_INTERFACE_MODE_RGMII_ID:
378 case PHY_INTERFACE_MODE_RGMII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100379 upsmr |= UPSMR_RPM;
380 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500381 case PHY_INTERFACE_MODE_SGMII:
Heiko Schocher582c55a2010-01-20 09:04:28 +0100382 upsmr |= UPSMR_SGMM;
383 break;
384 default:
385 return -EINVAL;
386 break;
387 }
Haiying Wange8efef72009-06-04 16:12:42 -0400388 break;
Dave Liu7737d5c2006-11-03 12:11:15 -0600389 default:
390 return -EINVAL;
391 break;
392 }
Heiko Schocher582c55a2010-01-20 09:04:28 +0100393
Dave Liu7737d5c2006-11-03 12:11:15 -0600394 out_be32(&uec_regs->maccfg2, maccfg2);
395 out_be32(&uec->uccf->uf_regs->upsmr, upsmr);
396
397 return 0;
398}
399
Andy Flemingda9d4612007-08-14 00:14:25 -0500400static int init_mii_management_configuration(uec_mii_t *uec_mii_regs)
Dave Liu7737d5c2006-11-03 12:11:15 -0600401{
402 uint timeout = 0x1000;
403 u32 miimcfg = 0;
404
Andy Flemingda9d4612007-08-14 00:14:25 -0500405 miimcfg = in_be32(&uec_mii_regs->miimcfg);
Dave Liu7737d5c2006-11-03 12:11:15 -0600406 miimcfg |= MIIMCFG_MNGMNT_CLC_DIV_INIT_VALUE;
Andy Flemingda9d4612007-08-14 00:14:25 -0500407 out_be32(&uec_mii_regs->miimcfg, miimcfg);
Dave Liu7737d5c2006-11-03 12:11:15 -0600408
409 /* Wait until the bus is free */
Andy Flemingda9d4612007-08-14 00:14:25 -0500410 while ((in_be32(&uec_mii_regs->miimcfg) & MIIMIND_BUSY) && timeout--);
Dave Liu7737d5c2006-11-03 12:11:15 -0600411 if (timeout <= 0) {
412 printf("%s: The MII Bus is stuck!", __FUNCTION__);
413 return -ETIMEDOUT;
414 }
415
416 return 0;
417}
418
419static int init_phy(struct eth_device *dev)
420{
421 uec_private_t *uec;
Andy Flemingda9d4612007-08-14 00:14:25 -0500422 uec_mii_t *umii_regs;
Dave Liu7737d5c2006-11-03 12:11:15 -0600423 struct uec_mii_info *mii_info;
424 struct phy_info *curphy;
425 int err;
426
427 uec = (uec_private_t *)dev->priv;
Andy Flemingda9d4612007-08-14 00:14:25 -0500428 umii_regs = uec->uec_mii_regs;
Dave Liu7737d5c2006-11-03 12:11:15 -0600429
430 uec->oldlink = 0;
431 uec->oldspeed = 0;
432 uec->oldduplex = -1;
433
434 mii_info = malloc(sizeof(*mii_info));
435 if (!mii_info) {
436 printf("%s: Could not allocate mii_info", dev->name);
437 return -ENOMEM;
438 }
439 memset(mii_info, 0, sizeof(*mii_info));
440
Dave Liu24c3aca2006-12-07 21:13:15 +0800441 if (uec->uec_info->uf_info.eth_type == GIGA_ETH) {
442 mii_info->speed = SPEED_1000;
443 } else {
444 mii_info->speed = SPEED_100;
445 }
446
Dave Liu7737d5c2006-11-03 12:11:15 -0600447 mii_info->duplex = DUPLEX_FULL;
448 mii_info->pause = 0;
449 mii_info->link = 1;
450
451 mii_info->advertising = (ADVERTISED_10baseT_Half |
452 ADVERTISED_10baseT_Full |
453 ADVERTISED_100baseT_Half |
454 ADVERTISED_100baseT_Full |
455 ADVERTISED_1000baseT_Full);
456 mii_info->autoneg = 1;
457 mii_info->mii_id = uec->uec_info->phy_address;
458 mii_info->dev = dev;
459
Andy Flemingda9d4612007-08-14 00:14:25 -0500460 mii_info->mdio_read = &uec_read_phy_reg;
461 mii_info->mdio_write = &uec_write_phy_reg;
Dave Liu7737d5c2006-11-03 12:11:15 -0600462
463 uec->mii_info = mii_info;
464
Kim Phillipsee62ed32008-01-15 14:11:00 -0600465 qe_set_mii_clk_src(uec->uec_info->uf_info.ucc_num);
466
Andy Flemingda9d4612007-08-14 00:14:25 -0500467 if (init_mii_management_configuration(umii_regs)) {
Dave Liu7737d5c2006-11-03 12:11:15 -0600468 printf("%s: The MII Bus is stuck!", dev->name);
469 err = -1;
470 goto bus_fail;
471 }
472
473 /* get info for this PHY */
Andy Flemingda9d4612007-08-14 00:14:25 -0500474 curphy = uec_get_phy_info(uec->mii_info);
Dave Liu7737d5c2006-11-03 12:11:15 -0600475 if (!curphy) {
476 printf("%s: No PHY found", dev->name);
477 err = -1;
478 goto no_phy;
479 }
480
481 mii_info->phyinfo = curphy;
482
483 /* Run the commands which initialize the PHY */
484 if (curphy->init) {
485 err = curphy->init(uec->mii_info);
486 if (err)
487 goto phy_init_fail;
488 }
489
490 return 0;
491
492phy_init_fail:
493no_phy:
494bus_fail:
495 free(mii_info);
496 return err;
497}
498
499static void adjust_link(struct eth_device *dev)
500{
501 uec_private_t *uec = (uec_private_t *)dev->priv;
Dave Liu7737d5c2006-11-03 12:11:15 -0600502 struct uec_mii_info *mii_info = uec->mii_info;
503
504 extern void change_phy_interface_mode(struct eth_device *dev,
Andy Fleming865ff852011-04-13 00:37:12 -0500505 phy_interface_t mode, int speed);
Dave Liu7737d5c2006-11-03 12:11:15 -0600506
507 if (mii_info->link) {
508 /* Now we make sure that we can be in full duplex mode.
509 * If not, we operate in half-duplex mode. */
510 if (mii_info->duplex != uec->oldduplex) {
511 if (!(mii_info->duplex)) {
512 uec_set_mac_duplex(uec, DUPLEX_HALF);
513 printf("%s: Half Duplex\n", dev->name);
514 } else {
515 uec_set_mac_duplex(uec, DUPLEX_FULL);
516 printf("%s: Full Duplex\n", dev->name);
517 }
518 uec->oldduplex = mii_info->duplex;
519 }
520
521 if (mii_info->speed != uec->oldspeed) {
Andy Fleming865ff852011-04-13 00:37:12 -0500522 phy_interface_t mode =
Heiko Schocher582c55a2010-01-20 09:04:28 +0100523 uec->uec_info->enet_interface_type;
Dave Liu24c3aca2006-12-07 21:13:15 +0800524 if (uec->uec_info->uf_info.eth_type == GIGA_ETH) {
525 switch (mii_info->speed) {
Andy Fleming865ff852011-04-13 00:37:12 -0500526 case SPEED_1000:
Dave Liu7737d5c2006-11-03 12:11:15 -0600527 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500528 case SPEED_100:
Dave Liu7737d5c2006-11-03 12:11:15 -0600529 printf ("switching to rgmii 100\n");
Andy Fleming865ff852011-04-13 00:37:12 -0500530 mode = PHY_INTERFACE_MODE_RGMII;
Dave Liu7737d5c2006-11-03 12:11:15 -0600531 break;
Andy Fleming865ff852011-04-13 00:37:12 -0500532 case SPEED_10:
Dave Liu7737d5c2006-11-03 12:11:15 -0600533 printf ("switching to rgmii 10\n");
Andy Fleming865ff852011-04-13 00:37:12 -0500534 mode = PHY_INTERFACE_MODE_RGMII;
Dave Liu7737d5c2006-11-03 12:11:15 -0600535 break;
536 default:
537 printf("%s: Ack,Speed(%d)is illegal\n",
538 dev->name, mii_info->speed);
539 break;
Dave Liu24c3aca2006-12-07 21:13:15 +0800540 }
Dave Liu7737d5c2006-11-03 12:11:15 -0600541 }
542
Heiko Schocher582c55a2010-01-20 09:04:28 +0100543 /* change phy */
544 change_phy_interface_mode(dev, mode, mii_info->speed);
545 /* change the MAC interface mode */
546 uec_set_mac_if_mode(uec, mode, mii_info->speed);
547
Dave Liu7737d5c2006-11-03 12:11:15 -0600548 printf("%s: Speed %dBT\n", dev->name, mii_info->speed);
549 uec->oldspeed = mii_info->speed;
550 }
551
552 if (!uec->oldlink) {
553 printf("%s: Link is up\n", dev->name);
554 uec->oldlink = 1;
555 }
556
557 } else { /* if (mii_info->link) */
558 if (uec->oldlink) {
559 printf("%s: Link is down\n", dev->name);
560 uec->oldlink = 0;
561 uec->oldspeed = 0;
562 uec->oldduplex = -1;
563 }
564 }
565}
566
567static void phy_change(struct eth_device *dev)
568{
569 uec_private_t *uec = (uec_private_t *)dev->priv;
Dave Liu7737d5c2006-11-03 12:11:15 -0600570
York Sun4167a672016-11-18 11:05:38 -0800571#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
Haiying Wanga52d2f82011-02-11 01:25:30 -0600572 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
573
574 /* QE9 and QE12 need to be set for enabling QE MII managment signals */
575 setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9);
576 setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
577#endif
578
Dave Liu7737d5c2006-11-03 12:11:15 -0600579 /* Update the link, speed, duplex */
Kim Phillipsee62ed32008-01-15 14:11:00 -0600580 uec->mii_info->phyinfo->read_status(uec->mii_info);
Dave Liu7737d5c2006-11-03 12:11:15 -0600581
York Sun4167a672016-11-18 11:05:38 -0800582#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
Haiying Wanga52d2f82011-02-11 01:25:30 -0600583 /*
584 * QE12 is muxed with LBCTL, it needs to be released for enabling
585 * LBCTL signal for LBC usage.
586 */
587 clrbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
588#endif
589
Dave Liu7737d5c2006-11-03 12:11:15 -0600590 /* Adjust the interface according to speed */
Kim Phillipsee62ed32008-01-15 14:11:00 -0600591 adjust_link(dev);
Dave Liu7737d5c2006-11-03 12:11:15 -0600592}
593
Richard Retanubun23c34af2009-06-17 16:00:41 -0400594#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
Ben Warrend9d78ee2008-08-07 23:26:35 -0700595
596/*
richardretanubun0115b192008-09-26 08:59:12 -0400597 * Find a device index from the devlist by name
598 *
599 * Returns:
600 * The index where the device is located, -1 on error
601 */
Mike Frysinger5700bb62010-07-27 18:35:08 -0400602static int uec_miiphy_find_dev_by_name(const char *devname)
richardretanubun0115b192008-09-26 08:59:12 -0400603{
604 int i;
605
606 for (i = 0; i < MAXCONTROLLERS; i++) {
607 if (strncmp(devname, devlist[i]->name, strlen(devname)) == 0) {
608 break;
609 }
610 }
611
612 /* If device cannot be found, returns -1 */
613 if (i == MAXCONTROLLERS) {
614 debug ("%s: device %s not found in devlist\n", __FUNCTION__, devname);
615 i = -1;
616 }
617
618 return i;
619}
620
621/*
Ben Warrend9d78ee2008-08-07 23:26:35 -0700622 * Read a MII PHY register.
623 *
624 * Returns:
625 * 0 on success
626 */
Joe Hershberger5a49f172016-08-08 11:28:38 -0500627static int uec_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
Ben Warrend9d78ee2008-08-07 23:26:35 -0700628{
Joe Hershberger5a49f172016-08-08 11:28:38 -0500629 unsigned short value = 0;
richardretanubun0115b192008-09-26 08:59:12 -0400630 int devindex = 0;
Ben Warrend9d78ee2008-08-07 23:26:35 -0700631
Joe Hershberger875e0bc2016-08-08 11:28:40 -0500632 if (bus->name == NULL) {
richardretanubun0115b192008-09-26 08:59:12 -0400633 debug("%s: NULL pointer given\n", __FUNCTION__);
634 } else {
Joe Hershberger5a49f172016-08-08 11:28:38 -0500635 devindex = uec_miiphy_find_dev_by_name(bus->name);
richardretanubun0115b192008-09-26 08:59:12 -0400636 if (devindex >= 0) {
Joe Hershberger5a49f172016-08-08 11:28:38 -0500637 value = uec_read_phy_reg(devlist[devindex], addr, reg);
richardretanubun0115b192008-09-26 08:59:12 -0400638 }
639 }
Joe Hershberger5a49f172016-08-08 11:28:38 -0500640 return value;
Ben Warrend9d78ee2008-08-07 23:26:35 -0700641}
642
643/*
644 * Write a MII PHY register.
645 *
646 * Returns:
647 * 0 on success
648 */
Joe Hershberger5a49f172016-08-08 11:28:38 -0500649static int uec_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
650 u16 value)
Ben Warrend9d78ee2008-08-07 23:26:35 -0700651{
richardretanubun0115b192008-09-26 08:59:12 -0400652 int devindex = 0;
Ben Warrend9d78ee2008-08-07 23:26:35 -0700653
Joe Hershberger5a49f172016-08-08 11:28:38 -0500654 if (bus->name == NULL) {
richardretanubun0115b192008-09-26 08:59:12 -0400655 debug("%s: NULL pointer given\n", __FUNCTION__);
656 } else {
Joe Hershberger5a49f172016-08-08 11:28:38 -0500657 devindex = uec_miiphy_find_dev_by_name(bus->name);
richardretanubun0115b192008-09-26 08:59:12 -0400658 if (devindex >= 0) {
659 uec_write_phy_reg(devlist[devindex], addr, reg, value);
660 }
661 }
Ben Warrend9d78ee2008-08-07 23:26:35 -0700662 return 0;
663}
Ben Warrend9d78ee2008-08-07 23:26:35 -0700664#endif
665
Dave Liu7737d5c2006-11-03 12:11:15 -0600666static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr)
667{
668 uec_t *uec_regs;
669 u32 mac_addr1;
670 u32 mac_addr2;
671
672 if (!uec) {
673 printf("%s: uec not initial\n", __FUNCTION__);
674 return -EINVAL;
675 }
676
677 uec_regs = uec->uec_regs;
678
679 /* if a station address of 0x12345678ABCD, perform a write to
680 MACSTNADDR1 of 0xCDAB7856,
681 MACSTNADDR2 of 0x34120000 */
682
683 mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) | \
684 (mac_addr[3] << 8) | (mac_addr[2]);
685 out_be32(&uec_regs->macstnaddr1, mac_addr1);
686
687 mac_addr2 = ((mac_addr[1] << 24) | (mac_addr[0] << 16)) & 0xffff0000;
688 out_be32(&uec_regs->macstnaddr2, mac_addr2);
689
690 return 0;
691}
692
693static int uec_convert_threads_num(uec_num_of_threads_e threads_num,
694 int *threads_num_ret)
695{
696 int num_threads_numerica;
697
698 switch (threads_num) {
699 case UEC_NUM_OF_THREADS_1:
700 num_threads_numerica = 1;
701 break;
702 case UEC_NUM_OF_THREADS_2:
703 num_threads_numerica = 2;
704 break;
705 case UEC_NUM_OF_THREADS_4:
706 num_threads_numerica = 4;
707 break;
708 case UEC_NUM_OF_THREADS_6:
709 num_threads_numerica = 6;
710 break;
711 case UEC_NUM_OF_THREADS_8:
712 num_threads_numerica = 8;
713 break;
714 default:
715 printf("%s: Bad number of threads value.",
716 __FUNCTION__);
717 return -EINVAL;
718 }
719
720 *threads_num_ret = num_threads_numerica;
721
722 return 0;
723}
724
725static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx)
726{
727 uec_info_t *uec_info;
728 u32 end_bd;
729 u8 bmrx = 0;
730 int i;
731
732 uec_info = uec->uec_info;
733
734 /* Alloc global Tx parameter RAM page */
735 uec->tx_glbl_pram_offset = qe_muram_alloc(
736 sizeof(uec_tx_global_pram_t),
737 UEC_TX_GLOBAL_PRAM_ALIGNMENT);
738 uec->p_tx_glbl_pram = (uec_tx_global_pram_t *)
739 qe_muram_addr(uec->tx_glbl_pram_offset);
740
741 /* Zero the global Tx prameter RAM */
742 memset(uec->p_tx_glbl_pram, 0, sizeof(uec_tx_global_pram_t));
743
744 /* Init global Tx parameter RAM */
745
746 /* TEMODER, RMON statistics disable, one Tx queue */
747 out_be16(&uec->p_tx_glbl_pram->temoder, TEMODER_INIT_VALUE);
748
749 /* SQPTR */
750 uec->send_q_mem_reg_offset = qe_muram_alloc(
751 sizeof(uec_send_queue_qd_t),
752 UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
753 uec->p_send_q_mem_reg = (uec_send_queue_mem_region_t *)
754 qe_muram_addr(uec->send_q_mem_reg_offset);
755 out_be32(&uec->p_tx_glbl_pram->sqptr, uec->send_q_mem_reg_offset);
756
757 /* Setup the table with TxBDs ring */
758 end_bd = (u32)uec->p_tx_bd_ring + (uec_info->tx_bd_ring_len - 1)
759 * SIZEOFBD;
760 out_be32(&uec->p_send_q_mem_reg->sqqd[0].bd_ring_base,
761 (u32)(uec->p_tx_bd_ring));
762 out_be32(&uec->p_send_q_mem_reg->sqqd[0].last_bd_completed_address,
763 end_bd);
764
765 /* Scheduler Base Pointer, we have only one Tx queue, no need it */
766 out_be32(&uec->p_tx_glbl_pram->schedulerbasepointer, 0);
767
768 /* TxRMON Base Pointer, TxRMON disable, we don't need it */
769 out_be32(&uec->p_tx_glbl_pram->txrmonbaseptr, 0);
770
771 /* TSTATE, global snooping, big endian, the CSB bus selected */
772 bmrx = BMR_INIT_VALUE;
773 out_be32(&uec->p_tx_glbl_pram->tstate, ((u32)(bmrx) << BMR_SHIFT));
774
775 /* IPH_Offset */
776 for (i = 0; i < MAX_IPH_OFFSET_ENTRY; i++) {
777 out_8(&uec->p_tx_glbl_pram->iphoffset[i], 0);
778 }
779
780 /* VTAG table */
781 for (i = 0; i < UEC_TX_VTAG_TABLE_ENTRY_MAX; i++) {
782 out_be32(&uec->p_tx_glbl_pram->vtagtable[i], 0);
783 }
784
785 /* TQPTR */
786 uec->thread_dat_tx_offset = qe_muram_alloc(
787 num_threads_tx * sizeof(uec_thread_data_tx_t) +
788 32 *(num_threads_tx == 1), UEC_THREAD_DATA_ALIGNMENT);
789
790 uec->p_thread_data_tx = (uec_thread_data_tx_t *)
791 qe_muram_addr(uec->thread_dat_tx_offset);
792 out_be32(&uec->p_tx_glbl_pram->tqptr, uec->thread_dat_tx_offset);
793}
794
795static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx)
796{
797 u8 bmrx = 0;
798 int i;
799 uec_82xx_address_filtering_pram_t *p_af_pram;
800
801 /* Allocate global Rx parameter RAM page */
802 uec->rx_glbl_pram_offset = qe_muram_alloc(
803 sizeof(uec_rx_global_pram_t), UEC_RX_GLOBAL_PRAM_ALIGNMENT);
804 uec->p_rx_glbl_pram = (uec_rx_global_pram_t *)
805 qe_muram_addr(uec->rx_glbl_pram_offset);
806
807 /* Zero Global Rx parameter RAM */
808 memset(uec->p_rx_glbl_pram, 0, sizeof(uec_rx_global_pram_t));
809
810 /* Init global Rx parameter RAM */
811 /* REMODER, Extended feature mode disable, VLAN disable,
812 LossLess flow control disable, Receive firmware statisic disable,
813 Extended address parsing mode disable, One Rx queues,
814 Dynamic maximum/minimum frame length disable, IP checksum check
815 disable, IP address alignment disable
816 */
817 out_be32(&uec->p_rx_glbl_pram->remoder, REMODER_INIT_VALUE);
818
819 /* RQPTR */
820 uec->thread_dat_rx_offset = qe_muram_alloc(
821 num_threads_rx * sizeof(uec_thread_data_rx_t),
822 UEC_THREAD_DATA_ALIGNMENT);
823 uec->p_thread_data_rx = (uec_thread_data_rx_t *)
824 qe_muram_addr(uec->thread_dat_rx_offset);
825 out_be32(&uec->p_rx_glbl_pram->rqptr, uec->thread_dat_rx_offset);
826
827 /* Type_or_Len */
828 out_be16(&uec->p_rx_glbl_pram->typeorlen, 3072);
829
830 /* RxRMON base pointer, we don't need it */
831 out_be32(&uec->p_rx_glbl_pram->rxrmonbaseptr, 0);
832
833 /* IntCoalescingPTR, we don't need it, no interrupt */
834 out_be32(&uec->p_rx_glbl_pram->intcoalescingptr, 0);
835
836 /* RSTATE, global snooping, big endian, the CSB bus selected */
837 bmrx = BMR_INIT_VALUE;
838 out_8(&uec->p_rx_glbl_pram->rstate, bmrx);
839
840 /* MRBLR */
841 out_be16(&uec->p_rx_glbl_pram->mrblr, MAX_RXBUF_LEN);
842
843 /* RBDQPTR */
844 uec->rx_bd_qs_tbl_offset = qe_muram_alloc(
845 sizeof(uec_rx_bd_queues_entry_t) + \
846 sizeof(uec_rx_prefetched_bds_t),
847 UEC_RX_BD_QUEUES_ALIGNMENT);
848 uec->p_rx_bd_qs_tbl = (uec_rx_bd_queues_entry_t *)
849 qe_muram_addr(uec->rx_bd_qs_tbl_offset);
850
851 /* Zero it */
852 memset(uec->p_rx_bd_qs_tbl, 0, sizeof(uec_rx_bd_queues_entry_t) + \
853 sizeof(uec_rx_prefetched_bds_t));
854 out_be32(&uec->p_rx_glbl_pram->rbdqptr, uec->rx_bd_qs_tbl_offset);
855 out_be32(&uec->p_rx_bd_qs_tbl->externalbdbaseptr,
856 (u32)uec->p_rx_bd_ring);
857
858 /* MFLR */
859 out_be16(&uec->p_rx_glbl_pram->mflr, MAX_FRAME_LEN);
860 /* MINFLR */
861 out_be16(&uec->p_rx_glbl_pram->minflr, MIN_FRAME_LEN);
862 /* MAXD1 */
863 out_be16(&uec->p_rx_glbl_pram->maxd1, MAX_DMA1_LEN);
864 /* MAXD2 */
865 out_be16(&uec->p_rx_glbl_pram->maxd2, MAX_DMA2_LEN);
866 /* ECAM_PTR */
867 out_be32(&uec->p_rx_glbl_pram->ecamptr, 0);
868 /* L2QT */
869 out_be32(&uec->p_rx_glbl_pram->l2qt, 0);
870 /* L3QT */
871 for (i = 0; i < 8; i++) {
872 out_be32(&uec->p_rx_glbl_pram->l3qt[i], 0);
873 }
874
875 /* VLAN_TYPE */
876 out_be16(&uec->p_rx_glbl_pram->vlantype, 0x8100);
877 /* TCI */
878 out_be16(&uec->p_rx_glbl_pram->vlantci, 0);
879
880 /* Clear PQ2 style address filtering hash table */
881 p_af_pram = (uec_82xx_address_filtering_pram_t *) \
882 uec->p_rx_glbl_pram->addressfiltering;
883
884 p_af_pram->iaddr_h = 0;
885 p_af_pram->iaddr_l = 0;
886 p_af_pram->gaddr_h = 0;
887 p_af_pram->gaddr_l = 0;
888}
889
890static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec,
891 int thread_tx, int thread_rx)
892{
893 uec_init_cmd_pram_t *p_init_enet_param;
894 u32 init_enet_param_offset;
895 uec_info_t *uec_info;
896 int i;
897 int snum;
898 u32 init_enet_offset;
899 u32 entry_val;
900 u32 command;
901 u32 cecr_subblock;
902
903 uec_info = uec->uec_info;
904
905 /* Allocate init enet command parameter */
906 uec->init_enet_param_offset = qe_muram_alloc(
907 sizeof(uec_init_cmd_pram_t), 4);
908 init_enet_param_offset = uec->init_enet_param_offset;
909 uec->p_init_enet_param = (uec_init_cmd_pram_t *)
910 qe_muram_addr(uec->init_enet_param_offset);
911
912 /* Zero init enet command struct */
913 memset((void *)uec->p_init_enet_param, 0, sizeof(uec_init_cmd_pram_t));
914
915 /* Init the command struct */
916 p_init_enet_param = uec->p_init_enet_param;
917 p_init_enet_param->resinit0 = ENET_INIT_PARAM_MAGIC_RES_INIT0;
918 p_init_enet_param->resinit1 = ENET_INIT_PARAM_MAGIC_RES_INIT1;
919 p_init_enet_param->resinit2 = ENET_INIT_PARAM_MAGIC_RES_INIT2;
920 p_init_enet_param->resinit3 = ENET_INIT_PARAM_MAGIC_RES_INIT3;
921 p_init_enet_param->resinit4 = ENET_INIT_PARAM_MAGIC_RES_INIT4;
922 p_init_enet_param->largestexternallookupkeysize = 0;
923
924 p_init_enet_param->rgftgfrxglobal |= ((u32)uec_info->num_threads_rx)
925 << ENET_INIT_PARAM_RGF_SHIFT;
926 p_init_enet_param->rgftgfrxglobal |= ((u32)uec_info->num_threads_tx)
927 << ENET_INIT_PARAM_TGF_SHIFT;
928
929 /* Init Rx global parameter pointer */
930 p_init_enet_param->rgftgfrxglobal |= uec->rx_glbl_pram_offset |
Haiying Wang52d6ad52009-05-21 15:32:13 -0400931 (u32)uec_info->risc_rx;
Dave Liu7737d5c2006-11-03 12:11:15 -0600932
933 /* Init Rx threads */
934 for (i = 0; i < (thread_rx + 1); i++) {
935 if ((snum = qe_get_snum()) < 0) {
936 printf("%s can not get snum\n", __FUNCTION__);
937 return -ENOMEM;
938 }
939
940 if (i==0) {
941 init_enet_offset = 0;
942 } else {
943 init_enet_offset = qe_muram_alloc(
944 sizeof(uec_thread_rx_pram_t),
945 UEC_THREAD_RX_PRAM_ALIGNMENT);
946 }
947
948 entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) |
Haiying Wang52d6ad52009-05-21 15:32:13 -0400949 init_enet_offset | (u32)uec_info->risc_rx;
Dave Liu7737d5c2006-11-03 12:11:15 -0600950 p_init_enet_param->rxthread[i] = entry_val;
951 }
952
953 /* Init Tx global parameter pointer */
954 p_init_enet_param->txglobal = uec->tx_glbl_pram_offset |
Haiying Wang52d6ad52009-05-21 15:32:13 -0400955 (u32)uec_info->risc_tx;
Dave Liu7737d5c2006-11-03 12:11:15 -0600956
957 /* Init Tx threads */
958 for (i = 0; i < thread_tx; i++) {
959 if ((snum = qe_get_snum()) < 0) {
960 printf("%s can not get snum\n", __FUNCTION__);
961 return -ENOMEM;
962 }
963
964 init_enet_offset = qe_muram_alloc(sizeof(uec_thread_tx_pram_t),
965 UEC_THREAD_TX_PRAM_ALIGNMENT);
966
967 entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) |
Haiying Wang52d6ad52009-05-21 15:32:13 -0400968 init_enet_offset | (u32)uec_info->risc_tx;
Dave Liu7737d5c2006-11-03 12:11:15 -0600969 p_init_enet_param->txthread[i] = entry_val;
970 }
971
972 __asm__ __volatile__("sync");
973
974 /* Issue QE command */
975 command = QE_INIT_TX_RX;
976 cecr_subblock = ucc_fast_get_qe_cr_subblock(
977 uec->uec_info->uf_info.ucc_num);
978 qe_issue_cmd(command, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET,
979 init_enet_param_offset);
980
981 return 0;
982}
983
984static int uec_startup(uec_private_t *uec)
985{
986 uec_info_t *uec_info;
987 ucc_fast_info_t *uf_info;
988 ucc_fast_private_t *uccf;
989 ucc_fast_t *uf_regs;
990 uec_t *uec_regs;
991 int num_threads_tx;
992 int num_threads_rx;
993 u32 utbipar;
Dave Liu7737d5c2006-11-03 12:11:15 -0600994 u32 length;
995 u32 align;
996 qe_bd_t *bd;
997 u8 *buf;
998 int i;
999
1000 if (!uec || !uec->uec_info) {
1001 printf("%s: uec or uec_info not initial\n", __FUNCTION__);
1002 return -EINVAL;
1003 }
1004
1005 uec_info = uec->uec_info;
1006 uf_info = &(uec_info->uf_info);
1007
1008 /* Check if Rx BD ring len is illegal */
1009 if ((uec_info->rx_bd_ring_len < UEC_RX_BD_RING_SIZE_MIN) || \
1010 (uec_info->rx_bd_ring_len % UEC_RX_BD_RING_SIZE_ALIGNMENT)) {
1011 printf("%s: Rx BD ring len must be multiple of 4, and > 8.\n",
1012 __FUNCTION__);
1013 return -EINVAL;
1014 }
1015
1016 /* Check if Tx BD ring len is illegal */
1017 if (uec_info->tx_bd_ring_len < UEC_TX_BD_RING_SIZE_MIN) {
1018 printf("%s: Tx BD ring length must not be smaller than 2.\n",
1019 __FUNCTION__);
1020 return -EINVAL;
1021 }
1022
1023 /* Check if MRBLR is illegal */
1024 if ((MAX_RXBUF_LEN == 0) || (MAX_RXBUF_LEN % UEC_MRBLR_ALIGNMENT)) {
1025 printf("%s: max rx buffer length must be mutliple of 128.\n",
1026 __FUNCTION__);
1027 return -EINVAL;
1028 }
1029
1030 /* Both Rx and Tx are stopped */
1031 uec->grace_stopped_rx = 1;
1032 uec->grace_stopped_tx = 1;
1033
1034 /* Init UCC fast */
1035 if (ucc_fast_init(uf_info, &uccf)) {
1036 printf("%s: failed to init ucc fast\n", __FUNCTION__);
1037 return -ENOMEM;
1038 }
1039
1040 /* Save uccf */
1041 uec->uccf = uccf;
1042
1043 /* Convert the Tx threads number */
1044 if (uec_convert_threads_num(uec_info->num_threads_tx,
1045 &num_threads_tx)) {
1046 return -EINVAL;
1047 }
1048
1049 /* Convert the Rx threads number */
1050 if (uec_convert_threads_num(uec_info->num_threads_rx,
1051 &num_threads_rx)) {
1052 return -EINVAL;
1053 }
1054
1055 uf_regs = uccf->uf_regs;
1056
1057 /* UEC register is following UCC fast registers */
1058 uec_regs = (uec_t *)(&uf_regs->ucc_eth);
1059
1060 /* Save the UEC register pointer to UEC private struct */
1061 uec->uec_regs = uec_regs;
1062
1063 /* Init UPSMR, enable hardware statistics (UCC) */
1064 out_be32(&uec->uccf->uf_regs->upsmr, UPSMR_INIT_VALUE);
1065
1066 /* Init MACCFG1, flow control disable, disable Tx and Rx */
1067 out_be32(&uec_regs->maccfg1, MACCFG1_INIT_VALUE);
1068
1069 /* Init MACCFG2, length check, MAC PAD and CRC enable */
1070 out_be32(&uec_regs->maccfg2, MACCFG2_INIT_VALUE);
1071
1072 /* Setup MAC interface mode */
Heiko Schocher582c55a2010-01-20 09:04:28 +01001073 uec_set_mac_if_mode(uec, uec_info->enet_interface_type, uec_info->speed);
Dave Liu7737d5c2006-11-03 12:11:15 -06001074
Andy Flemingda9d4612007-08-14 00:14:25 -05001075 /* Setup MII management base */
1076#ifndef CONFIG_eTSEC_MDIO_BUS
1077 uec->uec_mii_regs = (uec_mii_t *)(&uec_regs->miimcfg);
1078#else
1079 uec->uec_mii_regs = (uec_mii_t *) CONFIG_MIIM_ADDRESS;
1080#endif
1081
Dave Liu7737d5c2006-11-03 12:11:15 -06001082 /* Setup MII master clock source */
1083 qe_set_mii_clk_src(uec_info->uf_info.ucc_num);
1084
1085 /* Setup UTBIPAR */
1086 utbipar = in_be32(&uec_regs->utbipar);
1087 utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
Dave Liu7737d5c2006-11-03 12:11:15 -06001088
Richard Retanubun1a951932009-07-01 14:03:15 -04001089 /* Initialize UTBIPAR address to CONFIG_UTBIPAR_INIT_TBIPA for ALL UEC.
1090 * This frees up the remaining SMI addresses for use.
1091 */
1092 utbipar |= CONFIG_UTBIPAR_INIT_TBIPA << UTBIPAR_PHY_ADDRESS_SHIFT;
Dave Liu7737d5c2006-11-03 12:11:15 -06001093 out_be32(&uec_regs->utbipar, utbipar);
1094
Haiying Wange8efef72009-06-04 16:12:42 -04001095 /* Configure the TBI for SGMII operation */
Andy Fleming865ff852011-04-13 00:37:12 -05001096 if ((uec->uec_info->enet_interface_type == PHY_INTERFACE_MODE_SGMII) &&
1097 (uec->uec_info->speed == SPEED_1000)) {
Haiying Wange8efef72009-06-04 16:12:42 -04001098 uec_write_phy_reg(uec->dev, uec_regs->utbipar,
1099 ENET_TBI_MII_ANA, TBIANA_SETTINGS);
1100
1101 uec_write_phy_reg(uec->dev, uec_regs->utbipar,
1102 ENET_TBI_MII_TBICON, TBICON_CLK_SELECT);
1103
1104 uec_write_phy_reg(uec->dev, uec_regs->utbipar,
1105 ENET_TBI_MII_CR, TBICR_SETTINGS);
1106 }
1107
Dave Liu7737d5c2006-11-03 12:11:15 -06001108 /* Allocate Tx BDs */
1109 length = ((uec_info->tx_bd_ring_len * SIZEOFBD) /
1110 UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) *
1111 UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
1112 if ((uec_info->tx_bd_ring_len * SIZEOFBD) %
1113 UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) {
1114 length += UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
1115 }
1116
1117 align = UEC_TX_BD_RING_ALIGNMENT;
1118 uec->tx_bd_ring_offset = (u32)malloc((u32)(length + align));
1119 if (uec->tx_bd_ring_offset != 0) {
1120 uec->p_tx_bd_ring = (u8 *)((uec->tx_bd_ring_offset + align)
1121 & ~(align - 1));
1122 }
1123
1124 /* Zero all of Tx BDs */
1125 memset((void *)(uec->tx_bd_ring_offset), 0, length + align);
1126
1127 /* Allocate Rx BDs */
1128 length = uec_info->rx_bd_ring_len * SIZEOFBD;
1129 align = UEC_RX_BD_RING_ALIGNMENT;
1130 uec->rx_bd_ring_offset = (u32)(malloc((u32)(length + align)));
1131 if (uec->rx_bd_ring_offset != 0) {
1132 uec->p_rx_bd_ring = (u8 *)((uec->rx_bd_ring_offset + align)
1133 & ~(align - 1));
1134 }
1135
1136 /* Zero all of Rx BDs */
1137 memset((void *)(uec->rx_bd_ring_offset), 0, length + align);
1138
1139 /* Allocate Rx buffer */
1140 length = uec_info->rx_bd_ring_len * MAX_RXBUF_LEN;
1141 align = UEC_RX_DATA_BUF_ALIGNMENT;
1142 uec->rx_buf_offset = (u32)malloc(length + align);
1143 if (uec->rx_buf_offset != 0) {
1144 uec->p_rx_buf = (u8 *)((uec->rx_buf_offset + align)
1145 & ~(align - 1));
1146 }
1147
1148 /* Zero all of the Rx buffer */
1149 memset((void *)(uec->rx_buf_offset), 0, length + align);
1150
1151 /* Init TxBD ring */
1152 bd = (qe_bd_t *)uec->p_tx_bd_ring;
1153 uec->txBd = bd;
1154
1155 for (i = 0; i < uec_info->tx_bd_ring_len; i++) {
1156 BD_DATA_CLEAR(bd);
1157 BD_STATUS_SET(bd, 0);
1158 BD_LENGTH_SET(bd, 0);
1159 bd ++;
1160 }
1161 BD_STATUS_SET((--bd), TxBD_WRAP);
1162
1163 /* Init RxBD ring */
1164 bd = (qe_bd_t *)uec->p_rx_bd_ring;
1165 uec->rxBd = bd;
1166 buf = uec->p_rx_buf;
1167 for (i = 0; i < uec_info->rx_bd_ring_len; i++) {
1168 BD_DATA_SET(bd, buf);
1169 BD_LENGTH_SET(bd, 0);
1170 BD_STATUS_SET(bd, RxBD_EMPTY);
1171 buf += MAX_RXBUF_LEN;
1172 bd ++;
1173 }
1174 BD_STATUS_SET((--bd), RxBD_WRAP | RxBD_EMPTY);
1175
1176 /* Init global Tx parameter RAM */
1177 uec_init_tx_parameter(uec, num_threads_tx);
1178
1179 /* Init global Rx parameter RAM */
1180 uec_init_rx_parameter(uec, num_threads_rx);
1181
1182 /* Init ethernet Tx and Rx parameter command */
1183 if (uec_issue_init_enet_rxtx_cmd(uec, num_threads_tx,
1184 num_threads_rx)) {
1185 printf("%s issue init enet cmd failed\n", __FUNCTION__);
1186 return -ENOMEM;
1187 }
1188
1189 return 0;
1190}
1191
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +09001192static int uec_init(struct eth_device* dev, struct bd_info *bd)
Dave Liu7737d5c2006-11-03 12:11:15 -06001193{
1194 uec_private_t *uec;
Kim Phillipsee62ed32008-01-15 14:11:00 -06001195 int err, i;
1196 struct phy_info *curphy;
York Sun4167a672016-11-18 11:05:38 -08001197#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
Haiying Wanga52d2f82011-02-11 01:25:30 -06001198 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
1199#endif
Dave Liu7737d5c2006-11-03 12:11:15 -06001200
1201 uec = (uec_private_t *)dev->priv;
1202
1203 if (uec->the_first_run == 0) {
York Sun4167a672016-11-18 11:05:38 -08001204#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
Haiying Wanga52d2f82011-02-11 01:25:30 -06001205 /* QE9 and QE12 need to be set for enabling QE MII managment signals */
1206 setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9);
1207 setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
1208#endif
1209
Kim Phillipsee62ed32008-01-15 14:11:00 -06001210 err = init_phy(dev);
1211 if (err) {
1212 printf("%s: Cannot initialize PHY, aborting.\n",
1213 dev->name);
1214 return err;
Dave Liu7737d5c2006-11-03 12:11:15 -06001215 }
Kim Phillipsee62ed32008-01-15 14:11:00 -06001216
1217 curphy = uec->mii_info->phyinfo;
1218
1219 if (curphy->config_aneg) {
1220 err = curphy->config_aneg(uec->mii_info);
1221 if (err) {
1222 printf("%s: Can't negotiate PHY\n", dev->name);
1223 return err;
1224 }
1225 }
1226
1227 /* Give PHYs up to 5 sec to report a link */
1228 i = 50;
1229 do {
1230 err = curphy->read_status(uec->mii_info);
Joakim Tjernlundbd6c25a2010-08-11 11:44:21 +02001231 if (!(((i-- > 0) && !uec->mii_info->link) || err))
1232 break;
Kim Phillipsee62ed32008-01-15 14:11:00 -06001233 udelay(100000);
Joakim Tjernlundbd6c25a2010-08-11 11:44:21 +02001234 } while (1);
Kim Phillipsee62ed32008-01-15 14:11:00 -06001235
York Sun4167a672016-11-18 11:05:38 -08001236#if defined(CONFIG_ARCH_P1021) || defined(CONFIG_ARCH_P1025)
Haiying Wanga52d2f82011-02-11 01:25:30 -06001237 /* QE12 needs to be released for enabling LBCTL signal*/
1238 clrbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
1239#endif
1240
Kim Phillipsee62ed32008-01-15 14:11:00 -06001241 if (err || i <= 0)
1242 printf("warning: %s: timeout on PHY link\n", dev->name);
1243
Heiko Schocher582c55a2010-01-20 09:04:28 +01001244 adjust_link(dev);
Dave Liu7737d5c2006-11-03 12:11:15 -06001245 uec->the_first_run = 1;
1246 }
1247
Kim Phillipsee62ed32008-01-15 14:11:00 -06001248 /* Set up the MAC address */
1249 if (dev->enetaddr[0] & 0x01) {
1250 printf("%s: MacAddress is multcast address\n",
1251 __FUNCTION__);
1252 return -1;
1253 }
1254 uec_set_mac_address(uec, dev->enetaddr);
1255
1256
Dave Liu7737d5c2006-11-03 12:11:15 -06001257 err = uec_open(uec, COMM_DIR_RX_AND_TX);
1258 if (err) {
1259 printf("%s: cannot enable UEC device\n", dev->name);
Ben Warren422b1a02008-01-09 18:15:53 -05001260 return -1;
Dave Liu7737d5c2006-11-03 12:11:15 -06001261 }
1262
Kim Phillipsee62ed32008-01-15 14:11:00 -06001263 phy_change(dev);
1264
Ben Warren422b1a02008-01-09 18:15:53 -05001265 return (uec->mii_info->link ? 0 : -1);
Dave Liu7737d5c2006-11-03 12:11:15 -06001266}
1267
1268static void uec_halt(struct eth_device* dev)
1269{
1270 uec_private_t *uec = (uec_private_t *)dev->priv;
1271 uec_stop(uec, COMM_DIR_RX_AND_TX);
1272}
1273
Joe Hershberger7ae84d52012-05-22 07:56:21 +00001274static int uec_send(struct eth_device *dev, void *buf, int len)
Dave Liu7737d5c2006-11-03 12:11:15 -06001275{
1276 uec_private_t *uec;
1277 ucc_fast_private_t *uccf;
1278 volatile qe_bd_t *bd;
Dave Liuddd02492006-12-06 11:38:17 +08001279 u16 status;
Dave Liu7737d5c2006-11-03 12:11:15 -06001280 int i;
1281 int result = 0;
1282
1283 uec = (uec_private_t *)dev->priv;
1284 uccf = uec->uccf;
1285 bd = uec->txBd;
1286
1287 /* Find an empty TxBD */
Dave Liuddd02492006-12-06 11:38:17 +08001288 for (i = 0; bd->status & TxBD_READY; i++) {
Dave Liu7737d5c2006-11-03 12:11:15 -06001289 if (i > 0x100000) {
1290 printf("%s: tx buffer not ready\n", dev->name);
1291 return result;
1292 }
1293 }
1294
1295 /* Init TxBD */
1296 BD_DATA_SET(bd, buf);
1297 BD_LENGTH_SET(bd, len);
Emilian Medvea28899c2007-01-30 16:14:50 -06001298 status = bd->status;
Dave Liu7737d5c2006-11-03 12:11:15 -06001299 status &= BD_WRAP;
1300 status |= (TxBD_READY | TxBD_LAST);
1301 BD_STATUS_SET(bd, status);
1302
1303 /* Tell UCC to transmit the buffer */
1304 ucc_fast_transmit_on_demand(uccf);
1305
1306 /* Wait for buffer to be transmitted */
Dave Liuddd02492006-12-06 11:38:17 +08001307 for (i = 0; bd->status & TxBD_READY; i++) {
Dave Liu7737d5c2006-11-03 12:11:15 -06001308 if (i > 0x100000) {
1309 printf("%s: tx error\n", dev->name);
1310 return result;
1311 }
Dave Liu7737d5c2006-11-03 12:11:15 -06001312 }
1313
1314 /* Ok, the buffer be transimitted */
1315 BD_ADVANCE(bd, status, uec->p_tx_bd_ring);
1316 uec->txBd = bd;
1317 result = 1;
1318
1319 return result;
1320}
1321
1322static int uec_recv(struct eth_device* dev)
1323{
1324 uec_private_t *uec = dev->priv;
1325 volatile qe_bd_t *bd;
Dave Liuddd02492006-12-06 11:38:17 +08001326 u16 status;
Dave Liu7737d5c2006-11-03 12:11:15 -06001327 u16 len;
1328 u8 *data;
1329
1330 bd = uec->rxBd;
Dave Liuddd02492006-12-06 11:38:17 +08001331 status = bd->status;
Dave Liu7737d5c2006-11-03 12:11:15 -06001332
1333 while (!(status & RxBD_EMPTY)) {
1334 if (!(status & RxBD_ERROR)) {
1335 data = BD_DATA(bd);
1336 len = BD_LENGTH(bd);
Joe Hershberger1fd92db2015-04-08 01:41:06 -05001337 net_process_received_packet(data, len);
Dave Liu7737d5c2006-11-03 12:11:15 -06001338 } else {
1339 printf("%s: Rx error\n", dev->name);
1340 }
1341 status &= BD_CLEAN;
1342 BD_LENGTH_SET(bd, 0);
1343 BD_STATUS_SET(bd, status | RxBD_EMPTY);
1344 BD_ADVANCE(bd, status, uec->p_rx_bd_ring);
Dave Liuddd02492006-12-06 11:38:17 +08001345 status = bd->status;
Dave Liu7737d5c2006-11-03 12:11:15 -06001346 }
1347 uec->rxBd = bd;
1348
1349 return 1;
1350}
1351
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +09001352int uec_initialize(struct bd_info *bis, uec_info_t *uec_info)
Dave Liu7737d5c2006-11-03 12:11:15 -06001353{
1354 struct eth_device *dev;
1355 int i;
1356 uec_private_t *uec;
Dave Liu7737d5c2006-11-03 12:11:15 -06001357 int err;
1358
1359 dev = (struct eth_device *)malloc(sizeof(struct eth_device));
1360 if (!dev)
1361 return 0;
1362 memset(dev, 0, sizeof(struct eth_device));
1363
1364 /* Allocate the UEC private struct */
1365 uec = (uec_private_t *)malloc(sizeof(uec_private_t));
1366 if (!uec) {
1367 return -ENOMEM;
1368 }
1369 memset(uec, 0, sizeof(uec_private_t));
1370
Haiying Wang8e552582009-06-04 16:12:41 -04001371 /* Adjust uec_info */
1372#if (MAX_QE_RISC == 4)
1373 uec_info->risc_tx = QE_RISC_ALLOCATION_FOUR_RISCS;
1374 uec_info->risc_rx = QE_RISC_ALLOCATION_FOUR_RISCS;
Dave Liu7737d5c2006-11-03 12:11:15 -06001375#endif
Dave Liu7737d5c2006-11-03 12:11:15 -06001376
Haiying Wang8e552582009-06-04 16:12:41 -04001377 devlist[uec_info->uf_info.ucc_num] = dev;
David Saadad5d28fe2008-03-31 02:37:38 -07001378
Dave Liu7737d5c2006-11-03 12:11:15 -06001379 uec->uec_info = uec_info;
Haiying Wange8efef72009-06-04 16:12:42 -04001380 uec->dev = dev;
Dave Liu7737d5c2006-11-03 12:11:15 -06001381
Kim Phillips78b7a8e2010-07-26 18:34:57 -05001382 sprintf(dev->name, "UEC%d", uec_info->uf_info.ucc_num);
Dave Liu7737d5c2006-11-03 12:11:15 -06001383 dev->iobase = 0;
1384 dev->priv = (void *)uec;
1385 dev->init = uec_init;
1386 dev->halt = uec_halt;
1387 dev->send = uec_send;
1388 dev->recv = uec_recv;
1389
1390 /* Clear the ethnet address */
1391 for (i = 0; i < 6; i++)
1392 dev->enetaddr[i] = 0;
1393
1394 eth_register(dev);
1395
1396 err = uec_startup(uec);
1397 if (err) {
1398 printf("%s: Cannot configure net device, aborting.",dev->name);
1399 return err;
1400 }
1401
Richard Retanubun23c34af2009-06-17 16:00:41 -04001402#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
Joe Hershberger5a49f172016-08-08 11:28:38 -05001403 int retval;
1404 struct mii_dev *mdiodev = mdio_alloc();
1405 if (!mdiodev)
1406 return -ENOMEM;
1407 strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
1408 mdiodev->read = uec_miiphy_read;
1409 mdiodev->write = uec_miiphy_write;
1410
1411 retval = mdio_register(mdiodev);
1412 if (retval < 0)
1413 return retval;
David Saadad5d28fe2008-03-31 02:37:38 -07001414#endif
1415
Dave Liu7737d5c2006-11-03 12:11:15 -06001416 return 1;
1417}
Haiying Wang8e552582009-06-04 16:12:41 -04001418
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +09001419int uec_eth_init(struct bd_info *bis, uec_info_t *uecs, int num)
Haiying Wang8e552582009-06-04 16:12:41 -04001420{
1421 int i;
1422
1423 for (i = 0; i < num; i++)
1424 uec_initialize(bis, &uecs[i]);
1425
1426 return 0;
1427}
1428
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +09001429int uec_standard_init(struct bd_info *bis)
Haiying Wang8e552582009-06-04 16:12:41 -04001430{
1431 return uec_eth_init(bis, uec_info, ARRAY_SIZE(uec_info));
1432}