• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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