1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Description: Hieth driver main process
18 */
19
20
21 #define HIETH_SFV300
22 #include "hieth.h"
23 #include "mac.h"
24 #include "ctrl.h"
25 #include "glb.h"
26 #include "sys.h"
27 #include "mii_drv.h"
28 #include <config.h>
29 #include <miiphy.h>
30 #include <net.h>
31 #include <cpu_func.h>
32
33 /*************************************************************************/
34 int hieth_mdiobus_driver_init(struct hieth_netdev_local *ld);
35 void hieth_mdiobus_driver_exit(struct hieth_netdev_local *ld);
36
37 /* Used when trying to connect to a specific phy (mii bus id:phy device id) */
38 /* refer linux-2.6.23 ./include/linux/phy.h line 76 */
39 char mdio_bus_name[MAX_PHY_NAME_LEN];
40
41 #define MAC_LEN 6
42
43 struct hieth_netdev_local hieth_devs_priv[MAX_PORT] = {
44 {
45 .port = UP_PORT,
46 .mii_name = mdio_bus_name,
47 .phy_addr = HISFV_PHY_U,
48 .phy_intf = HIETH_MII_RMII_MODE_U,
49 },
50 {
51 .port = DOWN_PORT,
52 .mii_name = mdio_bus_name,
53 .phy_addr = HISFV_PHY_D,
54 .phy_intf = HIETH_MII_RMII_MODE_D,
55 },
56 };
57
set_mac_address(const char * mac)58 static int set_mac_address(const char *mac)
59 {
60 u32 val;
61
62 val = ((u32)mac[0] << 8) | (u32)mac[1]; /* mac 0 [8:15], mac 1 [0:7] */
63 writel(val, REG_BASE_SF + GLB_HOSTMAC_H16);
64 /* mac 2 [24:31], mac 3 [16:23], mac 4 [8:15], mac 5 [0:7] */
65 val = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) | ((u32)mac[4] << 8) | (u32)mac[5];
66 writel(val, REG_BASE_SF + GLB_HOSTMAC_L32);
67
68 return 0;
69 }
70
71 #ifdef HIETH_RX_QUEUE_MULTI_DESC
hieth_init_hw_desc_queue(struct hieth_netdev_local * ld)72 static int hieth_init_hw_desc_queue(struct hieth_netdev_local *ld)
73 {
74 struct hieth_frame_desc *queue_phy_addr = NULL;
75 int i;
76
77 const int size = HIETH_HW_DESC_DEPTH * sizeof(struct hieth_frame_desc);
78 /* init rx fq */
79 queue_phy_addr = (struct hieth_frame_desc *)malloc(size);
80 if (queue_phy_addr == NULL) {
81 printf("alloc rx fq error!\n");
82 return 1;
83 }
84
85 memset((void *)queue_phy_addr, 0, size);
86 ld->hieth_desc_head = queue_phy_addr;
87 ld->desc_hw_offset = 0;
88 ld->desc_rec_offset = 0;
89
90 for (i = 0; i < HIETH_HW_DESC_DEPTH; i++) {
91 queue_phy_addr[i].frm_addr = (unsigned long)memalign(PKTALIGN, PKTSIZE_ALIGN);
92 queue_phy_addr[i].frm_len = 0;
93 }
94 return 0;
95 }
96 #endif
97
98 #ifdef HIETH_RX_QUEUE_MULTI_DESC
hieth_destroy_hw_desc_queue(struct hieth_netdev_local * ld)99 static int hieth_destroy_hw_desc_queue(struct hieth_netdev_local *ld)
100 {
101 struct hieth_frame_desc *queue_phy_addr = ld->hieth_desc_head;
102 int i;
103
104 if (queue_phy_addr != NULL) {
105 for (i = 0; i < HIETH_HW_DESC_DEPTH; i++)
106 free((void *)queue_phy_addr[i].frm_addr);
107
108 free(ld->hieth_desc_head);
109 ld->hieth_desc_head = NULL;
110 }
111 ld->desc_hw_offset = 0;
112 ld->desc_rec_offset = 0;
113
114 return 0;
115 }
116 #endif
117
eth_set_host_mac_address(struct eth_device * dev)118 int eth_set_host_mac_address(struct eth_device *dev)
119 {
120 unsigned char mac[MAC_LEN];
121
122 memset(mac, 0, sizeof(mac));
123
124 if (!eth_env_get_enetaddr("ethaddr", mac)) {
125 printf("MAC address invalid!\n");
126 #ifdef CONFIG_NET_RANDOM_ETHADDR
127 net_random_ethaddr(mac);
128 printf("Set Random MAC address!\n");
129 eth_setenv_enetaddr("ethaddr", mac);
130 #endif
131 }
132
133 set_mac_address((char *)mac);
134 memcpy(dev->enetaddr, mac, MAC_LEN);
135
136 return 0;
137 }
138
phy_print_status(struct hieth_netdev_local * ld,unsigned int stat)139 static void phy_print_status(struct hieth_netdev_local *ld, unsigned int stat)
140 {
141 printf("%s : phy status change : LINK=%s : DUPLEX=%s : SPEED=%s\n",
142 (ld->port == UP_PORT) ? "eth0" : "eth1",
143 (stat & HIETH_LINKED) ? "UP" : "DOWN",
144 (stat & HIETH_DUP_FULL) ? "FULL" : "HALF",
145 (stat & HIETH_SPD_100M) ? "100M" : "10M");
146 }
147
hieth_adjust_link(struct hieth_netdev_local * ld)148 static void hieth_adjust_link(struct hieth_netdev_local *ld)
149 {
150 u32 stat = 0;
151 int timeout_us = 1000;
152 /* this env phy_link_time used to solve the difference phy auto-negotiation time of various phys */
153 char *timeout = env_get("phy_link_time");
154 if (timeout != NULL) {
155 timeout_us = simple_strtol(timeout, 0, 10); /* Base10 */
156 if (timeout_us < 0)
157 timeout_us = 1000; /* delay 1000us */
158 }
159 retry:
160 udelay(1);
161
162 stat |= miiphy_link(ld->mii_name, ld->phy_addr) ? HIETH_LINKED : 0;
163 stat |= miiphy_duplex(ld->mii_name, ld->phy_addr) == FULL ? HIETH_DUP_FULL : 0;
164 stat |= miiphy_speed(ld->mii_name, ld->phy_addr) == _100BASET ? HIETH_SPD_100M : 0;
165 if (--timeout_us && !(stat & HIETH_LINKED))
166 goto retry;
167
168 if (stat != ld->link_stat) {
169 hieth_set_linkstat(ld, stat);
170 phy_print_status(ld, stat);
171 ld->link_stat = stat;
172 hieth_set_mii_mode(ld, ld->phy_intf);
173 }
174
175 set_phy_valtage();
176 }
177
hieth_net_open(struct hieth_netdev_local * ld)178 static int hieth_net_open(struct hieth_netdev_local *ld)
179 {
180 /* enable sys-ctrl-en and clk-en */
181 hieth_sys_startup();
182
183 /* setup hardware tx dep */
184 hieth_writel_bits(ld, HIETH_HW_TXQ_DEPTH, ud_reg_name(GLB_QLEN_SET), BITS_TXQ_DEP);
185
186 /* setup hardware rx dep */
187 hieth_writel_bits(ld, HIETH_HW_RXQ_DEPTH, ud_reg_name(GLB_QLEN_SET), BITS_RXQ_DEP);
188
189 ld->link_stat = 0;
190 hieth_adjust_link(ld);
191
192 hieth_irq_enable(ld, ud_bit_name(HIETH_INT_RX_RDY));
193
194 return 0;
195 }
196
hieth_net_close(struct hieth_netdev_local * ld)197 static int hieth_net_close(struct hieth_netdev_local *ld)
198 {
199 hieth_glb_preinit_dummy(ld);
200
201 hieth_sys_allstop();
202
203 return 0;
204 }
205
hieth_dev_probe_init(struct hieth_netdev_local * ld)206 static int hieth_dev_probe_init(struct hieth_netdev_local *ld)
207 {
208 ld->iobase_phys = REG_BASE_SF;
209
210 hieth_glb_preinit_dummy(ld);
211
212 #ifdef HIETH_RX_QUEUE_MULTI_DESC
213 hieth_init_hw_desc_queue(ld);
214 #endif
215
216 hieth_sys_allstop();
217
218 return 0;
219 }
220
hieth_dev_remove(struct hieth_netdev_local * ld)221 static int hieth_dev_remove(struct hieth_netdev_local *ld)
222 {
223 #ifdef HIETH_RX_QUEUE_MULTI_DESC
224 hieth_destroy_hw_desc_queue(ld);
225 #endif
226
227 return 0;
228 }
229
hieth_get_phy_intf(struct hieth_netdev_local * ld)230 static void hieth_get_phy_intf(struct hieth_netdev_local *ld)
231 {
232 char *mdio_intf = NULL;
233
234 /* get mdio interface from env.FORMAT: mdio_intf=mii or mdio_intf=rmii */
235 mdio_intf = env_get("mdio_intf");
236 if (mdio_intf != NULL) {
237 if (!strncmp(mdio_intf, "mii", strlen("mii"))) {
238 ld->phy_intf = INTERFACE_MODE_MII;
239 } else if (!strncmp(mdio_intf, "rmii", strlen("rmii"))) {
240 ld->phy_intf = INTERFACE_MODE_RMII;
241 } else {
242 printf("Invalid mdio_intf, should be mii or rmii.\n");
243 ld->phy_intf = INTERFACE_MODE_RMII;
244 }
245 }
246 }
247
hieth_get_phy_addr(struct hieth_netdev_local * ld)248 static void hieth_get_phy_addr(struct hieth_netdev_local *ld)
249 {
250 char *phyaddr = NULL;
251 char addr_name[MAX_PORT][10] = { "phyaddru", "phyaddrd" }; /* max name size is 10 */
252
253 if (ld->port >= MAX_PORT)
254 return;
255
256 /* get phy addr of up port */
257 phyaddr = env_get(addr_name[ld->port]);
258 if (phyaddr != NULL) {
259 unsigned long tmp = simple_strtoul(phyaddr, 0, 10); /* use Base10 */
260 /* check phyaddr > 0x1f */
261 if (tmp >= 0x1f) {
262 printf("Detected env '%s' had been set greater"
263 "than 0x1f,this may not correct.\n",
264 addr_name[ld->port]);
265 return;
266 }
267 ld->phy_addr = (unsigned char)tmp;
268 } else {
269 #if defined(INNER_PHY)
270 if (ld->port == UP_PORT) {
271 #if defined(INNER_PHY_ADDR_U)
272 ld->phy_addr = INNER_PHY_ADDR_U;
273 #endif
274 } else {
275 #if defined(INNER_PHY_ADDR_D)
276 ld->phy_addr = INNER_PHY_ADDR_D;
277 #endif
278 }
279 #endif
280 }
281 }
282
hieth_exit(struct hieth_netdev_local * ld)283 static void hieth_exit(struct hieth_netdev_local *ld)
284 {
285 hieth_mdiobus_driver_exit(ld);
286
287 hieth_sys_exit();
288 }
289
hieth_init(struct eth_device * dev,bd_t * bd)290 int hieth_init(struct eth_device *dev, bd_t *bd)
291 {
292 struct hieth_netdev_local *ld = (struct hieth_netdev_local *)dev->priv;
293 int ret;
294 int count = 30;
295
296 hieth_get_phy_intf(ld);
297 #if defined(CONFIG_HI3536DV100)
298 hieth_set_crg_phy_mode(ld->phy_intf);
299 #endif
300
301 hieth_get_phy_addr(ld);
302 #ifdef INNER_PHY
303 if (ld->port == UP_PORT)
304 set_inner_phy_addr(ld->phy_addr);
305 #endif
306
307 printf(OSDRV_MODULE_VERSION_STRING "\n");
308
309 set_efuse_unread();
310
311 /* sys-func-sel */
312 hieth_sys_init();
313
314 /* register MDIO bus to uboot */
315 if (hieth_mdiobus_driver_init(ld) != 0) {
316 goto _error_hieth_init;
317 }
318
319 if (phy_detected(ld->mii_name, ld->phy_addr) == false) {
320 goto _error_hieth_init;
321 }
322
323 miiphy_reset(ld->mii_name, ld->phy_addr);
324
325 ret = hieth_dev_probe_init(ld);
326 if (ret) {
327 hieth_error("register Ether netdevice"
328 " driver failed!");
329 goto _error_hieth_init;
330 }
331
332 eth_set_host_mac_address(dev);
333
334 while (--count >= 0) {
335 /* open UpEther net dev */
336 hieth_net_open(ld);
337 if (ld->link_stat & HIETH_LINKED) {
338 return 0;
339 }
340 }
341
342 printf("PHY not link.\n");
343
344 _error_hieth_init:
345 hieth_mdiobus_driver_exit(ld);
346 hieth_net_close(ld);
347
348 return -1;
349 }
350
351 #ifdef HIETH_RX_QUEUE_MULTI_DESC
hieth_recv(struct eth_device * dev)352 static int hieth_recv(struct eth_device *dev)
353 {
354 struct hieth_netdev_local *ld = (struct hieth_netdev_local *)dev->priv;
355 int recvq_ready, hw_offset, rec_offset;
356 int timeout_us = 10000;
357 struct hieth_frame_desc *fd;
358 struct hieth_frame_desc receive_fd;
359
360 fd = ld->hieth_desc_head;
361 hw_offset = ld->desc_hw_offset;
362 rec_offset = ld->desc_rec_offset;
363
364 /* check this we can add a Rx addr */
365 recvq_ready = hieth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT), BITS_RECVQ_RDY);
366 if (!recvq_ready)
367 hieth_trace(HIETH_TRACE_DRV, "hw can't add a rx addr.");
368
369 while (recvq_ready &&
370 ((hw_offset + 1) % HIETH_HW_DESC_DEPTH != rec_offset)) {
371 receive_fd = fd[hw_offset];
372 invalidate_dcache_range(receive_fd.frm_addr,
373 ALIGN(receive_fd.frm_addr + PKTSIZE_ALIGN, ARCH_DMA_MINALIGN));
374 hw_recvq_setfd(ld, receive_fd);
375
376 hw_offset = (hw_offset + 1) % HIETH_HW_DESC_DEPTH;
377
378 recvq_ready =
379 hieth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT),
380 BITS_RECVQ_RDY);
381 }
382 ld->desc_hw_offset = hw_offset;
383
384 /* receive packed, loop in NetLoop */
385 while (--timeout_us && !is_recv_packet_rx(ld))
386 udelay(1);
387
388 if (is_recv_packet_rx(ld)) {
389 receive_fd = fd[rec_offset];
390
391 receive_fd.frm_len = hw_get_rxpkg_len(ld);
392 hw_set_rxpkg_finish(ld);
393
394 rec_offset = (rec_offset + 1) % HIETH_HW_DESC_DEPTH;
395 ld->desc_rec_offset = rec_offset;
396
397 if (hieth_invalid_rxpkg_len(receive_fd.frm_len)) {
398 hieth_error("frm_len invalid (%u)", receive_fd.frm_len);
399 goto _error_exit;
400 }
401
402 invalidate_dcache_range(receive_fd.frm_addr,
403 ALIGN(receive_fd.frm_addr + receive_fd.frm_len, ARCH_DMA_MINALIGN));
404 memcpy((void *)net_rx_packets[0], (void *)receive_fd.frm_addr,
405 receive_fd.frm_len);
406
407 /* Pass the packet up to the protocol layers. */
408 net_process_received_packet(net_rx_packets[0], receive_fd.frm_len);
409
410 return 0;
411 } else {
412 hieth_trace(HIETH_TRACE_DRV, "hw rx timeout.");
413 }
414
415 _error_exit:
416 return -1;
417 }
418 #else
hieth_recv(struct eth_device * dev)419 static int hieth_recv(struct eth_device *dev)
420 {
421 struct hieth_netdev_local *ld = (struct hieth_netdev_local *)dev->priv;
422 int recvq_ready;
423 int timeout_us = 10000;
424 struct hieth_frame_desc fd = { 0 };
425
426 /* check this we can add a Rx addr */
427 recvq_ready = hieth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT), BITS_RECVQ_RDY);
428 if (!recvq_ready)
429 hieth_trace(HIETH_TRACE_DRV, "hw can't add a rx addr.");
430
431 /* enable rx int */
432 hieth_irq_enable(ld, ud_bit_name(HIETH_INT_RX_RDY));
433
434 /* fill rx hwq fd */
435 fd.frm_addr = (uintptr_t)net_rx_packets[0];
436 fd.frm_len = 0;
437 /* recv data will be put into DDR , in case of get the cache data, mush be invalid Dcache */
438 invalidate_dcache_range(fd.frm_addr, ALIGN(fd.frm_addr + PKTSIZE_ALIGN, ARCH_DMA_MINALIGN));
439
440 hw_recvq_setfd(ld, fd);
441
442 /* receive packed, loop in NetLoop */
443 while (--timeout_us && !is_recv_packet(ld))
444 udelay(1);
445
446 if (is_recv_packet(ld)) {
447 fd.frm_len = hw_get_rxpkg_len(ld);
448 hw_set_rxpkg_finish(ld);
449
450 if (hieth_invalid_rxpkg_len(fd.frm_len)) {
451 hieth_error("frm_len invalid (%u)", fd.frm_len);
452 goto _error_exit;
453 }
454
455 invalidate_dcache_range(fd.frm_addr,
456 ALIGN(fd.frm_addr + fd.frm_len, ARCH_DMA_MINALIGN));
457 /* Pass the packet up to the protocol layers. */
458 net_process_received_packet(net_rx_packets[0], fd.frm_len);
459
460 return 0;
461 } else {
462 hieth_trace(HIETH_TRACE_DRV, "hw rx timeout.");
463 }
464
465 _error_exit:
466 return -1;
467 }
468 #endif
469
470 #define ETH_FCS_LEN 4 /* Octets in the FCS */
hieth_send(struct eth_device * dev,void * packet,int length)471 static int hieth_send(struct eth_device *dev, void *packet, int length)
472 {
473 struct hieth_netdev_local *ld = (struct hieth_netdev_local *)dev->priv;
474 unsigned int ints, xmitq_ready;
475 unsigned int timeout_us = 3000;
476 struct hieth_frame_desc fd;
477
478 /* check this we can add a Tx addr */
479 xmitq_ready = hieth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT), BITS_XMITQ_RDY);
480 if (!xmitq_ready) {
481 hieth_error("hw can't add a tx addr");
482 goto _error_exit;
483 }
484
485 /* enable tx int */
486 hieth_irq_enable(ld, ud_bit_name(HIETH_INT_TXQUE_RDY));
487
488 flush_cache((uintptr_t)packet, ALIGN((unsigned int)length + ETH_FCS_LEN, ARCH_DMA_MINALIGN));
489 /* fill tx hwq fd */
490 fd.frm_addr = (uintptr_t)packet;
491 fd.frm_len = length + ETH_FCS_LEN;
492 hw_xmitq_setfd(ld, fd);
493
494 do {
495 udelay(1);
496 ints = hieth_read_irqstatus(ld);
497 } while (--timeout_us && !(ints & ud_bit_name(HIETH_INT_TXQUE_RDY)));
498
499 hieth_clear_irqstatus(ld, ints);
500
501 if (!timeout_us) {
502 hieth_error("hw tx timeout");
503 goto _error_exit;
504 }
505
506 return 0;
507
508 _error_exit:
509 return -1;
510 }
511
hieth_halt(struct eth_device * dev)512 static void hieth_halt(struct eth_device *dev)
513 {
514 struct hieth_netdev_local *ld = (struct hieth_netdev_local *)dev->priv;
515
516 hieth_net_close(ld);
517
518 hieth_dev_remove(ld);
519
520 hieth_exit(ld);
521 }
522
hieth_register_dev(unsigned char port_id)523 static int hieth_register_dev(unsigned char port_id)
524 {
525 struct eth_device *dev;
526
527 dev = malloc(sizeof(*dev));
528 if (dev == NULL)
529 return -1;
530 memset(dev, 0, sizeof(*dev));
531
532 dev->iobase = REG_BASE_SF;
533 dev->init = hieth_init;
534 dev->halt = hieth_halt;
535 dev->send = hieth_send;
536 dev->recv = hieth_recv;
537 dev->priv = &hieth_devs_priv[port_id];
538 hieth_devs_priv[port_id].iobase_phys = REG_BASE_SF;
539 snprintf(dev->name, sizeof(dev->name) - 1, "eth%d", port_id);
540
541 eth_register(dev);
542
543 return 0;
544 }
545
hieth_initialize(bd_t * bis)546 int hieth_initialize(bd_t *bis)
547 {
548 int ret;
549
550 ret = hieth_register_dev(UP_PORT);
551 if (ret)
552 return ret;
553
554 return 0;
555 }
556