1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2013 Gerhard Sittig <gsi@denx.de>
4 * based on the U-Boot Asix driver as well as information
5 * from the Linux Moschip driver
6 */
7
8/*
9 * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices
10 */
11
12#include <common.h>
13#include <dm.h>
14#include <errno.h>
15#include <log.h>
16#include <net.h>
17#include <linux/delay.h>
18#include <linux/mii.h>
19#include <malloc.h>
20#include <memalign.h>
21#include <usb.h>
22#include <linux/printk.h>
23
24#include "usb_ether.h"
25
26#define MCS7830_BASE_NAME	"mcs"
27
28#define USBCALL_TIMEOUT		1000
29#define LINKSTATUS_TIMEOUT	5000	/* link status, connect timeout */
30#define LINKSTATUS_TIMEOUT_RES	50	/* link status, resolution in msec */
31
32#define MCS7830_RX_URB_SIZE	2048
33
34/* command opcodes */
35#define MCS7830_WR_BREQ		0x0d
36#define MCS7830_RD_BREQ		0x0e
37
38/* register layout, numerical offset specs for USB API calls */
39struct mcs7830_regs {
40	uint8_t multicast_hashes[8];
41	uint8_t packet_gap[2];
42	uint8_t phy_data[2];
43	uint8_t phy_command[2];
44	uint8_t configuration;
45	uint8_t ether_address[6];
46	uint8_t frame_drop_count;
47	uint8_t pause_threshold;
48};
49#define REG_MULTICAST_HASH	offsetof(struct mcs7830_regs, multicast_hashes)
50#define REG_PHY_DATA		offsetof(struct mcs7830_regs, phy_data)
51#define REG_PHY_CMD		offsetof(struct mcs7830_regs, phy_command)
52#define REG_CONFIG		offsetof(struct mcs7830_regs, configuration)
53#define REG_ETHER_ADDR		offsetof(struct mcs7830_regs, ether_address)
54#define REG_FRAME_DROP_COUNTER	offsetof(struct mcs7830_regs, frame_drop_count)
55#define REG_PAUSE_THRESHOLD	offsetof(struct mcs7830_regs, pause_threshold)
56
57/* bit masks and default values for the above registers */
58#define PHY_CMD1_READ		0x40
59#define PHY_CMD1_WRITE		0x20
60#define PHY_CMD1_PHYADDR	0x01
61
62#define PHY_CMD2_PEND		0x80
63#define PHY_CMD2_READY		0x40
64
65#define CONF_CFG		0x80
66#define CONF_SPEED100		0x40
67#define CONF_FDX_ENABLE		0x20
68#define CONF_RXENABLE		0x10
69#define CONF_TXENABLE		0x08
70#define CONF_SLEEPMODE		0x04
71#define CONF_ALLMULTICAST	0x02
72#define CONF_PROMISCUOUS	0x01
73
74#define PAUSE_THRESHOLD_DEFAULT	0
75
76/* bit masks for the status byte which follows received ethernet frames */
77#define STAT_RX_FRAME_CORRECT	0x20
78#define STAT_RX_LARGE_FRAME	0x10
79#define STAT_RX_CRC_ERROR	0x08
80#define STAT_RX_ALIGNMENT_ERROR	0x04
81#define STAT_RX_LENGTH_ERROR	0x02
82#define STAT_RX_SHORT_FRAME	0x01
83
84/*
85 * struct mcs7830_private - private driver data for an individual adapter
86 * @config:	shadow for the network adapter's configuration register
87 * @mchash:	shadow for the network adapter's multicast hash registers
88 */
89struct mcs7830_private {
90	uint8_t rx_buf[MCS7830_RX_URB_SIZE];
91	struct ueth_data ueth;
92	uint8_t config;
93	uint8_t mchash[8];
94};
95
96/*
97 * mcs7830_read_reg() - read a register of the network adapter
98 * @udev:	network device to read from
99 * @idx:	index of the register to start reading from
100 * @size:	number of bytes to read
101 * @data:	buffer to read into
102 * Return: zero upon success, negative upon error
103 */
104static int mcs7830_read_reg(struct usb_device *udev, uint8_t idx,
105			    uint16_t size, void *data)
106{
107	int len;
108	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, size);
109
110	debug("%s() idx=0x%04X sz=%d\n", __func__, idx, size);
111
112	len = usb_control_msg(udev,
113			      usb_rcvctrlpipe(udev, 0),
114			      MCS7830_RD_BREQ,
115			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
116			      0, idx, buf, size,
117			      USBCALL_TIMEOUT);
118	if (len != size) {
119		debug("%s() len=%d != sz=%d\n", __func__, len, size);
120		return -EIO;
121	}
122	memcpy(data, buf, size);
123	return 0;
124}
125
126/*
127 * mcs7830_write_reg() - write a register of the network adapter
128 * @udev:	network device to write to
129 * @idx:	index of the register to start writing to
130 * @size:	number of bytes to write
131 * @data:	buffer holding the data to write
132 * Return: zero upon success, negative upon error
133 */
134static int mcs7830_write_reg(struct usb_device *udev, uint8_t idx,
135			     uint16_t size, void *data)
136{
137	int len;
138	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, size);
139
140	debug("%s() idx=0x%04X sz=%d\n", __func__, idx, size);
141
142	memcpy(buf, data, size);
143	len = usb_control_msg(udev,
144			      usb_sndctrlpipe(udev, 0),
145			      MCS7830_WR_BREQ,
146			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
147			      0, idx, buf, size,
148			      USBCALL_TIMEOUT);
149	if (len != size) {
150		debug("%s() len=%d != sz=%d\n", __func__, len, size);
151		return -EIO;
152	}
153	return 0;
154}
155
156/*
157 * mcs7830_phy_emit_wait() - emit PHY read/write access, wait for its execution
158 * @udev:	network device to talk to
159 * @rwflag:	PHY_CMD1_READ or PHY_CMD1_WRITE opcode
160 * @index:	number of the PHY register to read or write
161 * Return: zero upon success, negative upon error
162 */
163static int mcs7830_phy_emit_wait(struct usb_device *udev,
164				 uint8_t rwflag, uint8_t index)
165{
166	int rc;
167	int retry;
168	uint8_t cmd[2];
169
170	/* send the PHY read/write request */
171	cmd[0] = rwflag | PHY_CMD1_PHYADDR;
172	cmd[1] = PHY_CMD2_PEND | (index & 0x1f);
173	rc = mcs7830_write_reg(udev, REG_PHY_CMD, sizeof(cmd), cmd);
174	if (rc < 0)
175		return rc;
176
177	/* wait for the response to become available (usually < 1ms) */
178	retry = 10;
179	do {
180		rc = mcs7830_read_reg(udev, REG_PHY_CMD, sizeof(cmd), cmd);
181		if (rc < 0)
182			return rc;
183		if (cmd[1] & PHY_CMD2_READY)
184			return 0;
185		if (!retry--)
186			return -ETIMEDOUT;
187		mdelay(1);
188	} while (1);
189	/* UNREACH */
190}
191
192/*
193 * mcs7830_read_phy() - read a PHY register of the network adapter
194 * @udev:	network device to read from
195 * @index:	index of the PHY register to read from
196 * Return: non-negative 16bit register content, negative upon error
197 */
198static int mcs7830_read_phy(struct usb_device *udev, uint8_t index)
199{
200	int rc;
201	uint16_t val;
202
203	/* issue the PHY read request and wait for its execution */
204	rc = mcs7830_phy_emit_wait(udev, PHY_CMD1_READ, index);
205	if (rc < 0)
206		return rc;
207
208	/* fetch the PHY data which was read */
209	rc = mcs7830_read_reg(udev, REG_PHY_DATA, sizeof(val), &val);
210	if (rc < 0)
211		return rc;
212	rc = le16_to_cpu(val);
213	debug("%s(%d) => 0x%04X\n", __func__, index, rc);
214	return rc;
215}
216
217/*
218 * mcs7830_write_phy() - write a PHY register of the network adapter
219 * @udev:	network device to write to
220 * @index:	index of the PHY register to write to
221 * @val:	value to write to the PHY register
222 * Return: zero upon success, negative upon error
223 */
224static int mcs7830_write_phy(struct usb_device *udev, uint8_t index,
225			     uint16_t val)
226{
227	int rc;
228
229	debug("%s(%d, 0x%04X)\n", __func__, index, val);
230
231	/* setup the PHY data which is to get written */
232	val = cpu_to_le16(val);
233	rc = mcs7830_write_reg(udev, REG_PHY_DATA, sizeof(val), &val);
234	if (rc < 0)
235		return rc;
236
237	/* issue the PHY write request and wait for its execution */
238	rc = mcs7830_phy_emit_wait(udev, PHY_CMD1_WRITE, index);
239	if (rc < 0)
240		return rc;
241
242	return 0;
243}
244
245/*
246 * mcs7830_write_config() - write to the network adapter's config register
247 * @udev:	network device to write to
248 * @priv:	private data
249 * Return: zero upon success, negative upon error
250 *
251 * the data which gets written is taken from the shadow config register
252 * within the device driver's private data
253 */
254static int mcs7830_write_config(struct usb_device *udev,
255				struct mcs7830_private *priv)
256{
257	int rc;
258
259	debug("%s()\n", __func__);
260
261	rc = mcs7830_write_reg(udev, REG_CONFIG,
262			       sizeof(priv->config), &priv->config);
263	if (rc < 0) {
264		debug("writing config to adapter failed\n");
265		return rc;
266	}
267
268	return 0;
269}
270
271/*
272 * mcs7830_write_mchash() - write the network adapter's multicast filter
273 * @udev:	network device to write to
274 * @priv:	private data
275 * Return: zero upon success, negative upon error
276 *
277 * the data which gets written is taken from the shadow multicast hashes
278 * within the device driver's private data
279 */
280static int mcs7830_write_mchash(struct usb_device *udev,
281				struct mcs7830_private *priv)
282{
283	int rc;
284
285	debug("%s()\n", __func__);
286
287	rc = mcs7830_write_reg(udev, REG_MULTICAST_HASH,
288			       sizeof(priv->mchash), &priv->mchash);
289	if (rc < 0) {
290		debug("writing multicast hash to adapter failed\n");
291		return rc;
292	}
293
294	return 0;
295}
296
297/*
298 * mcs7830_set_autoneg() - setup and trigger ethernet link autonegotiation
299 * @udev:	network device to run link negotiation on
300 * Return: zero upon success, negative upon error
301 *
302 * the routine advertises available media and starts autonegotiation
303 */
304static int mcs7830_set_autoneg(struct usb_device *udev)
305{
306	int adv, flg;
307	int rc;
308
309	debug("%s()\n", __func__);
310
311	/*
312	 * algorithm taken from the Linux driver, which took it from
313	 * "the original mcs7830 version 1.4 driver":
314	 *
315	 * enable all media, reset BMCR, enable auto neg, restart
316	 * auto neg while keeping the enable auto neg flag set
317	 */
318
319	adv = ADVERTISE_PAUSE_CAP | ADVERTISE_ALL | ADVERTISE_CSMA;
320	rc = mcs7830_write_phy(udev, MII_ADVERTISE, adv);
321
322	flg = 0;
323	if (!rc)
324		rc = mcs7830_write_phy(udev, MII_BMCR, flg);
325
326	flg |= BMCR_ANENABLE;
327	if (!rc)
328		rc = mcs7830_write_phy(udev, MII_BMCR, flg);
329
330	flg |= BMCR_ANRESTART;
331	if (!rc)
332		rc = mcs7830_write_phy(udev, MII_BMCR, flg);
333
334	return rc;
335}
336
337/*
338 * mcs7830_get_rev() - identify a network adapter's chip revision
339 * @udev:	network device to identify
340 * Return: non-negative number, reflecting the revision number
341 *
342 * currently, only "rev C and higher" and "below rev C" are needed, so
343 * the return value is #1 for "below rev C", and #2 for "rev C and above"
344 */
345static int mcs7830_get_rev(struct usb_device *udev)
346{
347	uint8_t buf[2];
348	int rc;
349	int rev;
350
351	/* register 22 is readable in rev C and higher */
352	rc = mcs7830_read_reg(udev, REG_FRAME_DROP_COUNTER, sizeof(buf), buf);
353	if (rc < 0)
354		rev = 1;
355	else
356		rev = 2;
357	debug("%s() rc=%d, rev=%d\n", __func__, rc, rev);
358	return rev;
359}
360
361/*
362 * mcs7830_apply_fixup() - identify an adapter and potentially apply fixups
363 * @udev:	network device to identify and apply fixups to
364 * Return: zero upon success (no errors emitted from here)
365 *
366 * this routine identifies the network adapter's chip revision, and applies
367 * fixups for known issues
368 */
369static int mcs7830_apply_fixup(struct usb_device *udev)
370{
371	int rev;
372	int i;
373	uint8_t thr;
374
375	rev = mcs7830_get_rev(udev);
376	debug("%s() rev=%d\n", __func__, rev);
377
378	/*
379	 * rev C requires setting the pause threshold (the Linux driver
380	 * is inconsistent, the implementation does it for "rev C
381	 * exactly", the introductory comment says "rev C and above")
382	 */
383	if (rev == 2) {
384		debug("%s: applying rev C fixup\n", __func__);
385		thr = PAUSE_THRESHOLD_DEFAULT;
386		for (i = 0; i < 2; i++) {
387			(void)mcs7830_write_reg(udev, REG_PAUSE_THRESHOLD,
388						sizeof(thr), &thr);
389			mdelay(1);
390		}
391	}
392
393	return 0;
394}
395
396/*
397 * mcs7830_basic_reset() - bring the network adapter into a known first state
398 * @eth:	network device to act upon
399 * Return: zero upon success, negative upon error
400 *
401 * this routine initializes the network adapter such that subsequent invocations
402 * of the interface callbacks can exchange ethernet frames; link negotiation is
403 * triggered from here already and continues in background
404 */
405static int mcs7830_basic_reset(struct usb_device *udev,
406			       struct mcs7830_private *priv)
407{
408	int rc;
409
410	debug("%s()\n", __func__);
411
412	/*
413	 * comment from the respective Linux driver, which
414	 * unconditionally sets the ALLMULTICAST flag as well:
415	 * should not be needed, but does not work otherwise
416	 */
417	priv->config = CONF_TXENABLE;
418	priv->config |= CONF_ALLMULTICAST;
419
420	rc = mcs7830_set_autoneg(udev);
421	if (rc < 0) {
422		pr_err("setting autoneg failed\n");
423		return rc;
424	}
425
426	rc = mcs7830_write_mchash(udev, priv);
427	if (rc < 0) {
428		pr_err("failed to set multicast hash\n");
429		return rc;
430	}
431
432	rc = mcs7830_write_config(udev, priv);
433	if (rc < 0) {
434		pr_err("failed to set configuration\n");
435		return rc;
436	}
437
438	rc = mcs7830_apply_fixup(udev);
439	if (rc < 0) {
440		pr_err("fixup application failed\n");
441		return rc;
442	}
443
444	return 0;
445}
446
447/*
448 * mcs7830_read_mac() - read an ethernet adapter's MAC address
449 * @udev:	network device to read from
450 * @enetaddr:	place to put ethernet MAC address
451 * Return: zero upon success, negative upon error
452 *
453 * this routine fetches the MAC address stored within the ethernet adapter,
454 * and stores it in the ethernet interface's data structure
455 */
456static int mcs7830_read_mac(struct usb_device *udev, unsigned char enetaddr[])
457{
458	int rc;
459	uint8_t buf[ETH_ALEN];
460
461	debug("%s()\n", __func__);
462
463	rc = mcs7830_read_reg(udev, REG_ETHER_ADDR, ETH_ALEN, buf);
464	if (rc < 0) {
465		debug("reading MAC from adapter failed\n");
466		return rc;
467	}
468
469	memcpy(enetaddr, buf, ETH_ALEN);
470	return 0;
471}
472
473static int mcs7830_write_mac_common(struct usb_device *udev,
474				    unsigned char enetaddr[])
475{
476	int rc;
477
478	debug("%s()\n", __func__);
479
480	rc = mcs7830_write_reg(udev, REG_ETHER_ADDR, ETH_ALEN, enetaddr);
481	if (rc < 0) {
482		debug("writing MAC to adapter failed\n");
483		return rc;
484	}
485	return 0;
486}
487
488static int mcs7830_init_common(struct usb_device *udev)
489{
490	int timeout;
491	int have_link;
492
493	debug("%s()\n", __func__);
494
495	timeout = 0;
496	do {
497		have_link = mcs7830_read_phy(udev, MII_BMSR) & BMSR_LSTATUS;
498		if (have_link)
499			break;
500		udelay(LINKSTATUS_TIMEOUT_RES * 1000);
501		timeout += LINKSTATUS_TIMEOUT_RES;
502	} while (timeout < LINKSTATUS_TIMEOUT);
503	if (!have_link) {
504		debug("ethernet link is down\n");
505		return -ETIMEDOUT;
506	}
507	return 0;
508}
509
510static int mcs7830_send_common(struct ueth_data *ueth, void *packet,
511			       int length)
512{
513	struct usb_device *udev = ueth->pusb_dev;
514	int rc;
515	int gotlen;
516	/* there is a status byte after the ethernet frame */
517	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, buf, PKTSIZE + sizeof(uint8_t));
518
519	memcpy(buf, packet, length);
520	rc = usb_bulk_msg(udev,
521			  usb_sndbulkpipe(udev, ueth->ep_out),
522			  &buf[0], length, &gotlen,
523			  USBCALL_TIMEOUT);
524	debug("%s() TX want len %d, got len %d, rc %d\n",
525	      __func__, length, gotlen, rc);
526	return rc;
527}
528
529static int mcs7830_recv_common(struct ueth_data *ueth, uint8_t *buf)
530{
531	int rc, wantlen, gotlen;
532	uint8_t sts;
533
534	debug("%s()\n", __func__);
535
536	/* fetch input data from the adapter */
537	wantlen = MCS7830_RX_URB_SIZE;
538	rc = usb_bulk_msg(ueth->pusb_dev,
539			  usb_rcvbulkpipe(ueth->pusb_dev, ueth->ep_in),
540			  &buf[0], wantlen, &gotlen,
541			  USBCALL_TIMEOUT);
542	debug("%s() RX want len %d, got len %d, rc %d\n",
543	      __func__, wantlen, gotlen, rc);
544	if (rc != 0) {
545		pr_err("RX: failed to receive\n");
546		return rc;
547	}
548	if (gotlen > wantlen) {
549		pr_err("RX: got too many bytes (%d)\n", gotlen);
550		return -EIO;
551	}
552
553	/*
554	 * the bulk message that we received from USB contains exactly
555	 * one ethernet frame and a trailing status byte
556	 */
557	if (gotlen < sizeof(sts))
558		return -EIO;
559	gotlen -= sizeof(sts);
560	sts = buf[gotlen];
561
562	if (sts == STAT_RX_FRAME_CORRECT) {
563		debug("%s() got a frame, len=%d\n", __func__, gotlen);
564		return gotlen;
565	}
566
567	debug("RX: frame error (sts 0x%02X, %s %s %s %s %s)\n",
568	      sts,
569	      (sts & STAT_RX_LARGE_FRAME) ? "large" : "-",
570	      (sts & STAT_RX_LENGTH_ERROR) ?  "length" : "-",
571	      (sts & STAT_RX_SHORT_FRAME) ? "short" : "-",
572	      (sts & STAT_RX_CRC_ERROR) ? "crc" : "-",
573	      (sts & STAT_RX_ALIGNMENT_ERROR) ?  "align" : "-");
574	return -EIO;
575}
576
577static int mcs7830_eth_start(struct udevice *dev)
578{
579	struct usb_device *udev = dev_get_parent_priv(dev);
580
581	return mcs7830_init_common(udev);
582}
583
584void mcs7830_eth_stop(struct udevice *dev)
585{
586	debug("** %s()\n", __func__);
587}
588
589int mcs7830_eth_send(struct udevice *dev, void *packet, int length)
590{
591	struct mcs7830_private *priv = dev_get_priv(dev);
592	struct ueth_data *ueth = &priv->ueth;
593
594	return mcs7830_send_common(ueth, packet, length);
595}
596
597int mcs7830_eth_recv(struct udevice *dev, int flags, uchar **packetp)
598{
599	struct mcs7830_private *priv = dev_get_priv(dev);
600	struct ueth_data *ueth = &priv->ueth;
601	int len;
602
603	len = mcs7830_recv_common(ueth, priv->rx_buf);
604	*packetp = priv->rx_buf;
605
606	return len;
607}
608
609static int mcs7830_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
610{
611	struct mcs7830_private *priv = dev_get_priv(dev);
612
613	packet_len = ALIGN(packet_len, 4);
614	usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
615
616	return 0;
617}
618
619int mcs7830_write_hwaddr(struct udevice *dev)
620{
621	struct usb_device *udev = dev_get_parent_priv(dev);
622	struct eth_pdata *pdata = dev_get_plat(dev);
623
624	return mcs7830_write_mac_common(udev, pdata->enetaddr);
625}
626
627static int mcs7830_eth_probe(struct udevice *dev)
628{
629	struct usb_device *udev = dev_get_parent_priv(dev);
630	struct mcs7830_private *priv = dev_get_priv(dev);
631	struct eth_pdata *pdata = dev_get_plat(dev);
632	struct ueth_data *ueth = &priv->ueth;
633
634	if (mcs7830_basic_reset(udev, priv))
635		return 0;
636
637	if (mcs7830_read_mac(udev, pdata->enetaddr))
638		return 0;
639
640	return usb_ether_register(dev, ueth, MCS7830_RX_URB_SIZE);
641}
642
643static const struct eth_ops mcs7830_eth_ops = {
644	.start	= mcs7830_eth_start,
645	.send	= mcs7830_eth_send,
646	.recv	= mcs7830_eth_recv,
647	.free_pkt = mcs7830_free_pkt,
648	.stop	= mcs7830_eth_stop,
649	.write_hwaddr = mcs7830_write_hwaddr,
650};
651
652U_BOOT_DRIVER(mcs7830_eth) = {
653	.name	= "mcs7830_eth",
654	.id	= UCLASS_ETH,
655	.probe = mcs7830_eth_probe,
656	.ops	= &mcs7830_eth_ops,
657	.priv_auto	= sizeof(struct mcs7830_private),
658	.plat_auto	= sizeof(struct eth_pdata),
659	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
660};
661
662static const struct usb_device_id mcs7830_eth_id_table[] = {
663	{ USB_DEVICE(0x9710, 0x7832) },		/* Moschip 7832 */
664	{ USB_DEVICE(0x9710, 0x7830), },	/* Moschip 7830 */
665	{ USB_DEVICE(0x9710, 0x7730), },	/* Moschip 7730 */
666	{ USB_DEVICE(0x0df6, 0x0021), },	/* Sitecom LN 30 */
667	{ }		/* Terminating entry */
668};
669
670U_BOOT_USB_DEVICE(mcs7830_eth, mcs7830_eth_id_table);
671