xref: /openbmc/u-boot/drivers/usb/eth/r8152.c (revision c7ac1538)
19dc8ba19STed Chen /*
29dc8ba19STed Chen  * Copyright (c) 2015 Realtek Semiconductor Corp. All rights reserved.
39dc8ba19STed Chen  *
49dc8ba19STed Chen  * SPDX-License-Identifier:	GPL-2.0
59dc8ba19STed Chen  *
69dc8ba19STed Chen  */
79dc8ba19STed Chen 
89dc8ba19STed Chen #include <common.h>
96688452aSStefan Roese #include <dm.h>
109dc8ba19STed Chen #include <errno.h>
119dc8ba19STed Chen #include <malloc.h>
12*c7ac1538SStefan Roese #include <memalign.h>
139dc8ba19STed Chen #include <usb.h>
149dc8ba19STed Chen #include <usb/lin_gadget_compat.h>
159dc8ba19STed Chen #include <linux/mii.h>
169dc8ba19STed Chen #include <linux/bitops.h>
179dc8ba19STed Chen #include "usb_ether.h"
189dc8ba19STed Chen #include "r8152.h"
199dc8ba19STed Chen 
206688452aSStefan Roese #ifndef CONFIG_DM_ETH
219dc8ba19STed Chen /* local vars */
229dc8ba19STed Chen static int curr_eth_dev; /* index for name of next device detected */
239dc8ba19STed Chen 
249dc8ba19STed Chen struct r8152_dongle {
259dc8ba19STed Chen 	unsigned short vendor;
269dc8ba19STed Chen 	unsigned short product;
279dc8ba19STed Chen };
289dc8ba19STed Chen 
299dc8ba19STed Chen static const struct r8152_dongle const r8152_dongles[] = {
309dc8ba19STed Chen 	/* Realtek */
319dc8ba19STed Chen 	{ 0x0bda, 0x8050 },
329dc8ba19STed Chen 	{ 0x0bda, 0x8152 },
339dc8ba19STed Chen 	{ 0x0bda, 0x8153 },
349dc8ba19STed Chen 
359dc8ba19STed Chen 	/* Samsung */
369dc8ba19STed Chen 	{ 0x04e8, 0xa101 },
379dc8ba19STed Chen 
389dc8ba19STed Chen 	/* Lenovo */
399dc8ba19STed Chen 	{ 0x17ef, 0x304f },
409dc8ba19STed Chen 	{ 0x17ef, 0x3052 },
419dc8ba19STed Chen 	{ 0x17ef, 0x3054 },
429dc8ba19STed Chen 	{ 0x17ef, 0x3057 },
439dc8ba19STed Chen 	{ 0x17ef, 0x7205 },
449dc8ba19STed Chen 	{ 0x17ef, 0x720a },
459dc8ba19STed Chen 	{ 0x17ef, 0x720b },
469dc8ba19STed Chen 	{ 0x17ef, 0x720c },
479dc8ba19STed Chen 
489dc8ba19STed Chen 	/* TP-LINK */
499dc8ba19STed Chen 	{ 0x2357, 0x0601 },
509dc8ba19STed Chen 
519dc8ba19STed Chen 	/* Nvidia */
529dc8ba19STed Chen 	{ 0x0955, 0x09ff },
539dc8ba19STed Chen };
546688452aSStefan Roese #endif
556688452aSStefan Roese 
566688452aSStefan Roese struct r8152_version {
576688452aSStefan Roese 	unsigned short tcr;
586688452aSStefan Roese 	unsigned short version;
596688452aSStefan Roese 	bool           gmii;
606688452aSStefan Roese };
619dc8ba19STed Chen 
629dc8ba19STed Chen static const struct r8152_version const r8152_versions[] = {
639dc8ba19STed Chen 	{ 0x4c00, RTL_VER_01, 0 },
649dc8ba19STed Chen 	{ 0x4c10, RTL_VER_02, 0 },
659dc8ba19STed Chen 	{ 0x5c00, RTL_VER_03, 1 },
669dc8ba19STed Chen 	{ 0x5c10, RTL_VER_04, 1 },
679dc8ba19STed Chen 	{ 0x5c20, RTL_VER_05, 1 },
689dc8ba19STed Chen 	{ 0x5c30, RTL_VER_06, 1 },
699dc8ba19STed Chen 	{ 0x4800, RTL_VER_07, 0 },
709dc8ba19STed Chen };
719dc8ba19STed Chen 
729dc8ba19STed Chen static
739dc8ba19STed Chen int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
749dc8ba19STed Chen {
75*c7ac1538SStefan Roese 	ALLOC_CACHE_ALIGN_BUFFER(void *, tmp, size);
76*c7ac1538SStefan Roese 	int ret;
77*c7ac1538SStefan Roese 
78*c7ac1538SStefan Roese 	ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
799dc8ba19STed Chen 		RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
80*c7ac1538SStefan Roese 		value, index, tmp, size, 500);
81*c7ac1538SStefan Roese 	memcpy(data, tmp, size);
82*c7ac1538SStefan Roese 	return ret;
839dc8ba19STed Chen }
849dc8ba19STed Chen 
859dc8ba19STed Chen static
869dc8ba19STed Chen int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
879dc8ba19STed Chen {
88*c7ac1538SStefan Roese 	ALLOC_CACHE_ALIGN_BUFFER(void *, tmp, size);
89*c7ac1538SStefan Roese 
90*c7ac1538SStefan Roese 	memcpy(tmp, data, size);
919dc8ba19STed Chen 	return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
929dc8ba19STed Chen 			       RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
93*c7ac1538SStefan Roese 			       value, index, tmp, size, 500);
949dc8ba19STed Chen }
959dc8ba19STed Chen 
969dc8ba19STed Chen int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
979dc8ba19STed Chen 		     void *data, u16 type)
989dc8ba19STed Chen {
999dc8ba19STed Chen 	u16 burst_size = 64;
1009dc8ba19STed Chen 	int ret;
1019dc8ba19STed Chen 	int txsize;
1029dc8ba19STed Chen 
1039dc8ba19STed Chen 	/* both size and index must be 4 bytes align */
1049dc8ba19STed Chen 	if ((size & 3) || !size || (index & 3) || !data)
1059dc8ba19STed Chen 		return -EINVAL;
1069dc8ba19STed Chen 
1079dc8ba19STed Chen 	if (index + size > 0xffff)
1089dc8ba19STed Chen 		return -EINVAL;
1099dc8ba19STed Chen 
1109dc8ba19STed Chen 	while (size) {
1119dc8ba19STed Chen 		txsize = min(size, burst_size);
1129dc8ba19STed Chen 		ret = get_registers(tp, index, type, txsize, data);
1139dc8ba19STed Chen 		if (ret < 0)
1149dc8ba19STed Chen 			break;
1159dc8ba19STed Chen 
1169dc8ba19STed Chen 		index += txsize;
1179dc8ba19STed Chen 		data += txsize;
1189dc8ba19STed Chen 		size -= txsize;
1199dc8ba19STed Chen 	}
1209dc8ba19STed Chen 
1219dc8ba19STed Chen 	return ret;
1229dc8ba19STed Chen }
1239dc8ba19STed Chen 
1249dc8ba19STed Chen int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
1259dc8ba19STed Chen 		      u16 size, void *data, u16 type)
1269dc8ba19STed Chen {
1279dc8ba19STed Chen 	int ret;
1289dc8ba19STed Chen 	u16 byteen_start, byteen_end, byte_en_to_hw;
1299dc8ba19STed Chen 	u16 burst_size = 512;
1309dc8ba19STed Chen 	int txsize;
1319dc8ba19STed Chen 
1329dc8ba19STed Chen 	/* both size and index must be 4 bytes align */
1339dc8ba19STed Chen 	if ((size & 3) || !size || (index & 3) || !data)
1349dc8ba19STed Chen 		return -EINVAL;
1359dc8ba19STed Chen 
1369dc8ba19STed Chen 	if (index + size > 0xffff)
1379dc8ba19STed Chen 		return -EINVAL;
1389dc8ba19STed Chen 
1399dc8ba19STed Chen 	byteen_start = byteen & BYTE_EN_START_MASK;
1409dc8ba19STed Chen 	byteen_end = byteen & BYTE_EN_END_MASK;
1419dc8ba19STed Chen 
1429dc8ba19STed Chen 	byte_en_to_hw = byteen_start | (byteen_start << 4);
1439dc8ba19STed Chen 	ret = set_registers(tp, index, type | byte_en_to_hw, 4, data);
1449dc8ba19STed Chen 	if (ret < 0)
1459dc8ba19STed Chen 		return ret;
1469dc8ba19STed Chen 
1479dc8ba19STed Chen 	index += 4;
1489dc8ba19STed Chen 	data += 4;
1499dc8ba19STed Chen 	size -= 4;
1509dc8ba19STed Chen 
1519dc8ba19STed Chen 	if (size) {
1529dc8ba19STed Chen 		size -= 4;
1539dc8ba19STed Chen 
1549dc8ba19STed Chen 		while (size) {
1559dc8ba19STed Chen 			txsize = min(size, burst_size);
1569dc8ba19STed Chen 
1579dc8ba19STed Chen 			ret = set_registers(tp, index,
1589dc8ba19STed Chen 					    type | BYTE_EN_DWORD,
1599dc8ba19STed Chen 					    txsize, data);
1609dc8ba19STed Chen 			if (ret < 0)
1619dc8ba19STed Chen 				return ret;
1629dc8ba19STed Chen 
1639dc8ba19STed Chen 			index += txsize;
1649dc8ba19STed Chen 			data += txsize;
1659dc8ba19STed Chen 			size -= txsize;
1669dc8ba19STed Chen 		}
1679dc8ba19STed Chen 
1689dc8ba19STed Chen 		byte_en_to_hw = byteen_end | (byteen_end >> 4);
1699dc8ba19STed Chen 		ret = set_registers(tp, index, type | byte_en_to_hw, 4, data);
1709dc8ba19STed Chen 		if (ret < 0)
1719dc8ba19STed Chen 			return ret;
1729dc8ba19STed Chen 	}
1739dc8ba19STed Chen 
1749dc8ba19STed Chen 	return ret;
1759dc8ba19STed Chen }
1769dc8ba19STed Chen 
1779dc8ba19STed Chen int pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
1789dc8ba19STed Chen {
1799dc8ba19STed Chen 	return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA);
1809dc8ba19STed Chen }
1819dc8ba19STed Chen 
1829dc8ba19STed Chen int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
1839dc8ba19STed Chen {
1849dc8ba19STed Chen 	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA);
1859dc8ba19STed Chen }
1869dc8ba19STed Chen 
1879dc8ba19STed Chen int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
1889dc8ba19STed Chen {
1899dc8ba19STed Chen 	return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB);
1909dc8ba19STed Chen }
1919dc8ba19STed Chen 
1929dc8ba19STed Chen int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
1939dc8ba19STed Chen {
1949dc8ba19STed Chen 	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB);
1959dc8ba19STed Chen }
1969dc8ba19STed Chen 
1979dc8ba19STed Chen u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
1989dc8ba19STed Chen {
1999dc8ba19STed Chen 	__le32 data;
2009dc8ba19STed Chen 
2019dc8ba19STed Chen 	generic_ocp_read(tp, index, sizeof(data), &data, type);
2029dc8ba19STed Chen 
2039dc8ba19STed Chen 	return __le32_to_cpu(data);
2049dc8ba19STed Chen }
2059dc8ba19STed Chen 
2069dc8ba19STed Chen void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
2079dc8ba19STed Chen {
2089dc8ba19STed Chen 	__le32 tmp = __cpu_to_le32(data);
2099dc8ba19STed Chen 
2109dc8ba19STed Chen 	generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
2119dc8ba19STed Chen }
2129dc8ba19STed Chen 
2139dc8ba19STed Chen u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
2149dc8ba19STed Chen {
2159dc8ba19STed Chen 	u32 data;
2169dc8ba19STed Chen 	__le32 tmp;
2179dc8ba19STed Chen 	u8 shift = index & 2;
2189dc8ba19STed Chen 
2199dc8ba19STed Chen 	index &= ~3;
2209dc8ba19STed Chen 
2219dc8ba19STed Chen 	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
2229dc8ba19STed Chen 
2239dc8ba19STed Chen 	data = __le32_to_cpu(tmp);
2249dc8ba19STed Chen 	data >>= (shift * 8);
2259dc8ba19STed Chen 	data &= 0xffff;
2269dc8ba19STed Chen 
2279dc8ba19STed Chen 	return data;
2289dc8ba19STed Chen }
2299dc8ba19STed Chen 
2309dc8ba19STed Chen void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
2319dc8ba19STed Chen {
2329dc8ba19STed Chen 	u32 mask = 0xffff;
2339dc8ba19STed Chen 	__le32 tmp;
2349dc8ba19STed Chen 	u16 byen = BYTE_EN_WORD;
2359dc8ba19STed Chen 	u8 shift = index & 2;
2369dc8ba19STed Chen 
2379dc8ba19STed Chen 	data &= mask;
2389dc8ba19STed Chen 
2399dc8ba19STed Chen 	if (index & 2) {
2409dc8ba19STed Chen 		byen <<= shift;
2419dc8ba19STed Chen 		mask <<= (shift * 8);
2429dc8ba19STed Chen 		data <<= (shift * 8);
2439dc8ba19STed Chen 		index &= ~3;
2449dc8ba19STed Chen 	}
2459dc8ba19STed Chen 
2469dc8ba19STed Chen 	tmp = __cpu_to_le32(data);
2479dc8ba19STed Chen 
2489dc8ba19STed Chen 	generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
2499dc8ba19STed Chen }
2509dc8ba19STed Chen 
2519dc8ba19STed Chen u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
2529dc8ba19STed Chen {
2539dc8ba19STed Chen 	u32 data;
2549dc8ba19STed Chen 	__le32 tmp;
2559dc8ba19STed Chen 	u8 shift = index & 3;
2569dc8ba19STed Chen 
2579dc8ba19STed Chen 	index &= ~3;
2589dc8ba19STed Chen 
2599dc8ba19STed Chen 	generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
2609dc8ba19STed Chen 
2619dc8ba19STed Chen 	data = __le32_to_cpu(tmp);
2629dc8ba19STed Chen 	data >>= (shift * 8);
2639dc8ba19STed Chen 	data &= 0xff;
2649dc8ba19STed Chen 
2659dc8ba19STed Chen 	return data;
2669dc8ba19STed Chen }
2679dc8ba19STed Chen 
2689dc8ba19STed Chen void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
2699dc8ba19STed Chen {
2709dc8ba19STed Chen 	u32 mask = 0xff;
2719dc8ba19STed Chen 	__le32 tmp;
2729dc8ba19STed Chen 	u16 byen = BYTE_EN_BYTE;
2739dc8ba19STed Chen 	u8 shift = index & 3;
2749dc8ba19STed Chen 
2759dc8ba19STed Chen 	data &= mask;
2769dc8ba19STed Chen 
2779dc8ba19STed Chen 	if (index & 3) {
2789dc8ba19STed Chen 		byen <<= shift;
2799dc8ba19STed Chen 		mask <<= (shift * 8);
2809dc8ba19STed Chen 		data <<= (shift * 8);
2819dc8ba19STed Chen 		index &= ~3;
2829dc8ba19STed Chen 	}
2839dc8ba19STed Chen 
2849dc8ba19STed Chen 	tmp = __cpu_to_le32(data);
2859dc8ba19STed Chen 
2869dc8ba19STed Chen 	generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
2879dc8ba19STed Chen }
2889dc8ba19STed Chen 
2899dc8ba19STed Chen u16 ocp_reg_read(struct r8152 *tp, u16 addr)
2909dc8ba19STed Chen {
2919dc8ba19STed Chen 	u16 ocp_base, ocp_index;
2929dc8ba19STed Chen 
2939dc8ba19STed Chen 	ocp_base = addr & 0xf000;
2949dc8ba19STed Chen 	if (ocp_base != tp->ocp_base) {
2959dc8ba19STed Chen 		ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
2969dc8ba19STed Chen 		tp->ocp_base = ocp_base;
2979dc8ba19STed Chen 	}
2989dc8ba19STed Chen 
2999dc8ba19STed Chen 	ocp_index = (addr & 0x0fff) | 0xb000;
3009dc8ba19STed Chen 	return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index);
3019dc8ba19STed Chen }
3029dc8ba19STed Chen 
3039dc8ba19STed Chen void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
3049dc8ba19STed Chen {
3059dc8ba19STed Chen 	u16 ocp_base, ocp_index;
3069dc8ba19STed Chen 
3079dc8ba19STed Chen 	ocp_base = addr & 0xf000;
3089dc8ba19STed Chen 	if (ocp_base != tp->ocp_base) {
3099dc8ba19STed Chen 		ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
3109dc8ba19STed Chen 		tp->ocp_base = ocp_base;
3119dc8ba19STed Chen 	}
3129dc8ba19STed Chen 
3139dc8ba19STed Chen 	ocp_index = (addr & 0x0fff) | 0xb000;
3149dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
3159dc8ba19STed Chen }
3169dc8ba19STed Chen 
3179dc8ba19STed Chen static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
3189dc8ba19STed Chen {
3199dc8ba19STed Chen 	ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value);
3209dc8ba19STed Chen }
3219dc8ba19STed Chen 
3229dc8ba19STed Chen static int r8152_mdio_read(struct r8152 *tp, u32 reg_addr)
3239dc8ba19STed Chen {
3249dc8ba19STed Chen 	return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2);
3259dc8ba19STed Chen }
3269dc8ba19STed Chen 
3279dc8ba19STed Chen void sram_write(struct r8152 *tp, u16 addr, u16 data)
3289dc8ba19STed Chen {
3299dc8ba19STed Chen 	ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
3309dc8ba19STed Chen 	ocp_reg_write(tp, OCP_SRAM_DATA, data);
3319dc8ba19STed Chen }
3329dc8ba19STed Chen 
3339dc8ba19STed Chen int r8152_wait_for_bit(struct r8152 *tp, bool ocp_reg, u16 type, u16 index,
3349dc8ba19STed Chen 		       const u32 mask, bool set, unsigned int timeout)
3359dc8ba19STed Chen {
3369dc8ba19STed Chen 	u32 val;
3379dc8ba19STed Chen 
3389dc8ba19STed Chen 	while (--timeout) {
3399dc8ba19STed Chen 		if (ocp_reg)
3409dc8ba19STed Chen 			val = ocp_reg_read(tp, index);
3419dc8ba19STed Chen 		else
3429dc8ba19STed Chen 			val = ocp_read_dword(tp, type, index);
3439dc8ba19STed Chen 
3449dc8ba19STed Chen 		if (!set)
3459dc8ba19STed Chen 			val = ~val;
3469dc8ba19STed Chen 
3479dc8ba19STed Chen 		if ((val & mask) == mask)
3489dc8ba19STed Chen 			return 0;
3499dc8ba19STed Chen 
3509dc8ba19STed Chen 		mdelay(1);
3519dc8ba19STed Chen 	}
3529dc8ba19STed Chen 
3539dc8ba19STed Chen 	debug("%s: Timeout (index=%04x mask=%08x timeout=%d)\n",
3549dc8ba19STed Chen 	      __func__, index, mask, timeout);
3559dc8ba19STed Chen 
3569dc8ba19STed Chen 	return -ETIMEDOUT;
3579dc8ba19STed Chen }
3589dc8ba19STed Chen 
3599dc8ba19STed Chen static void r8152b_reset_packet_filter(struct r8152 *tp)
3609dc8ba19STed Chen {
3619dc8ba19STed Chen 	u32 ocp_data;
3629dc8ba19STed Chen 
3639dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC);
3649dc8ba19STed Chen 	ocp_data &= ~FMC_FCR_MCU_EN;
3659dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
3669dc8ba19STed Chen 	ocp_data |= FMC_FCR_MCU_EN;
3679dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
3689dc8ba19STed Chen }
3699dc8ba19STed Chen 
3709dc8ba19STed Chen static void rtl8152_wait_fifo_empty(struct r8152 *tp)
3719dc8ba19STed Chen {
3729dc8ba19STed Chen 	int ret;
3739dc8ba19STed Chen 
3749dc8ba19STed Chen 	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_PHY_PWR,
3759dc8ba19STed Chen 				 PLA_PHY_PWR_TXEMP, 1, R8152_WAIT_TIMEOUT);
3769dc8ba19STed Chen 	if (ret)
3779dc8ba19STed Chen 		debug("Timeout waiting for FIFO empty\n");
3789dc8ba19STed Chen 
3799dc8ba19STed Chen 	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_TCR0,
3809dc8ba19STed Chen 				 TCR0_TX_EMPTY, 1, R8152_WAIT_TIMEOUT);
3819dc8ba19STed Chen 	if (ret)
3829dc8ba19STed Chen 		debug("Timeout waiting for TX empty\n");
3839dc8ba19STed Chen }
3849dc8ba19STed Chen 
3859dc8ba19STed Chen static void rtl8152_nic_reset(struct r8152 *tp)
3869dc8ba19STed Chen {
3879dc8ba19STed Chen 	int ret;
3889dc8ba19STed Chen 	u32 ocp_data;
3899dc8ba19STed Chen 
3909dc8ba19STed Chen 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, BIST_CTRL);
3919dc8ba19STed Chen 	ocp_data |= BIST_CTRL_SW_RESET;
3929dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, BIST_CTRL, ocp_data);
3939dc8ba19STed Chen 
3949dc8ba19STed Chen 	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, BIST_CTRL,
3959dc8ba19STed Chen 				 BIST_CTRL_SW_RESET, 0, R8152_WAIT_TIMEOUT);
3969dc8ba19STed Chen 	if (ret)
3979dc8ba19STed Chen 		debug("Timeout waiting for NIC reset\n");
3989dc8ba19STed Chen }
3999dc8ba19STed Chen 
4009dc8ba19STed Chen static u8 rtl8152_get_speed(struct r8152 *tp)
4019dc8ba19STed Chen {
4029dc8ba19STed Chen 	return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
4039dc8ba19STed Chen }
4049dc8ba19STed Chen 
4059dc8ba19STed Chen static void rtl_set_eee_plus(struct r8152 *tp)
4069dc8ba19STed Chen {
4079dc8ba19STed Chen 	u32 ocp_data;
4089dc8ba19STed Chen 
4099dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
4109dc8ba19STed Chen 	ocp_data &= ~EEEP_CR_EEEP_TX;
4119dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
4129dc8ba19STed Chen }
4139dc8ba19STed Chen 
4149dc8ba19STed Chen static void rxdy_gated_en(struct r8152 *tp, bool enable)
4159dc8ba19STed Chen {
4169dc8ba19STed Chen 	u32 ocp_data;
4179dc8ba19STed Chen 
4189dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
4199dc8ba19STed Chen 	if (enable)
4209dc8ba19STed Chen 		ocp_data |= RXDY_GATED_EN;
4219dc8ba19STed Chen 	else
4229dc8ba19STed Chen 		ocp_data &= ~RXDY_GATED_EN;
4239dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
4249dc8ba19STed Chen }
4259dc8ba19STed Chen 
4269dc8ba19STed Chen static void rtl8152_set_rx_mode(struct r8152 *tp)
4279dc8ba19STed Chen {
4289dc8ba19STed Chen 	u32 ocp_data;
4299dc8ba19STed Chen 	__le32 tmp[2];
4309dc8ba19STed Chen 
4319dc8ba19STed Chen 	tmp[0] = 0xffffffff;
4329dc8ba19STed Chen 	tmp[1] = 0xffffffff;
4339dc8ba19STed Chen 
4349dc8ba19STed Chen 	pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp);
4359dc8ba19STed Chen 
4369dc8ba19STed Chen 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
4379dc8ba19STed Chen 	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
4389dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
4399dc8ba19STed Chen }
4409dc8ba19STed Chen 
4419dc8ba19STed Chen static int rtl_enable(struct r8152 *tp)
4429dc8ba19STed Chen {
4439dc8ba19STed Chen 	u32 ocp_data;
4449dc8ba19STed Chen 
4459dc8ba19STed Chen 	r8152b_reset_packet_filter(tp);
4469dc8ba19STed Chen 
4479dc8ba19STed Chen 	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
4489dc8ba19STed Chen 	ocp_data |= PLA_CR_RE | PLA_CR_TE;
4499dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
4509dc8ba19STed Chen 
4519dc8ba19STed Chen 	rxdy_gated_en(tp, false);
4529dc8ba19STed Chen 
4539dc8ba19STed Chen 	rtl8152_set_rx_mode(tp);
4549dc8ba19STed Chen 
4559dc8ba19STed Chen 	return 0;
4569dc8ba19STed Chen }
4579dc8ba19STed Chen 
4589dc8ba19STed Chen static int rtl8152_enable(struct r8152 *tp)
4599dc8ba19STed Chen {
4609dc8ba19STed Chen 	rtl_set_eee_plus(tp);
4619dc8ba19STed Chen 
4629dc8ba19STed Chen 	return rtl_enable(tp);
4639dc8ba19STed Chen }
4649dc8ba19STed Chen 
4659dc8ba19STed Chen static void r8153_set_rx_early_timeout(struct r8152 *tp)
4669dc8ba19STed Chen {
4679dc8ba19STed Chen 	u32 ocp_data = tp->coalesce / 8;
4689dc8ba19STed Chen 
4699dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_TIMEOUT, ocp_data);
4709dc8ba19STed Chen }
4719dc8ba19STed Chen 
4729dc8ba19STed Chen static void r8153_set_rx_early_size(struct r8152 *tp)
4739dc8ba19STed Chen {
4749dc8ba19STed Chen 	u32 ocp_data = (RTL8152_AGG_BUF_SZ - RTL8153_RMS) / 4;
4759dc8ba19STed Chen 
4769dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ocp_data);
4779dc8ba19STed Chen }
4789dc8ba19STed Chen 
4799dc8ba19STed Chen static int rtl8153_enable(struct r8152 *tp)
4809dc8ba19STed Chen {
4819dc8ba19STed Chen 	rtl_set_eee_plus(tp);
4829dc8ba19STed Chen 	r8153_set_rx_early_timeout(tp);
4839dc8ba19STed Chen 	r8153_set_rx_early_size(tp);
4849dc8ba19STed Chen 
4859dc8ba19STed Chen 	return rtl_enable(tp);
4869dc8ba19STed Chen }
4879dc8ba19STed Chen 
4889dc8ba19STed Chen static void rtl_disable(struct r8152 *tp)
4899dc8ba19STed Chen {
4909dc8ba19STed Chen 	u32 ocp_data;
4919dc8ba19STed Chen 
4929dc8ba19STed Chen 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
4939dc8ba19STed Chen 	ocp_data &= ~RCR_ACPT_ALL;
4949dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
4959dc8ba19STed Chen 
4969dc8ba19STed Chen 	rxdy_gated_en(tp, true);
4979dc8ba19STed Chen 
4989dc8ba19STed Chen 	rtl8152_wait_fifo_empty(tp);
4999dc8ba19STed Chen 	rtl8152_nic_reset(tp);
5009dc8ba19STed Chen }
5019dc8ba19STed Chen 
5029dc8ba19STed Chen static void r8152_power_cut_en(struct r8152 *tp, bool enable)
5039dc8ba19STed Chen {
5049dc8ba19STed Chen 	u32 ocp_data;
5059dc8ba19STed Chen 
5069dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
5079dc8ba19STed Chen 	if (enable)
5089dc8ba19STed Chen 		ocp_data |= POWER_CUT;
5099dc8ba19STed Chen 	else
5109dc8ba19STed Chen 		ocp_data &= ~POWER_CUT;
5119dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
5129dc8ba19STed Chen 
5139dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
5149dc8ba19STed Chen 	ocp_data &= ~RESUME_INDICATE;
5159dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
5169dc8ba19STed Chen }
5179dc8ba19STed Chen 
5189dc8ba19STed Chen static void rtl_rx_vlan_en(struct r8152 *tp, bool enable)
5199dc8ba19STed Chen {
5209dc8ba19STed Chen 	u32 ocp_data;
5219dc8ba19STed Chen 
5229dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
5239dc8ba19STed Chen 	if (enable)
5249dc8ba19STed Chen 		ocp_data |= CPCR_RX_VLAN;
5259dc8ba19STed Chen 	else
5269dc8ba19STed Chen 		ocp_data &= ~CPCR_RX_VLAN;
5279dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
5289dc8ba19STed Chen }
5299dc8ba19STed Chen 
5309dc8ba19STed Chen static void r8153_u1u2en(struct r8152 *tp, bool enable)
5319dc8ba19STed Chen {
5329dc8ba19STed Chen 	u8 u1u2[8];
5339dc8ba19STed Chen 
5349dc8ba19STed Chen 	if (enable)
5359dc8ba19STed Chen 		memset(u1u2, 0xff, sizeof(u1u2));
5369dc8ba19STed Chen 	else
5379dc8ba19STed Chen 		memset(u1u2, 0x00, sizeof(u1u2));
5389dc8ba19STed Chen 
5399dc8ba19STed Chen 	usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
5409dc8ba19STed Chen }
5419dc8ba19STed Chen 
5429dc8ba19STed Chen static void r8153_u2p3en(struct r8152 *tp, bool enable)
5439dc8ba19STed Chen {
5449dc8ba19STed Chen 	u32 ocp_data;
5459dc8ba19STed Chen 
5469dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL);
5479dc8ba19STed Chen 	if (enable && tp->version != RTL_VER_03 && tp->version != RTL_VER_04)
5489dc8ba19STed Chen 		ocp_data |= U2P3_ENABLE;
5499dc8ba19STed Chen 	else
5509dc8ba19STed Chen 		ocp_data &= ~U2P3_ENABLE;
5519dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
5529dc8ba19STed Chen }
5539dc8ba19STed Chen 
5549dc8ba19STed Chen static void r8153_power_cut_en(struct r8152 *tp, bool enable)
5559dc8ba19STed Chen {
5569dc8ba19STed Chen 	u32 ocp_data;
5579dc8ba19STed Chen 
5589dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT);
5599dc8ba19STed Chen 	if (enable)
5609dc8ba19STed Chen 		ocp_data |= PWR_EN | PHASE2_EN;
5619dc8ba19STed Chen 	else
5629dc8ba19STed Chen 		ocp_data &= ~(PWR_EN | PHASE2_EN);
5639dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data);
5649dc8ba19STed Chen 
5659dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
5669dc8ba19STed Chen 	ocp_data &= ~PCUT_STATUS;
5679dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
5689dc8ba19STed Chen }
5699dc8ba19STed Chen 
5709dc8ba19STed Chen static int r8152_read_mac(struct r8152 *tp, unsigned char *macaddr)
5719dc8ba19STed Chen {
5729dc8ba19STed Chen 	int ret;
5739dc8ba19STed Chen 	unsigned char enetaddr[8] = {0};
5749dc8ba19STed Chen 
5759dc8ba19STed Chen 	ret = pla_ocp_read(tp, PLA_IDR, 8, enetaddr);
5769dc8ba19STed Chen 	if (ret < 0)
5779dc8ba19STed Chen 		return ret;
5789dc8ba19STed Chen 
5799dc8ba19STed Chen 	memcpy(macaddr, enetaddr, ETH_ALEN);
5809dc8ba19STed Chen 	return 0;
5819dc8ba19STed Chen }
5829dc8ba19STed Chen 
5839dc8ba19STed Chen static void r8152b_disable_aldps(struct r8152 *tp)
5849dc8ba19STed Chen {
5859dc8ba19STed Chen 	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
5869dc8ba19STed Chen 	mdelay(20);
5879dc8ba19STed Chen }
5889dc8ba19STed Chen 
5899dc8ba19STed Chen static void r8152b_enable_aldps(struct r8152 *tp)
5909dc8ba19STed Chen {
5919dc8ba19STed Chen 	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
5929dc8ba19STed Chen 		LINKENA | DIS_SDSAVE);
5939dc8ba19STed Chen }
5949dc8ba19STed Chen 
5959dc8ba19STed Chen static void rtl8152_disable(struct r8152 *tp)
5969dc8ba19STed Chen {
5979dc8ba19STed Chen 	r8152b_disable_aldps(tp);
5989dc8ba19STed Chen 	rtl_disable(tp);
5999dc8ba19STed Chen 	r8152b_enable_aldps(tp);
6009dc8ba19STed Chen }
6019dc8ba19STed Chen 
6029dc8ba19STed Chen static void r8152b_hw_phy_cfg(struct r8152 *tp)
6039dc8ba19STed Chen {
6049dc8ba19STed Chen 	u16 data;
6059dc8ba19STed Chen 
6069dc8ba19STed Chen 	data = r8152_mdio_read(tp, MII_BMCR);
6079dc8ba19STed Chen 	if (data & BMCR_PDOWN) {
6089dc8ba19STed Chen 		data &= ~BMCR_PDOWN;
6099dc8ba19STed Chen 		r8152_mdio_write(tp, MII_BMCR, data);
6109dc8ba19STed Chen 	}
6119dc8ba19STed Chen 
6129dc8ba19STed Chen 	r8152b_firmware(tp);
6139dc8ba19STed Chen }
6149dc8ba19STed Chen 
6159dc8ba19STed Chen static void rtl8152_reinit_ll(struct r8152 *tp)
6169dc8ba19STed Chen {
6179dc8ba19STed Chen 	u32 ocp_data;
6189dc8ba19STed Chen 	int ret;
6199dc8ba19STed Chen 
6209dc8ba19STed Chen 	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_PHY_PWR,
6219dc8ba19STed Chen 				 PLA_PHY_PWR_LLR, 1, R8152_WAIT_TIMEOUT);
6229dc8ba19STed Chen 	if (ret)
6239dc8ba19STed Chen 		debug("Timeout waiting for link list ready\n");
6249dc8ba19STed Chen 
6259dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
6269dc8ba19STed Chen 	ocp_data |= RE_INIT_LL;
6279dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
6289dc8ba19STed Chen 
6299dc8ba19STed Chen 	ret = r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_PHY_PWR,
6309dc8ba19STed Chen 				 PLA_PHY_PWR_LLR, 1, R8152_WAIT_TIMEOUT);
6319dc8ba19STed Chen 	if (ret)
6329dc8ba19STed Chen 		debug("Timeout waiting for link list ready\n");
6339dc8ba19STed Chen }
6349dc8ba19STed Chen 
6359dc8ba19STed Chen static void r8152b_exit_oob(struct r8152 *tp)
6369dc8ba19STed Chen {
6379dc8ba19STed Chen 	u32 ocp_data;
6389dc8ba19STed Chen 
6399dc8ba19STed Chen 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
6409dc8ba19STed Chen 	ocp_data &= ~RCR_ACPT_ALL;
6419dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
6429dc8ba19STed Chen 
6439dc8ba19STed Chen 	rxdy_gated_en(tp, true);
6449dc8ba19STed Chen 	r8152b_hw_phy_cfg(tp);
6459dc8ba19STed Chen 
6469dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
6479dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
6489dc8ba19STed Chen 
6499dc8ba19STed Chen 	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
6509dc8ba19STed Chen 	ocp_data &= ~NOW_IS_OOB;
6519dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
6529dc8ba19STed Chen 
6539dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
6549dc8ba19STed Chen 	ocp_data &= ~MCU_BORW_EN;
6559dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
6569dc8ba19STed Chen 
6579dc8ba19STed Chen 	rtl8152_reinit_ll(tp);
6589dc8ba19STed Chen 	rtl8152_nic_reset(tp);
6599dc8ba19STed Chen 
6609dc8ba19STed Chen 	/* rx share fifo credit full threshold */
6619dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
6629dc8ba19STed Chen 
6639dc8ba19STed Chen 	if (tp->udev->speed == USB_SPEED_FULL ||
6649dc8ba19STed Chen 	    tp->udev->speed == USB_SPEED_LOW) {
6659dc8ba19STed Chen 		/* rx share fifo credit near full threshold */
6669dc8ba19STed Chen 		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
6679dc8ba19STed Chen 				RXFIFO_THR2_FULL);
6689dc8ba19STed Chen 		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
6699dc8ba19STed Chen 				RXFIFO_THR3_FULL);
6709dc8ba19STed Chen 	} else {
6719dc8ba19STed Chen 		/* rx share fifo credit near full threshold */
6729dc8ba19STed Chen 		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
6739dc8ba19STed Chen 				RXFIFO_THR2_HIGH);
6749dc8ba19STed Chen 		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
6759dc8ba19STed Chen 				RXFIFO_THR3_HIGH);
6769dc8ba19STed Chen 	}
6779dc8ba19STed Chen 
6789dc8ba19STed Chen 	/* TX share fifo free credit full threshold */
6799dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL);
6809dc8ba19STed Chen 
6819dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
6829dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
6839dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
6849dc8ba19STed Chen 			TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
6859dc8ba19STed Chen 
6869dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
6879dc8ba19STed Chen 
6889dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
6899dc8ba19STed Chen 	ocp_data |= TCR0_AUTO_FIFO;
6909dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
6919dc8ba19STed Chen }
6929dc8ba19STed Chen 
6939dc8ba19STed Chen static void r8152b_enter_oob(struct r8152 *tp)
6949dc8ba19STed Chen {
6959dc8ba19STed Chen 	u32 ocp_data;
6969dc8ba19STed Chen 
6979dc8ba19STed Chen 	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
6989dc8ba19STed Chen 	ocp_data &= ~NOW_IS_OOB;
6999dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
7009dc8ba19STed Chen 
7019dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
7029dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
7039dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
7049dc8ba19STed Chen 
7059dc8ba19STed Chen 	rtl_disable(tp);
7069dc8ba19STed Chen 
7079dc8ba19STed Chen 	rtl8152_reinit_ll(tp);
7089dc8ba19STed Chen 
7099dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
7109dc8ba19STed Chen 
7119dc8ba19STed Chen 	rtl_rx_vlan_en(tp, false);
7129dc8ba19STed Chen 
7139dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR);
7149dc8ba19STed Chen 	ocp_data |= ALDPS_PROXY_MODE;
7159dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data);
7169dc8ba19STed Chen 
7179dc8ba19STed Chen 	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
7189dc8ba19STed Chen 	ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
7199dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
7209dc8ba19STed Chen 
7219dc8ba19STed Chen 	rxdy_gated_en(tp, false);
7229dc8ba19STed Chen 
7239dc8ba19STed Chen 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
7249dc8ba19STed Chen 	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
7259dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
7269dc8ba19STed Chen }
7279dc8ba19STed Chen 
7289dc8ba19STed Chen static void r8153_hw_phy_cfg(struct r8152 *tp)
7299dc8ba19STed Chen {
7309dc8ba19STed Chen 	u32 ocp_data;
7319dc8ba19STed Chen 	u16 data;
7329dc8ba19STed Chen 
7339dc8ba19STed Chen 	if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 ||
7349dc8ba19STed Chen 	    tp->version == RTL_VER_05)
7359dc8ba19STed Chen 		ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L);
7369dc8ba19STed Chen 
7379dc8ba19STed Chen 	data = r8152_mdio_read(tp, MII_BMCR);
7389dc8ba19STed Chen 	if (data & BMCR_PDOWN) {
7399dc8ba19STed Chen 		data &= ~BMCR_PDOWN;
7409dc8ba19STed Chen 		r8152_mdio_write(tp, MII_BMCR, data);
7419dc8ba19STed Chen 	}
7429dc8ba19STed Chen 
7439dc8ba19STed Chen 	r8153_firmware(tp);
7449dc8ba19STed Chen 
7459dc8ba19STed Chen 	if (tp->version == RTL_VER_03) {
7469dc8ba19STed Chen 		data = ocp_reg_read(tp, OCP_EEE_CFG);
7479dc8ba19STed Chen 		data &= ~CTAP_SHORT_EN;
7489dc8ba19STed Chen 		ocp_reg_write(tp, OCP_EEE_CFG, data);
7499dc8ba19STed Chen 	}
7509dc8ba19STed Chen 
7519dc8ba19STed Chen 	data = ocp_reg_read(tp, OCP_POWER_CFG);
7529dc8ba19STed Chen 	data |= EEE_CLKDIV_EN;
7539dc8ba19STed Chen 	ocp_reg_write(tp, OCP_POWER_CFG, data);
7549dc8ba19STed Chen 
7559dc8ba19STed Chen 	data = ocp_reg_read(tp, OCP_DOWN_SPEED);
7569dc8ba19STed Chen 	data |= EN_10M_BGOFF;
7579dc8ba19STed Chen 	ocp_reg_write(tp, OCP_DOWN_SPEED, data);
7589dc8ba19STed Chen 	data = ocp_reg_read(tp, OCP_POWER_CFG);
7599dc8ba19STed Chen 	data |= EN_10M_PLLOFF;
7609dc8ba19STed Chen 	ocp_reg_write(tp, OCP_POWER_CFG, data);
7619dc8ba19STed Chen 	sram_write(tp, SRAM_IMPEDANCE, 0x0b13);
7629dc8ba19STed Chen 
7639dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
7649dc8ba19STed Chen 	ocp_data |= PFM_PWM_SWITCH;
7659dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
7669dc8ba19STed Chen 
7679dc8ba19STed Chen 	/* Enable LPF corner auto tune */
7689dc8ba19STed Chen 	sram_write(tp, SRAM_LPF_CFG, 0xf70f);
7699dc8ba19STed Chen 
7709dc8ba19STed Chen 	/* Adjust 10M Amplitude */
7719dc8ba19STed Chen 	sram_write(tp, SRAM_10M_AMP1, 0x00af);
7729dc8ba19STed Chen 	sram_write(tp, SRAM_10M_AMP2, 0x0208);
7739dc8ba19STed Chen }
7749dc8ba19STed Chen 
7759dc8ba19STed Chen static void r8153_first_init(struct r8152 *tp)
7769dc8ba19STed Chen {
7779dc8ba19STed Chen 	u32 ocp_data;
7789dc8ba19STed Chen 
7799dc8ba19STed Chen 	rxdy_gated_en(tp, true);
7809dc8ba19STed Chen 
7819dc8ba19STed Chen 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
7829dc8ba19STed Chen 	ocp_data &= ~RCR_ACPT_ALL;
7839dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
7849dc8ba19STed Chen 
7859dc8ba19STed Chen 	r8153_hw_phy_cfg(tp);
7869dc8ba19STed Chen 
7879dc8ba19STed Chen 	rtl8152_nic_reset(tp);
7889dc8ba19STed Chen 
7899dc8ba19STed Chen 	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
7909dc8ba19STed Chen 	ocp_data &= ~NOW_IS_OOB;
7919dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
7929dc8ba19STed Chen 
7939dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
7949dc8ba19STed Chen 	ocp_data &= ~MCU_BORW_EN;
7959dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
7969dc8ba19STed Chen 
7979dc8ba19STed Chen 	rtl8152_reinit_ll(tp);
7989dc8ba19STed Chen 
7999dc8ba19STed Chen 	rtl_rx_vlan_en(tp, false);
8009dc8ba19STed Chen 
8019dc8ba19STed Chen 	ocp_data = RTL8153_RMS;
8029dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data);
8039dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO);
8049dc8ba19STed Chen 
8059dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
8069dc8ba19STed Chen 	ocp_data |= TCR0_AUTO_FIFO;
8079dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
8089dc8ba19STed Chen 
8099dc8ba19STed Chen 	rtl8152_nic_reset(tp);
8109dc8ba19STed Chen 
8119dc8ba19STed Chen 	/* rx share fifo credit full threshold */
8129dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
8139dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL);
8149dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL);
8159dc8ba19STed Chen 	/* TX share fifo free credit full threshold */
8169dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
8179dc8ba19STed Chen 
8189dc8ba19STed Chen 	/* rx aggregation */
8199dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
8209dc8ba19STed Chen 
8219dc8ba19STed Chen 	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
8229dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
8239dc8ba19STed Chen }
8249dc8ba19STed Chen 
8259dc8ba19STed Chen static void r8153_enter_oob(struct r8152 *tp)
8269dc8ba19STed Chen {
8279dc8ba19STed Chen 	u32 ocp_data;
8289dc8ba19STed Chen 
8299dc8ba19STed Chen 	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
8309dc8ba19STed Chen 	ocp_data &= ~NOW_IS_OOB;
8319dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
8329dc8ba19STed Chen 
8339dc8ba19STed Chen 	rtl_disable(tp);
8349dc8ba19STed Chen 
8359dc8ba19STed Chen 	rtl8152_reinit_ll(tp);
8369dc8ba19STed Chen 
8379dc8ba19STed Chen 	ocp_data = RTL8153_RMS;
8389dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data);
8399dc8ba19STed Chen 
8409dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
8419dc8ba19STed Chen 	ocp_data &= ~TEREDO_WAKE_MASK;
8429dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
8439dc8ba19STed Chen 
8449dc8ba19STed Chen 	rtl_rx_vlan_en(tp, false);
8459dc8ba19STed Chen 
8469dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR);
8479dc8ba19STed Chen 	ocp_data |= ALDPS_PROXY_MODE;
8489dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data);
8499dc8ba19STed Chen 
8509dc8ba19STed Chen 	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
8519dc8ba19STed Chen 	ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
8529dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
8539dc8ba19STed Chen 
8549dc8ba19STed Chen 	rxdy_gated_en(tp, false);
8559dc8ba19STed Chen 
8569dc8ba19STed Chen 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
8579dc8ba19STed Chen 	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
8589dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
8599dc8ba19STed Chen }
8609dc8ba19STed Chen 
8619dc8ba19STed Chen static void r8153_disable_aldps(struct r8152 *tp)
8629dc8ba19STed Chen {
8639dc8ba19STed Chen 	u16 data;
8649dc8ba19STed Chen 
8659dc8ba19STed Chen 	data = ocp_reg_read(tp, OCP_POWER_CFG);
8669dc8ba19STed Chen 	data &= ~EN_ALDPS;
8679dc8ba19STed Chen 	ocp_reg_write(tp, OCP_POWER_CFG, data);
8689dc8ba19STed Chen 	mdelay(20);
8699dc8ba19STed Chen }
8709dc8ba19STed Chen 
8719dc8ba19STed Chen static void rtl8153_disable(struct r8152 *tp)
8729dc8ba19STed Chen {
8739dc8ba19STed Chen 	r8153_disable_aldps(tp);
8749dc8ba19STed Chen 	rtl_disable(tp);
8759dc8ba19STed Chen }
8769dc8ba19STed Chen 
8779dc8ba19STed Chen static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
8789dc8ba19STed Chen {
8799dc8ba19STed Chen 	u16 bmcr, anar, gbcr;
8809dc8ba19STed Chen 
8819dc8ba19STed Chen 	anar = r8152_mdio_read(tp, MII_ADVERTISE);
8829dc8ba19STed Chen 	anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
8839dc8ba19STed Chen 		  ADVERTISE_100HALF | ADVERTISE_100FULL);
8849dc8ba19STed Chen 	if (tp->supports_gmii) {
8859dc8ba19STed Chen 		gbcr = r8152_mdio_read(tp, MII_CTRL1000);
8869dc8ba19STed Chen 		gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
8879dc8ba19STed Chen 	} else {
8889dc8ba19STed Chen 		gbcr = 0;
8899dc8ba19STed Chen 	}
8909dc8ba19STed Chen 
8919dc8ba19STed Chen 	if (autoneg == AUTONEG_DISABLE) {
8929dc8ba19STed Chen 		if (speed == SPEED_10) {
8939dc8ba19STed Chen 			bmcr = 0;
8949dc8ba19STed Chen 			anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
8959dc8ba19STed Chen 		} else if (speed == SPEED_100) {
8969dc8ba19STed Chen 			bmcr = BMCR_SPEED100;
8979dc8ba19STed Chen 			anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
8989dc8ba19STed Chen 		} else if (speed == SPEED_1000 && tp->supports_gmii) {
8999dc8ba19STed Chen 			bmcr = BMCR_SPEED1000;
9009dc8ba19STed Chen 			gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
9019dc8ba19STed Chen 		} else {
9029dc8ba19STed Chen 			return -EINVAL;
9039dc8ba19STed Chen 		}
9049dc8ba19STed Chen 
9059dc8ba19STed Chen 		if (duplex == DUPLEX_FULL)
9069dc8ba19STed Chen 			bmcr |= BMCR_FULLDPLX;
9079dc8ba19STed Chen 	} else {
9089dc8ba19STed Chen 		if (speed == SPEED_10) {
9099dc8ba19STed Chen 			if (duplex == DUPLEX_FULL)
9109dc8ba19STed Chen 				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
9119dc8ba19STed Chen 			else
9129dc8ba19STed Chen 				anar |= ADVERTISE_10HALF;
9139dc8ba19STed Chen 		} else if (speed == SPEED_100) {
9149dc8ba19STed Chen 			if (duplex == DUPLEX_FULL) {
9159dc8ba19STed Chen 				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
9169dc8ba19STed Chen 				anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
9179dc8ba19STed Chen 			} else {
9189dc8ba19STed Chen 				anar |= ADVERTISE_10HALF;
9199dc8ba19STed Chen 				anar |= ADVERTISE_100HALF;
9209dc8ba19STed Chen 			}
9219dc8ba19STed Chen 		} else if (speed == SPEED_1000 && tp->supports_gmii) {
9229dc8ba19STed Chen 			if (duplex == DUPLEX_FULL) {
9239dc8ba19STed Chen 				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
9249dc8ba19STed Chen 				anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
9259dc8ba19STed Chen 				gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
9269dc8ba19STed Chen 			} else {
9279dc8ba19STed Chen 				anar |= ADVERTISE_10HALF;
9289dc8ba19STed Chen 				anar |= ADVERTISE_100HALF;
9299dc8ba19STed Chen 				gbcr |= ADVERTISE_1000HALF;
9309dc8ba19STed Chen 			}
9319dc8ba19STed Chen 		} else {
9329dc8ba19STed Chen 			return -EINVAL;
9339dc8ba19STed Chen 		}
9349dc8ba19STed Chen 
9359dc8ba19STed Chen 		bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
9369dc8ba19STed Chen 	}
9379dc8ba19STed Chen 
9389dc8ba19STed Chen 	if (tp->supports_gmii)
9399dc8ba19STed Chen 		r8152_mdio_write(tp, MII_CTRL1000, gbcr);
9409dc8ba19STed Chen 
9419dc8ba19STed Chen 	r8152_mdio_write(tp, MII_ADVERTISE, anar);
9429dc8ba19STed Chen 	r8152_mdio_write(tp, MII_BMCR, bmcr);
9439dc8ba19STed Chen 
9449dc8ba19STed Chen 	return 0;
9459dc8ba19STed Chen }
9469dc8ba19STed Chen 
9479dc8ba19STed Chen static void rtl8152_up(struct r8152 *tp)
9489dc8ba19STed Chen {
9499dc8ba19STed Chen 	r8152b_disable_aldps(tp);
9509dc8ba19STed Chen 	r8152b_exit_oob(tp);
9519dc8ba19STed Chen 	r8152b_enable_aldps(tp);
9529dc8ba19STed Chen }
9539dc8ba19STed Chen 
9549dc8ba19STed Chen static void rtl8152_down(struct r8152 *tp)
9559dc8ba19STed Chen {
9569dc8ba19STed Chen 	r8152_power_cut_en(tp, false);
9579dc8ba19STed Chen 	r8152b_disable_aldps(tp);
9589dc8ba19STed Chen 	r8152b_enter_oob(tp);
9599dc8ba19STed Chen 	r8152b_enable_aldps(tp);
9609dc8ba19STed Chen }
9619dc8ba19STed Chen 
9629dc8ba19STed Chen static void rtl8153_up(struct r8152 *tp)
9639dc8ba19STed Chen {
9649dc8ba19STed Chen 	r8153_u1u2en(tp, false);
9659dc8ba19STed Chen 	r8153_disable_aldps(tp);
9669dc8ba19STed Chen 	r8153_first_init(tp);
9679dc8ba19STed Chen 	r8153_u2p3en(tp, false);
9689dc8ba19STed Chen }
9699dc8ba19STed Chen 
9709dc8ba19STed Chen static void rtl8153_down(struct r8152 *tp)
9719dc8ba19STed Chen {
9729dc8ba19STed Chen 	r8153_u1u2en(tp, false);
9739dc8ba19STed Chen 	r8153_u2p3en(tp, false);
9749dc8ba19STed Chen 	r8153_power_cut_en(tp, false);
9759dc8ba19STed Chen 	r8153_disable_aldps(tp);
9769dc8ba19STed Chen 	r8153_enter_oob(tp);
9779dc8ba19STed Chen }
9789dc8ba19STed Chen 
9799dc8ba19STed Chen static void r8152b_get_version(struct r8152 *tp)
9809dc8ba19STed Chen {
9819dc8ba19STed Chen 	u32 ocp_data;
9829dc8ba19STed Chen 	u16 tcr;
9839dc8ba19STed Chen 	int i;
9849dc8ba19STed Chen 
9859dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1);
9869dc8ba19STed Chen 	tcr = (u16)(ocp_data & VERSION_MASK);
9879dc8ba19STed Chen 
9889dc8ba19STed Chen 	for (i = 0; i < ARRAY_SIZE(r8152_versions); i++) {
9899dc8ba19STed Chen 		if (tcr == r8152_versions[i].tcr) {
9909dc8ba19STed Chen 			/* Found a supported version */
9919dc8ba19STed Chen 			tp->version = r8152_versions[i].version;
9929dc8ba19STed Chen 			tp->supports_gmii = r8152_versions[i].gmii;
9939dc8ba19STed Chen 			break;
9949dc8ba19STed Chen 		}
9959dc8ba19STed Chen 	}
9969dc8ba19STed Chen 
9979dc8ba19STed Chen 	if (tp->version == RTL_VER_UNKNOWN)
9989dc8ba19STed Chen 		debug("r8152 Unknown tcr version 0x%04x\n", tcr);
9999dc8ba19STed Chen }
10009dc8ba19STed Chen 
10019dc8ba19STed Chen static void r8152b_enable_fc(struct r8152 *tp)
10029dc8ba19STed Chen {
10039dc8ba19STed Chen 	u16 anar;
10049dc8ba19STed Chen 	anar = r8152_mdio_read(tp, MII_ADVERTISE);
10059dc8ba19STed Chen 	anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
10069dc8ba19STed Chen 	r8152_mdio_write(tp, MII_ADVERTISE, anar);
10079dc8ba19STed Chen }
10089dc8ba19STed Chen 
10099dc8ba19STed Chen static void rtl_tally_reset(struct r8152 *tp)
10109dc8ba19STed Chen {
10119dc8ba19STed Chen 	u32 ocp_data;
10129dc8ba19STed Chen 
10139dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY);
10149dc8ba19STed Chen 	ocp_data |= TALLY_RESET;
10159dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
10169dc8ba19STed Chen }
10179dc8ba19STed Chen 
10189dc8ba19STed Chen static void r8152b_init(struct r8152 *tp)
10199dc8ba19STed Chen {
10209dc8ba19STed Chen 	u32 ocp_data;
10219dc8ba19STed Chen 
10229dc8ba19STed Chen 	r8152b_disable_aldps(tp);
10239dc8ba19STed Chen 
10249dc8ba19STed Chen 	if (tp->version == RTL_VER_01) {
10259dc8ba19STed Chen 		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
10269dc8ba19STed Chen 		ocp_data &= ~LED_MODE_MASK;
10279dc8ba19STed Chen 		ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
10289dc8ba19STed Chen 	}
10299dc8ba19STed Chen 
10309dc8ba19STed Chen 	r8152_power_cut_en(tp, false);
10319dc8ba19STed Chen 
10329dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
10339dc8ba19STed Chen 	ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
10349dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
10359dc8ba19STed Chen 	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL);
10369dc8ba19STed Chen 	ocp_data &= ~MCU_CLK_RATIO_MASK;
10379dc8ba19STed Chen 	ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN;
10389dc8ba19STed Chen 	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data);
10399dc8ba19STed Chen 	ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
10409dc8ba19STed Chen 		   SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK;
10419dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
10429dc8ba19STed Chen 
10439dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_TIMER);
10449dc8ba19STed Chen 	ocp_data |= BIT(15);
10459dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_TIMER, ocp_data);
10469dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, 0xcbfc, 0x03e8);
10479dc8ba19STed Chen 	ocp_data &= ~BIT(15);
10489dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_TIMER, ocp_data);
10499dc8ba19STed Chen 
10509dc8ba19STed Chen 	r8152b_enable_fc(tp);
10519dc8ba19STed Chen 	rtl_tally_reset(tp);
10529dc8ba19STed Chen 
10539dc8ba19STed Chen 	/* enable rx aggregation */
10549dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
10559dc8ba19STed Chen 
10569dc8ba19STed Chen 	ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN);
10579dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
10589dc8ba19STed Chen }
10599dc8ba19STed Chen 
10609dc8ba19STed Chen static void r8153_init(struct r8152 *tp)
10619dc8ba19STed Chen {
10629dc8ba19STed Chen 	int i;
10639dc8ba19STed Chen 	u32 ocp_data;
10649dc8ba19STed Chen 
10659dc8ba19STed Chen 	r8153_disable_aldps(tp);
10669dc8ba19STed Chen 	r8153_u1u2en(tp, false);
10679dc8ba19STed Chen 
10689dc8ba19STed Chen 	r8152_wait_for_bit(tp, 0, MCU_TYPE_PLA, PLA_BOOT_CTRL,
10699dc8ba19STed Chen 			   AUTOLOAD_DONE, 1, R8152_WAIT_TIMEOUT);
10709dc8ba19STed Chen 
10719dc8ba19STed Chen 	for (i = 0; i < R8152_WAIT_TIMEOUT; i++) {
10729dc8ba19STed Chen 		ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK;
10739dc8ba19STed Chen 		if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN)
10749dc8ba19STed Chen 			break;
10759dc8ba19STed Chen 
10769dc8ba19STed Chen 		mdelay(1);
10779dc8ba19STed Chen 	}
10789dc8ba19STed Chen 
10799dc8ba19STed Chen 	r8153_u2p3en(tp, false);
10809dc8ba19STed Chen 
10819dc8ba19STed Chen 	if (tp->version == RTL_VER_04) {
10829dc8ba19STed Chen 		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2);
10839dc8ba19STed Chen 		ocp_data &= ~pwd_dn_scale_mask;
10849dc8ba19STed Chen 		ocp_data |= pwd_dn_scale(96);
10859dc8ba19STed Chen 		ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2, ocp_data);
10869dc8ba19STed Chen 
10879dc8ba19STed Chen 		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
10889dc8ba19STed Chen 		ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
10899dc8ba19STed Chen 		ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
10909dc8ba19STed Chen 	} else if (tp->version == RTL_VER_05) {
10919dc8ba19STed Chen 		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0);
10929dc8ba19STed Chen 		ocp_data &= ~ECM_ALDPS;
10939dc8ba19STed Chen 		ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data);
10949dc8ba19STed Chen 
10959dc8ba19STed Chen 		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1);
10969dc8ba19STed Chen 		if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0)
10979dc8ba19STed Chen 			ocp_data &= ~DYNAMIC_BURST;
10989dc8ba19STed Chen 		else
10999dc8ba19STed Chen 			ocp_data |= DYNAMIC_BURST;
11009dc8ba19STed Chen 		ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data);
11019dc8ba19STed Chen 	} else if (tp->version == RTL_VER_06) {
11029dc8ba19STed Chen 		ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1);
11039dc8ba19STed Chen 		if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0)
11049dc8ba19STed Chen 			ocp_data &= ~DYNAMIC_BURST;
11059dc8ba19STed Chen 		else
11069dc8ba19STed Chen 			ocp_data |= DYNAMIC_BURST;
11079dc8ba19STed Chen 		ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data);
11089dc8ba19STed Chen 	}
11099dc8ba19STed Chen 
11109dc8ba19STed Chen 	ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2);
11119dc8ba19STed Chen 	ocp_data |= EP4_FULL_FC;
11129dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2, ocp_data);
11139dc8ba19STed Chen 
11149dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL);
11159dc8ba19STed Chen 	ocp_data &= ~TIMER11_EN;
11169dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data);
11179dc8ba19STed Chen 
11189dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
11199dc8ba19STed Chen 	ocp_data &= ~LED_MODE_MASK;
11209dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
11219dc8ba19STed Chen 
11229dc8ba19STed Chen 	ocp_data = FIFO_EMPTY_1FB | ROK_EXIT_LPM;
11239dc8ba19STed Chen 	if (tp->version == RTL_VER_04 && tp->udev->speed != USB_SPEED_SUPER)
11249dc8ba19STed Chen 		ocp_data |= LPM_TIMER_500MS;
11259dc8ba19STed Chen 	else
11269dc8ba19STed Chen 		ocp_data |= LPM_TIMER_500US;
11279dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data);
11289dc8ba19STed Chen 
11299dc8ba19STed Chen 	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2);
11309dc8ba19STed Chen 	ocp_data &= ~SEN_VAL_MASK;
11319dc8ba19STed Chen 	ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE;
11329dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data);
11339dc8ba19STed Chen 
11349dc8ba19STed Chen 	ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001);
11359dc8ba19STed Chen 
11369dc8ba19STed Chen 	r8153_power_cut_en(tp, false);
11379dc8ba19STed Chen 
11389dc8ba19STed Chen 	r8152b_enable_fc(tp);
11399dc8ba19STed Chen 	rtl_tally_reset(tp);
11409dc8ba19STed Chen }
11419dc8ba19STed Chen 
11429dc8ba19STed Chen static void rtl8152_unload(struct r8152 *tp)
11439dc8ba19STed Chen {
11449dc8ba19STed Chen 	if (tp->version != RTL_VER_01)
11459dc8ba19STed Chen 		r8152_power_cut_en(tp, true);
11469dc8ba19STed Chen }
11479dc8ba19STed Chen 
11489dc8ba19STed Chen static void rtl8153_unload(struct r8152 *tp)
11499dc8ba19STed Chen {
11509dc8ba19STed Chen 	r8153_power_cut_en(tp, false);
11519dc8ba19STed Chen }
11529dc8ba19STed Chen 
11539dc8ba19STed Chen static int rtl_ops_init(struct r8152 *tp)
11549dc8ba19STed Chen {
11559dc8ba19STed Chen 	struct rtl_ops *ops = &tp->rtl_ops;
11569dc8ba19STed Chen 	int ret = 0;
11579dc8ba19STed Chen 
11589dc8ba19STed Chen 	switch (tp->version) {
11599dc8ba19STed Chen 	case RTL_VER_01:
11609dc8ba19STed Chen 	case RTL_VER_02:
11619dc8ba19STed Chen 	case RTL_VER_07:
11629dc8ba19STed Chen 		ops->init		= r8152b_init;
11639dc8ba19STed Chen 		ops->enable		= rtl8152_enable;
11649dc8ba19STed Chen 		ops->disable		= rtl8152_disable;
11659dc8ba19STed Chen 		ops->up			= rtl8152_up;
11669dc8ba19STed Chen 		ops->down		= rtl8152_down;
11679dc8ba19STed Chen 		ops->unload		= rtl8152_unload;
11689dc8ba19STed Chen 		break;
11699dc8ba19STed Chen 
11709dc8ba19STed Chen 	case RTL_VER_03:
11719dc8ba19STed Chen 	case RTL_VER_04:
11729dc8ba19STed Chen 	case RTL_VER_05:
11739dc8ba19STed Chen 	case RTL_VER_06:
11749dc8ba19STed Chen 		ops->init		= r8153_init;
11759dc8ba19STed Chen 		ops->enable		= rtl8153_enable;
11769dc8ba19STed Chen 		ops->disable		= rtl8153_disable;
11779dc8ba19STed Chen 		ops->up			= rtl8153_up;
11789dc8ba19STed Chen 		ops->down		= rtl8153_down;
11799dc8ba19STed Chen 		ops->unload		= rtl8153_unload;
11809dc8ba19STed Chen 		break;
11819dc8ba19STed Chen 
11829dc8ba19STed Chen 	default:
11839dc8ba19STed Chen 		ret = -ENODEV;
11849dc8ba19STed Chen 		printf("r8152 Unknown Device\n");
11859dc8ba19STed Chen 		break;
11869dc8ba19STed Chen 	}
11879dc8ba19STed Chen 
11889dc8ba19STed Chen 	return ret;
11899dc8ba19STed Chen }
11909dc8ba19STed Chen 
11916688452aSStefan Roese static int r8152_init_common(struct r8152 *tp)
11929dc8ba19STed Chen {
11939dc8ba19STed Chen 	u8 speed;
11949dc8ba19STed Chen 	int timeout = 0;
11959dc8ba19STed Chen 	int link_detected;
11969dc8ba19STed Chen 
11979dc8ba19STed Chen 	debug("** %s()\n", __func__);
11989dc8ba19STed Chen 
11999dc8ba19STed Chen 	do {
12009dc8ba19STed Chen 		speed = rtl8152_get_speed(tp);
12019dc8ba19STed Chen 
12029dc8ba19STed Chen 		link_detected = speed & LINK_STATUS;
12039dc8ba19STed Chen 		if (!link_detected) {
12049dc8ba19STed Chen 			if (timeout == 0)
12059dc8ba19STed Chen 				printf("Waiting for Ethernet connection... ");
12069dc8ba19STed Chen 			mdelay(TIMEOUT_RESOLUTION);
12079dc8ba19STed Chen 			timeout += TIMEOUT_RESOLUTION;
12089dc8ba19STed Chen 		}
12099dc8ba19STed Chen 	} while (!link_detected && timeout < PHY_CONNECT_TIMEOUT);
12109dc8ba19STed Chen 	if (link_detected) {
12119dc8ba19STed Chen 		tp->rtl_ops.enable(tp);
12129dc8ba19STed Chen 
12139dc8ba19STed Chen 		if (timeout != 0)
12149dc8ba19STed Chen 			printf("done.\n");
12159dc8ba19STed Chen 	} else {
12169dc8ba19STed Chen 		printf("unable to connect.\n");
12179dc8ba19STed Chen 	}
12189dc8ba19STed Chen 
12199dc8ba19STed Chen 	return 0;
12209dc8ba19STed Chen }
12219dc8ba19STed Chen 
12226688452aSStefan Roese static int r8152_send_common(struct ueth_data *ueth, void *packet, int length)
12239dc8ba19STed Chen {
12246688452aSStefan Roese 	struct usb_device *udev = ueth->pusb_dev;
12259dc8ba19STed Chen 	u32 opts1, opts2 = 0;
12269dc8ba19STed Chen 	int err;
12279dc8ba19STed Chen 	int actual_len;
1228*c7ac1538SStefan Roese 	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, msg,
1229*c7ac1538SStefan Roese 				 PKTSIZE + sizeof(struct tx_desc));
12309dc8ba19STed Chen 	struct tx_desc *tx_desc = (struct tx_desc *)msg;
12319dc8ba19STed Chen 
12329dc8ba19STed Chen 	debug("** %s(), len %d\n", __func__, length);
12339dc8ba19STed Chen 
12349dc8ba19STed Chen 	opts1 = length | TX_FS | TX_LS;
12359dc8ba19STed Chen 
12369dc8ba19STed Chen 	tx_desc->opts2 = cpu_to_le32(opts2);
12379dc8ba19STed Chen 	tx_desc->opts1 = cpu_to_le32(opts1);
12389dc8ba19STed Chen 
12399dc8ba19STed Chen 	memcpy(msg + sizeof(struct tx_desc), (void *)packet, length);
12409dc8ba19STed Chen 
12416688452aSStefan Roese 	err = usb_bulk_msg(udev, usb_sndbulkpipe(udev, ueth->ep_out),
12426688452aSStefan Roese 			   (void *)msg, length + sizeof(struct tx_desc),
12436688452aSStefan Roese 			   &actual_len, USB_BULK_SEND_TIMEOUT);
12449dc8ba19STed Chen 	debug("Tx: len = %zu, actual = %u, err = %d\n",
12459dc8ba19STed Chen 	      length + sizeof(struct tx_desc), actual_len, err);
12469dc8ba19STed Chen 
12479dc8ba19STed Chen 	return err;
12489dc8ba19STed Chen }
12499dc8ba19STed Chen 
12506688452aSStefan Roese #ifndef CONFIG_DM_ETH
12516688452aSStefan Roese static int r8152_init(struct eth_device *eth, bd_t *bd)
12526688452aSStefan Roese {
12536688452aSStefan Roese 	struct ueth_data *dev = (struct ueth_data *)eth->priv;
12546688452aSStefan Roese 	struct r8152 *tp = (struct r8152 *)dev->dev_priv;
12556688452aSStefan Roese 
12566688452aSStefan Roese 	return r8152_init_common(tp);
12576688452aSStefan Roese }
12586688452aSStefan Roese 
12596688452aSStefan Roese static int r8152_send(struct eth_device *eth, void *packet, int length)
12606688452aSStefan Roese {
12616688452aSStefan Roese 	struct ueth_data *dev = (struct ueth_data *)eth->priv;
12626688452aSStefan Roese 
12636688452aSStefan Roese 	return r8152_send_common(dev, packet, length);
12646688452aSStefan Roese }
12656688452aSStefan Roese 
12669dc8ba19STed Chen static int r8152_recv(struct eth_device *eth)
12679dc8ba19STed Chen {
12689dc8ba19STed Chen 	struct ueth_data *dev = (struct ueth_data *)eth->priv;
12699dc8ba19STed Chen 
1270*c7ac1538SStefan Roese 	ALLOC_CACHE_ALIGN_BUFFER(uint8_t, recv_buf, RTL8152_AGG_BUF_SZ);
12719dc8ba19STed Chen 	unsigned char *pkt_ptr;
12729dc8ba19STed Chen 	int err;
12739dc8ba19STed Chen 	int actual_len;
12749dc8ba19STed Chen 	u16 packet_len;
12759dc8ba19STed Chen 
12769dc8ba19STed Chen 	u32 bytes_process = 0;
12779dc8ba19STed Chen 	struct rx_desc *rx_desc;
12789dc8ba19STed Chen 
12799dc8ba19STed Chen 	debug("** %s()\n", __func__);
12809dc8ba19STed Chen 
12819dc8ba19STed Chen 	err = usb_bulk_msg(dev->pusb_dev,
12829dc8ba19STed Chen 				usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
12839dc8ba19STed Chen 				(void *)recv_buf,
12849dc8ba19STed Chen 				RTL8152_AGG_BUF_SZ,
12859dc8ba19STed Chen 				&actual_len,
12869dc8ba19STed Chen 				USB_BULK_RECV_TIMEOUT);
12879dc8ba19STed Chen 	debug("Rx: len = %u, actual = %u, err = %d\n", RTL8152_AGG_BUF_SZ,
12889dc8ba19STed Chen 	      actual_len, err);
12899dc8ba19STed Chen 	if (err != 0) {
12909dc8ba19STed Chen 		debug("Rx: failed to receive\n");
12919dc8ba19STed Chen 		return -1;
12929dc8ba19STed Chen 	}
12939dc8ba19STed Chen 	if (actual_len > RTL8152_AGG_BUF_SZ) {
12949dc8ba19STed Chen 		debug("Rx: received too many bytes %d\n", actual_len);
12959dc8ba19STed Chen 		return -1;
12969dc8ba19STed Chen 	}
12979dc8ba19STed Chen 
12989dc8ba19STed Chen 	while (bytes_process < actual_len) {
12999dc8ba19STed Chen 		rx_desc = (struct rx_desc *)(recv_buf + bytes_process);
13009dc8ba19STed Chen 		pkt_ptr = recv_buf + sizeof(struct rx_desc) + bytes_process;
13019dc8ba19STed Chen 
13029dc8ba19STed Chen 		packet_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
13039dc8ba19STed Chen 		packet_len -= CRC_SIZE;
13049dc8ba19STed Chen 
13059dc8ba19STed Chen 		net_process_received_packet(pkt_ptr, packet_len);
13069dc8ba19STed Chen 
13079dc8ba19STed Chen 		bytes_process +=
13089dc8ba19STed Chen 			(packet_len + sizeof(struct rx_desc) + CRC_SIZE);
13099dc8ba19STed Chen 
13109dc8ba19STed Chen 		if (bytes_process % 8)
13119dc8ba19STed Chen 			bytes_process = bytes_process + 8 - (bytes_process % 8);
13129dc8ba19STed Chen 	}
13139dc8ba19STed Chen 
13149dc8ba19STed Chen 	return 0;
13159dc8ba19STed Chen }
13169dc8ba19STed Chen 
13179dc8ba19STed Chen static void r8152_halt(struct eth_device *eth)
13189dc8ba19STed Chen {
13199dc8ba19STed Chen 	struct ueth_data *dev = (struct ueth_data *)eth->priv;
13209dc8ba19STed Chen 	struct r8152 *tp = (struct r8152 *)dev->dev_priv;
13219dc8ba19STed Chen 
13229dc8ba19STed Chen 	debug("** %s()\n", __func__);
13239dc8ba19STed Chen 
13249dc8ba19STed Chen 	tp->rtl_ops.disable(tp);
13259dc8ba19STed Chen }
13269dc8ba19STed Chen 
13279dc8ba19STed Chen static int r8152_write_hwaddr(struct eth_device *eth)
13289dc8ba19STed Chen {
13299dc8ba19STed Chen 	struct ueth_data *dev = (struct ueth_data *)eth->priv;
13309dc8ba19STed Chen 	struct r8152 *tp = (struct r8152 *)dev->dev_priv;
13319dc8ba19STed Chen 
13329dc8ba19STed Chen 	unsigned char enetaddr[8] = {0};
13339dc8ba19STed Chen 
13349dc8ba19STed Chen 	memcpy(enetaddr, eth->enetaddr, ETH_ALEN);
13359dc8ba19STed Chen 
13369dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
13379dc8ba19STed Chen 	pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, enetaddr);
13389dc8ba19STed Chen 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
13399dc8ba19STed Chen 
13409dc8ba19STed Chen 	debug("MAC %pM\n", eth->enetaddr);
13419dc8ba19STed Chen 	return 0;
13429dc8ba19STed Chen }
13439dc8ba19STed Chen 
13449dc8ba19STed Chen void r8152_eth_before_probe(void)
13459dc8ba19STed Chen {
13469dc8ba19STed Chen 	curr_eth_dev = 0;
13479dc8ba19STed Chen }
13489dc8ba19STed Chen 
13499dc8ba19STed Chen /* Probe to see if a new device is actually an realtek device */
13509dc8ba19STed Chen int r8152_eth_probe(struct usb_device *dev, unsigned int ifnum,
13519dc8ba19STed Chen 		      struct ueth_data *ss)
13529dc8ba19STed Chen {
13539dc8ba19STed Chen 	struct usb_interface *iface;
13549dc8ba19STed Chen 	struct usb_interface_descriptor *iface_desc;
13559dc8ba19STed Chen 	int ep_in_found = 0, ep_out_found = 0;
13569dc8ba19STed Chen 	int i;
13579dc8ba19STed Chen 
13589dc8ba19STed Chen 	struct r8152 *tp;
13599dc8ba19STed Chen 
13609dc8ba19STed Chen 	/* let's examine the device now */
13619dc8ba19STed Chen 	iface = &dev->config.if_desc[ifnum];
13629dc8ba19STed Chen 	iface_desc = &dev->config.if_desc[ifnum].desc;
13639dc8ba19STed Chen 
13649dc8ba19STed Chen 	for (i = 0; i < ARRAY_SIZE(r8152_dongles); i++) {
13659dc8ba19STed Chen 		if (dev->descriptor.idVendor == r8152_dongles[i].vendor &&
13669dc8ba19STed Chen 		    dev->descriptor.idProduct == r8152_dongles[i].product)
13679dc8ba19STed Chen 			/* Found a supported dongle */
13689dc8ba19STed Chen 			break;
13699dc8ba19STed Chen 	}
13709dc8ba19STed Chen 
13719dc8ba19STed Chen 	if (i == ARRAY_SIZE(r8152_dongles))
13729dc8ba19STed Chen 		return 0;
13739dc8ba19STed Chen 
13749dc8ba19STed Chen 	memset(ss, 0, sizeof(struct ueth_data));
13759dc8ba19STed Chen 
13769dc8ba19STed Chen 	/* At this point, we know we've got a live one */
13779dc8ba19STed Chen 	debug("\n\nUSB Ethernet device detected: %#04x:%#04x\n",
13789dc8ba19STed Chen 	      dev->descriptor.idVendor, dev->descriptor.idProduct);
13799dc8ba19STed Chen 
13809dc8ba19STed Chen 	/* Initialize the ueth_data structure with some useful info */
13819dc8ba19STed Chen 	ss->ifnum = ifnum;
13829dc8ba19STed Chen 	ss->pusb_dev = dev;
13839dc8ba19STed Chen 	ss->subclass = iface_desc->bInterfaceSubClass;
13849dc8ba19STed Chen 	ss->protocol = iface_desc->bInterfaceProtocol;
13859dc8ba19STed Chen 
13869dc8ba19STed Chen 	/* alloc driver private */
13879dc8ba19STed Chen 	ss->dev_priv = calloc(1, sizeof(struct r8152));
13889dc8ba19STed Chen 
13899dc8ba19STed Chen 	if (!ss->dev_priv)
13909dc8ba19STed Chen 		return 0;
13919dc8ba19STed Chen 
13929dc8ba19STed Chen 	/*
13939dc8ba19STed Chen 	 * We are expecting a minimum of 3 endpoints - in, out (bulk), and
13949dc8ba19STed Chen 	 * int. We will ignore any others.
13959dc8ba19STed Chen 	 */
13969dc8ba19STed Chen 	for (i = 0; i < iface_desc->bNumEndpoints; i++) {
13979dc8ba19STed Chen 		/* is it an BULK endpoint? */
13989dc8ba19STed Chen 		if ((iface->ep_desc[i].bmAttributes &
13999dc8ba19STed Chen 		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
14009dc8ba19STed Chen 			u8 ep_addr = iface->ep_desc[i].bEndpointAddress;
14019dc8ba19STed Chen 			if ((ep_addr & USB_DIR_IN) && !ep_in_found) {
14029dc8ba19STed Chen 				ss->ep_in = ep_addr &
14039dc8ba19STed Chen 					USB_ENDPOINT_NUMBER_MASK;
14049dc8ba19STed Chen 				ep_in_found = 1;
14059dc8ba19STed Chen 			} else {
14069dc8ba19STed Chen 				if (!ep_out_found) {
14079dc8ba19STed Chen 					ss->ep_out = ep_addr &
14089dc8ba19STed Chen 						USB_ENDPOINT_NUMBER_MASK;
14099dc8ba19STed Chen 					ep_out_found = 1;
14109dc8ba19STed Chen 				}
14119dc8ba19STed Chen 			}
14129dc8ba19STed Chen 		}
14139dc8ba19STed Chen 
14149dc8ba19STed Chen 		/* is it an interrupt endpoint? */
14159dc8ba19STed Chen 		if ((iface->ep_desc[i].bmAttributes &
14169dc8ba19STed Chen 		    USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
14179dc8ba19STed Chen 			ss->ep_int = iface->ep_desc[i].bEndpointAddress &
14189dc8ba19STed Chen 				USB_ENDPOINT_NUMBER_MASK;
14199dc8ba19STed Chen 			ss->irqinterval = iface->ep_desc[i].bInterval;
14209dc8ba19STed Chen 		}
14219dc8ba19STed Chen 	}
14229dc8ba19STed Chen 
14239dc8ba19STed Chen 	debug("Endpoints In %d Out %d Int %d\n",
14249dc8ba19STed Chen 	      ss->ep_in, ss->ep_out, ss->ep_int);
14259dc8ba19STed Chen 
14269dc8ba19STed Chen 	/* Do some basic sanity checks, and bail if we find a problem */
14279dc8ba19STed Chen 	if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) ||
14289dc8ba19STed Chen 	    !ss->ep_in || !ss->ep_out || !ss->ep_int) {
14299dc8ba19STed Chen 		debug("Problems with device\n");
14309dc8ba19STed Chen 		return 0;
14319dc8ba19STed Chen 	}
14329dc8ba19STed Chen 
14339dc8ba19STed Chen 	dev->privptr = (void *)ss;
14349dc8ba19STed Chen 
14359dc8ba19STed Chen 	tp = ss->dev_priv;
14369dc8ba19STed Chen 	tp->udev = dev;
14379dc8ba19STed Chen 	tp->intf = iface;
14389dc8ba19STed Chen 
14399dc8ba19STed Chen 	r8152b_get_version(tp);
14409dc8ba19STed Chen 
14419dc8ba19STed Chen 	if (rtl_ops_init(tp))
14429dc8ba19STed Chen 		return 0;
14439dc8ba19STed Chen 
14449dc8ba19STed Chen 	tp->rtl_ops.init(tp);
14459dc8ba19STed Chen 	tp->rtl_ops.up(tp);
14469dc8ba19STed Chen 
14479dc8ba19STed Chen 	rtl8152_set_speed(tp, AUTONEG_ENABLE,
14489dc8ba19STed Chen 			  tp->supports_gmii ? SPEED_1000 : SPEED_100,
14499dc8ba19STed Chen 			  DUPLEX_FULL);
14509dc8ba19STed Chen 
14519dc8ba19STed Chen 	return 1;
14529dc8ba19STed Chen }
14539dc8ba19STed Chen 
14549dc8ba19STed Chen int r8152_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
14559dc8ba19STed Chen 				struct eth_device *eth)
14569dc8ba19STed Chen {
14579dc8ba19STed Chen 	if (!eth) {
14589dc8ba19STed Chen 		debug("%s: missing parameter.\n", __func__);
14599dc8ba19STed Chen 		return 0;
14609dc8ba19STed Chen 	}
14619dc8ba19STed Chen 
14629dc8ba19STed Chen 	sprintf(eth->name, "%s#%d", R8152_BASE_NAME, curr_eth_dev++);
14639dc8ba19STed Chen 	eth->init = r8152_init;
14649dc8ba19STed Chen 	eth->send = r8152_send;
14659dc8ba19STed Chen 	eth->recv = r8152_recv;
14669dc8ba19STed Chen 	eth->halt = r8152_halt;
14679dc8ba19STed Chen 	eth->write_hwaddr = r8152_write_hwaddr;
14689dc8ba19STed Chen 	eth->priv = ss;
14699dc8ba19STed Chen 
14709dc8ba19STed Chen 	/* Get the MAC address */
14719dc8ba19STed Chen 	if (r8152_read_mac(ss->dev_priv, eth->enetaddr) < 0)
14729dc8ba19STed Chen 		return 0;
14739dc8ba19STed Chen 
14749dc8ba19STed Chen 	debug("MAC %pM\n", eth->enetaddr);
14759dc8ba19STed Chen 	return 1;
14769dc8ba19STed Chen }
14776688452aSStefan Roese #endif /* !CONFIG_DM_ETH */
14786688452aSStefan Roese 
14796688452aSStefan Roese #ifdef CONFIG_DM_ETH
14806688452aSStefan Roese static int r8152_eth_start(struct udevice *dev)
14816688452aSStefan Roese {
14826688452aSStefan Roese 	struct r8152 *tp = dev_get_priv(dev);
14836688452aSStefan Roese 
14846688452aSStefan Roese 	debug("** %s (%d)\n", __func__, __LINE__);
14856688452aSStefan Roese 
14866688452aSStefan Roese 	return r8152_init_common(tp);
14876688452aSStefan Roese }
14886688452aSStefan Roese 
14896688452aSStefan Roese void r8152_eth_stop(struct udevice *dev)
14906688452aSStefan Roese {
14916688452aSStefan Roese 	struct r8152 *tp = dev_get_priv(dev);
14926688452aSStefan Roese 
14936688452aSStefan Roese 	debug("** %s (%d)\n", __func__, __LINE__);
14946688452aSStefan Roese 
14956688452aSStefan Roese 	tp->rtl_ops.disable(tp);
14966688452aSStefan Roese }
14976688452aSStefan Roese 
14986688452aSStefan Roese int r8152_eth_send(struct udevice *dev, void *packet, int length)
14996688452aSStefan Roese {
15006688452aSStefan Roese 	struct r8152 *tp = dev_get_priv(dev);
15016688452aSStefan Roese 
15026688452aSStefan Roese 	return r8152_send_common(&tp->ueth, packet, length);
15036688452aSStefan Roese }
15046688452aSStefan Roese 
15056688452aSStefan Roese int r8152_eth_recv(struct udevice *dev, int flags, uchar **packetp)
15066688452aSStefan Roese {
15076688452aSStefan Roese 	struct r8152 *tp = dev_get_priv(dev);
15086688452aSStefan Roese 	struct ueth_data *ueth = &tp->ueth;
15096688452aSStefan Roese 	uint8_t *ptr;
15106688452aSStefan Roese 	int ret, len;
15116688452aSStefan Roese 	struct rx_desc *rx_desc;
15126688452aSStefan Roese 	u16 packet_len;
15136688452aSStefan Roese 
15146688452aSStefan Roese 	len = usb_ether_get_rx_bytes(ueth, &ptr);
15156688452aSStefan Roese 	debug("%s: first try, len=%d\n", __func__, len);
15166688452aSStefan Roese 	if (!len) {
15176688452aSStefan Roese 		if (!(flags & ETH_RECV_CHECK_DEVICE))
15186688452aSStefan Roese 			return -EAGAIN;
15196688452aSStefan Roese 		ret = usb_ether_receive(ueth, RTL8152_AGG_BUF_SZ);
15206688452aSStefan Roese 		if (ret)
15216688452aSStefan Roese 			return ret;
15226688452aSStefan Roese 
15236688452aSStefan Roese 		len = usb_ether_get_rx_bytes(ueth, &ptr);
15246688452aSStefan Roese 		debug("%s: second try, len=%d\n", __func__, len);
15256688452aSStefan Roese 	}
15266688452aSStefan Roese 
15276688452aSStefan Roese 	rx_desc = (struct rx_desc *)ptr;
15286688452aSStefan Roese 	packet_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
15296688452aSStefan Roese 	packet_len -= CRC_SIZE;
15306688452aSStefan Roese 
15316688452aSStefan Roese 	if (packet_len > len - (sizeof(struct rx_desc) + CRC_SIZE)) {
15326688452aSStefan Roese 		debug("Rx: too large packet: %d\n", packet_len);
15336688452aSStefan Roese 		goto err;
15346688452aSStefan Roese 	}
15356688452aSStefan Roese 
15366688452aSStefan Roese 	*packetp = ptr + sizeof(struct rx_desc);
15376688452aSStefan Roese 	return packet_len;
15386688452aSStefan Roese 
15396688452aSStefan Roese err:
15406688452aSStefan Roese 	usb_ether_advance_rxbuf(ueth, -1);
15416688452aSStefan Roese 	return -ENOSPC;
15426688452aSStefan Roese }
15436688452aSStefan Roese 
15446688452aSStefan Roese static int r8152_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
15456688452aSStefan Roese {
15466688452aSStefan Roese 	struct r8152 *tp = dev_get_priv(dev);
15476688452aSStefan Roese 
15486688452aSStefan Roese 	packet_len += sizeof(struct rx_desc) + CRC_SIZE;
15496688452aSStefan Roese 	packet_len = ALIGN(packet_len, 8);
15506688452aSStefan Roese 	usb_ether_advance_rxbuf(&tp->ueth, packet_len);
15516688452aSStefan Roese 
15526688452aSStefan Roese 	return 0;
15536688452aSStefan Roese }
15546688452aSStefan Roese 
15556688452aSStefan Roese static int r8152_write_hwaddr(struct udevice *dev)
15566688452aSStefan Roese {
15576688452aSStefan Roese 	struct eth_pdata *pdata = dev_get_platdata(dev);
15586688452aSStefan Roese 	struct r8152 *tp = dev_get_priv(dev);
15596688452aSStefan Roese 
15606688452aSStefan Roese 	unsigned char enetaddr[8] = { 0 };
15616688452aSStefan Roese 
15626688452aSStefan Roese 	debug("** %s (%d)\n", __func__, __LINE__);
15636688452aSStefan Roese 	memcpy(enetaddr, pdata->enetaddr, ETH_ALEN);
15646688452aSStefan Roese 
15656688452aSStefan Roese 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
15666688452aSStefan Roese 	pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, enetaddr);
15676688452aSStefan Roese 	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
15686688452aSStefan Roese 
15696688452aSStefan Roese 	debug("MAC %pM\n", pdata->enetaddr);
15706688452aSStefan Roese 	return 0;
15716688452aSStefan Roese }
15726688452aSStefan Roese 
15736688452aSStefan Roese int r8152_read_rom_hwaddr(struct udevice *dev)
15746688452aSStefan Roese {
15756688452aSStefan Roese 	struct eth_pdata *pdata = dev_get_platdata(dev);
15766688452aSStefan Roese 	struct r8152 *tp = dev_get_priv(dev);
15776688452aSStefan Roese 
15786688452aSStefan Roese 	debug("** %s (%d)\n", __func__, __LINE__);
15796688452aSStefan Roese 	r8152_read_mac(tp, pdata->enetaddr);
15806688452aSStefan Roese 	return 0;
15816688452aSStefan Roese }
15826688452aSStefan Roese 
15836688452aSStefan Roese static int r8152_eth_probe(struct udevice *dev)
15846688452aSStefan Roese {
15856688452aSStefan Roese 	struct usb_device *udev = dev_get_parent_priv(dev);
15866688452aSStefan Roese 	struct eth_pdata *pdata = dev_get_platdata(dev);
15876688452aSStefan Roese 	struct r8152 *tp = dev_get_priv(dev);
15886688452aSStefan Roese 	struct ueth_data *ueth = &tp->ueth;
15896688452aSStefan Roese 	int ret;
15906688452aSStefan Roese 
15916688452aSStefan Roese 	tp->udev = udev;
15926688452aSStefan Roese 	r8152_read_mac(tp, pdata->enetaddr);
15936688452aSStefan Roese 
15946688452aSStefan Roese 	r8152b_get_version(tp);
15956688452aSStefan Roese 
15966688452aSStefan Roese 	ret = rtl_ops_init(tp);
15976688452aSStefan Roese 	if (ret)
15986688452aSStefan Roese 		return ret;
15996688452aSStefan Roese 
16006688452aSStefan Roese 	tp->rtl_ops.init(tp);
16016688452aSStefan Roese 	tp->rtl_ops.up(tp);
16026688452aSStefan Roese 
16036688452aSStefan Roese 	rtl8152_set_speed(tp, AUTONEG_ENABLE,
16046688452aSStefan Roese 			  tp->supports_gmii ? SPEED_1000 : SPEED_100,
16056688452aSStefan Roese 			  DUPLEX_FULL);
16066688452aSStefan Roese 
16076688452aSStefan Roese 	return usb_ether_register(dev, ueth, RTL8152_AGG_BUF_SZ);
16086688452aSStefan Roese }
16096688452aSStefan Roese 
16106688452aSStefan Roese static const struct eth_ops r8152_eth_ops = {
16116688452aSStefan Roese 	.start	= r8152_eth_start,
16126688452aSStefan Roese 	.send	= r8152_eth_send,
16136688452aSStefan Roese 	.recv	= r8152_eth_recv,
16146688452aSStefan Roese 	.free_pkt = r8152_free_pkt,
16156688452aSStefan Roese 	.stop	= r8152_eth_stop,
16166688452aSStefan Roese 	.write_hwaddr = r8152_write_hwaddr,
16176688452aSStefan Roese 	.read_rom_hwaddr = r8152_read_rom_hwaddr,
16186688452aSStefan Roese };
16196688452aSStefan Roese 
16206688452aSStefan Roese U_BOOT_DRIVER(r8152_eth) = {
16216688452aSStefan Roese 	.name	= "r8152_eth",
16226688452aSStefan Roese 	.id	= UCLASS_ETH,
16236688452aSStefan Roese 	.probe = r8152_eth_probe,
16246688452aSStefan Roese 	.ops	= &r8152_eth_ops,
16256688452aSStefan Roese 	.priv_auto_alloc_size = sizeof(struct r8152),
16266688452aSStefan Roese 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
16276688452aSStefan Roese };
16286688452aSStefan Roese 
16296688452aSStefan Roese static const struct usb_device_id r8152_eth_id_table[] = {
16306688452aSStefan Roese 	/* Realtek */
16316688452aSStefan Roese 	{ USB_DEVICE(0x0bda, 0x8050) },
16326688452aSStefan Roese 	{ USB_DEVICE(0x0bda, 0x8152) },
16336688452aSStefan Roese 	{ USB_DEVICE(0x0bda, 0x8153) },
16346688452aSStefan Roese 
16356688452aSStefan Roese 	/* Samsung */
16366688452aSStefan Roese 	{ USB_DEVICE(0x04e8, 0xa101) },
16376688452aSStefan Roese 
16386688452aSStefan Roese 	/* Lenovo */
16396688452aSStefan Roese 	{ USB_DEVICE(0x17ef, 0x304f) },
16406688452aSStefan Roese 	{ USB_DEVICE(0x17ef, 0x3052) },
16416688452aSStefan Roese 	{ USB_DEVICE(0x17ef, 0x3054) },
16426688452aSStefan Roese 	{ USB_DEVICE(0x17ef, 0x3057) },
16436688452aSStefan Roese 	{ USB_DEVICE(0x17ef, 0x7205) },
16446688452aSStefan Roese 	{ USB_DEVICE(0x17ef, 0x720a) },
16456688452aSStefan Roese 	{ USB_DEVICE(0x17ef, 0x720b) },
16466688452aSStefan Roese 	{ USB_DEVICE(0x17ef, 0x720c) },
16476688452aSStefan Roese 
16486688452aSStefan Roese 	/* TP-LINK */
16496688452aSStefan Roese 	{ USB_DEVICE(0x2357, 0x0601) },
16506688452aSStefan Roese 
16516688452aSStefan Roese 	/* Nvidia */
16526688452aSStefan Roese 	{ USB_DEVICE(0x0955, 0x09ff) },
16536688452aSStefan Roese 
16546688452aSStefan Roese 	{ }		/* Terminating entry */
16556688452aSStefan Roese };
16566688452aSStefan Roese 
16576688452aSStefan Roese U_BOOT_USB_DEVICE(r8152_eth, r8152_eth_id_table);
16586688452aSStefan Roese #endif /* CONFIG_DM_ETH */
16596688452aSStefan Roese 
1660