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