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