xref: /OK3568_Linux_fs/u-boot/drivers/net/phy/rk630phy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0+
2 /**
3  *
4  * Driver for ROCKCHIP RK630 Ethernet PHYs
5  *
6  * Copyright (c) 2020, Fuzhou Rockchip Electronics Co., Ltd
7  *
8  * David Wu <david.wu@rock-chips.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  */
16 
17 #include <config.h>
18 #include <common.h>
19 #include <misc.h>
20 #include <phy.h>
21 
22 #define RK630_PHY_ID				0x00441400
23 
24 /* PAGE 0 */
25 #define REG_MMD_ACCESS_CONTROL			0x0d
26 #define REG_MMD_ACCESS_DATA_ADDRESS		0x0e
27 #define REG_INTERRUPT_STATUS			0X10
28 #define REG_INTERRUPT_MASK			0X11
29 #define REG_GLOBAL_CONFIGURATION		0X13
30 #define REG_MAC_ADDRESS0			0x16
31 #define REG_MAC_ADDRESS1			0x17
32 #define REG_MAC_ADDRESS2			0x18
33 
34 #define REG_PAGE_SEL				0x1F
35 
36 /* PAGE 1 */
37 #define REG_PAGE1_APS_CTRL			0x12
38 #define REG_PAGE1_UAPS_CONFIGURE		0X13
39 #define REG_PAGE1_EEE_CONFIGURE			0x17
40 
41 /* PAGE 2 */
42 #define REG_PAGE2_AFE_CTRL			0x18
43 
44 /* PAGE 6 */
45 #define REG_PAGE6_ADC_ANONTROL			0x10
46 #define REG_PAGE6_GAIN_ANONTROL			0x12
47 #define REG_PAGE6_AFE_RX_CTRL			0x13
48 #define REG_PAGE6_AFE_TX_CTRL			0x14
49 #define REG_PAGE6_AFE_DRIVER2			0x15
50 #define REG_PAGE6_CP_CURRENT			0x17
51 #define REG_PAGE6_ADC_OP_BIAS			0x18
52 #define REG_PAGE6_RX_DECTOR			0x19
53 #define REG_PAGE6_TX_MOS_DRV			0x1B
54 #define REG_PAGE6_AFE_PDCW			0x1c
55 
56 /* PAGE 8 */
57 #define REG_PAGE8_AFE_CTRL			0x18
58 #define REG_PAGE8_AUTO_CAL			0x1d
59 
60 /*
61  * Fixed address:
62  * Addr: 1 --- RK630@S40
63  *       2 --- RV1106@T22
64  */
65 #define PHY_ADDR_S40 1
66 #define PHY_ADDR_T22 2
67 
68 #define T22_TX_LEVEL_100M			0x2d
69 #define T22_TX_LEVEL_10M			0x32
70 
rk630_phy_t22_get_txlevel_from_efuse(unsigned char * txlevel_100,unsigned char * txlevel_10)71 static int rk630_phy_t22_get_txlevel_from_efuse(unsigned char *txlevel_100,
72 						unsigned char *txlevel_10)
73 {
74 #if defined(CONFIG_ROCKCHIP_EFUSE) || defined(CONFIG_ROCKCHIP_OTP)
75 	unsigned char tx_level[2];
76 	struct udevice *dev;
77 	u32 regs[2] = {0};
78 	ofnode node;
79 	int ret;
80 
81 	/* retrieve the device */
82 	if (IS_ENABLED(CONFIG_ROCKCHIP_EFUSE))
83 		ret = uclass_get_device_by_driver(UCLASS_MISC,
84 						  DM_GET_DRIVER(rockchip_efuse),
85 						  &dev);
86 	else
87 		ret = uclass_get_device_by_driver(UCLASS_MISC,
88 						  DM_GET_DRIVER(rockchip_otp),
89 						  &dev);
90 
91 	if (ret) {
92 		printf("%s: could not find efuse/otp device\n", __func__);
93 		return ret;
94 	}
95 
96 	node = dev_read_subnode(dev, "macphy-txlevel");
97 	if (!ofnode_valid(node))
98 		return -EINVAL;
99 
100 	ret = ofnode_read_u32_array(node, "reg", regs, 2);
101 	if (ret) {
102 		printf("Cannot get efuse reg\n");
103 		return -EINVAL;
104 	}
105 
106 	/* read the txlevel from the efuses */
107 	ret = misc_read(dev, regs[0], &tx_level, 2);
108 	if (ret) {
109 		printf("%s: read txlevel from efuse/otp failed, ret=%d\n",
110 		       __func__, ret);
111 		return ret;
112 	}
113 	*txlevel_100 = tx_level[1];
114 	*txlevel_10 = tx_level[0];
115 
116 	return 0;
117 #else
118 	return -EINVAL;
119 #endif
120 }
121 
rk630_phy_startup(struct phy_device * phydev)122 static int rk630_phy_startup(struct phy_device *phydev)
123 {
124 	int ret;
125 
126 	/* Read the Status (2x to make sure link is right) */
127 	ret = genphy_update_link(phydev);
128 	if (ret)
129 		return ret;
130 
131 	/* Read the Status (2x to make sure link is right) */
132 	phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
133 
134 	return genphy_parse_link(phydev);
135 }
136 
rk630_phy_s40_config_init(struct phy_device * phydev)137 static void rk630_phy_s40_config_init(struct phy_device *phydev)
138 {
139 	phy_write(phydev, 0, MDIO_DEVAD_NONE,
140 		  phy_read(phydev, MDIO_DEVAD_NONE, 0) & ~BIT(13));
141 
142 	/* Switch to page 1 */
143 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100);
144 	/* Disable APS */
145 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824);
146 	/* Switch to page 2 */
147 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200);
148 	/* PHYAFE TRX optimization */
149 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000);
150 	/* Switch to page 6 */
151 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600);
152 	/* PHYAFE TX optimization */
153 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x708f);
154 	/* PHYAFE RX optimization */
155 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_RX_CTRL, 0xf000);
156 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 0x1530);
157 
158 	/* Switch to page 8 */
159 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800);
160 	/* PHYAFE TRX optimization */
161 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AFE_CTRL, 0x00bc);
162 
163 	/* Switch to page 0 */
164 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000);
165 }
166 
rk630_phy_t22_config_init(struct phy_device * phydev)167 static void rk630_phy_t22_config_init(struct phy_device *phydev)
168 {
169 	unsigned char tx_level_100M = T22_TX_LEVEL_100M;
170 	unsigned char tx_level_10M = T22_TX_LEVEL_10M;
171 
172 	/* Switch to page 1 */
173 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100);
174 	/* Disable APS */
175 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824);
176 	/* Switch to page 2 */
177 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200);
178 	/* PHYAFE TRX optimization */
179 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000);
180 	/* Switch to page 6 */
181 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600);
182 	/* PHYAFE ADC optimization */
183 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_ANONTROL, 0x5540);
184 	/* PHYAFE Gain optimization */
185 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_GAIN_ANONTROL, 0x0400);
186 	/* PHYAFE EQ optimization */
187 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x1088);
188 
189 	if (rk630_phy_t22_get_txlevel_from_efuse(&tx_level_100M, &tx_level_10M)) {
190 		tx_level_100M = T22_TX_LEVEL_100M;
191 		tx_level_10M = T22_TX_LEVEL_10M;
192 	}
193 	/* PHYAFE TX optimization */
194 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2,
195 		  (tx_level_100M << 8) | tx_level_10M);
196 
197 	/* PHYAFE CP current optimization */
198 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_CP_CURRENT, 0x0575);
199 	/* ADC OP BIAS optimization */
200 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_OP_BIAS, 0x0000);
201 	/* Rx signal detctor level optimization */
202 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_RX_DECTOR, 0x0408);
203 	/* PHYAFE PDCW optimization */
204 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_PDCW, 0x8880);
205 	/* Add PHY Tx mos drive, reduce power noise/jitter */
206 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_TX_MOS_DRV, 0x888e);
207 
208 	/* Switch to page 8 */
209 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800);
210 	/* Disable auto-cal */
211 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AUTO_CAL, 0x0844);
212 
213 	/* Switch to page 0 */
214 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000);
215 
216 	/* Disable eee mode advertised */
217 	phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_CONTROL, 0x0007);
218 	phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_DATA_ADDRESS, 0x003c);
219 	phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_CONTROL, 0x4007);
220 	phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_DATA_ADDRESS, 0x0000);
221 }
rk630_phy_config_init(struct phy_device * phydev)222 static int rk630_phy_config_init(struct phy_device *phydev)
223 {
224 	switch (phydev->addr) {
225 	case PHY_ADDR_S40:
226 		rk630_phy_s40_config_init(phydev);
227 		break;
228 	case PHY_ADDR_T22:
229 		rk630_phy_t22_config_init(phydev);
230 		break;
231 	default:
232 		printf("Unsupported address for current phy: %d\n",
233 		       phydev->addr);
234 		return -EINVAL;
235 	}
236 
237 	genphy_config_aneg(phydev);
238 	return 0;
239 }
240 
241 static struct phy_driver RK630_driver = {
242 	.name = "Rockchip RK630",
243 	.uid = RK630_PHY_ID,
244 	.mask = 0xffffff,
245 	.features = PHY_BASIC_FEATURES,
246 	.config = &rk630_phy_config_init,
247 	.startup = &rk630_phy_startup,
248 };
249 
phy_rk630_init(void)250 int phy_rk630_init(void)
251 {
252 	phy_register(&RK630_driver);
253 	return 0;
254 }
255