xref: /rk3399_rockchip-uboot/drivers/net/phy/rk630phy.c (revision 2bcebb1a79550117e5474bb586bdc094e4fe0576)
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_AFE_PDCW			0x1c
54 
55 /* PAGE 8 */
56 #define REG_PAGE8_AFE_CTRL			0x18
57 #define REG_PAGE8_AUTO_CAL			0x1d
58 
59 /*
60  * Fixed address:
61  * Addr: 1 --- RK630@S40
62  *       2 --- RV1106@T22
63  */
64 #define PHY_ADDR_S40 1
65 #define PHY_ADDR_T22 2
66 
67 #define T22_TX_LEVEL_100M			0x2d
68 #define T22_TX_LEVEL_10M			0x32
69 
70 static int rk630_phy_t22_get_txlevel_from_efuse(unsigned char *txlevel_100,
71 						unsigned char *txlevel_10)
72 {
73 #if defined(CONFIG_ROCKCHIP_EFUSE) || defined(CONFIG_ROCKCHIP_OTP)
74 	unsigned char tx_level[2];
75 	struct udevice *dev;
76 	u32 regs[2] = {0};
77 	ofnode node;
78 	int ret;
79 
80 	/* retrieve the device */
81 	if (IS_ENABLED(CONFIG_ROCKCHIP_EFUSE))
82 		ret = uclass_get_device_by_driver(UCLASS_MISC,
83 						  DM_GET_DRIVER(rockchip_efuse),
84 						  &dev);
85 	else
86 		ret = uclass_get_device_by_driver(UCLASS_MISC,
87 						  DM_GET_DRIVER(rockchip_otp),
88 						  &dev);
89 
90 	if (ret) {
91 		printf("%s: could not find efuse/otp device\n", __func__);
92 		return ret;
93 	}
94 
95 	node = dev_read_subnode(dev, "macphy-txlevel");
96 	if (!ofnode_valid(node))
97 		return -EINVAL;
98 
99 	ret = ofnode_read_u32_array(node, "reg", regs, 2);
100 	if (ret) {
101 		printf("Cannot get efuse reg\n");
102 		return -EINVAL;
103 	}
104 
105 	/* read the txlevel from the efuses */
106 	ret = misc_read(dev, regs[0], &tx_level, 2);
107 	if (ret) {
108 		printf("%s: read txlevel from efuse/otp failed, ret=%d\n",
109 		       __func__, ret);
110 		return ret;
111 	}
112 	*txlevel_100 = tx_level[1];
113 	*txlevel_10 = tx_level[0];
114 
115 	return 0;
116 #else
117 	return -EINVAL;
118 #endif
119 }
120 
121 static int rk630_phy_startup(struct phy_device *phydev)
122 {
123 	int ret;
124 
125 	/* Read the Status (2x to make sure link is right) */
126 	ret = genphy_update_link(phydev);
127 	if (ret)
128 		return ret;
129 
130 	/* Read the Status (2x to make sure link is right) */
131 	phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
132 
133 	return genphy_parse_link(phydev);
134 }
135 
136 static void rk630_phy_s40_config_init(struct phy_device *phydev)
137 {
138 	phy_write(phydev, 0, MDIO_DEVAD_NONE,
139 		  phy_read(phydev, MDIO_DEVAD_NONE, 0) & ~BIT(13));
140 
141 	/* Switch to page 1 */
142 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100);
143 	/* Disable APS */
144 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824);
145 	/* Switch to page 2 */
146 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200);
147 	/* PHYAFE TRX optimization */
148 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000);
149 	/* Switch to page 6 */
150 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600);
151 	/* PHYAFE TX optimization */
152 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x708f);
153 	/* PHYAFE RX optimization */
154 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_RX_CTRL, 0xf000);
155 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 0x1530);
156 
157 	/* Switch to page 8 */
158 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800);
159 	/* PHYAFE TRX optimization */
160 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AFE_CTRL, 0x00bc);
161 
162 	/* Switch to page 0 */
163 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000);
164 }
165 
166 static void rk630_phy_t22_config_init(struct phy_device *phydev)
167 {
168 	unsigned char tx_level_100M = T22_TX_LEVEL_100M;
169 	unsigned char tx_level_10M = T22_TX_LEVEL_10M;
170 
171 	/* Switch to page 1 */
172 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100);
173 	/* Disable APS */
174 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824);
175 	/* Switch to page 2 */
176 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200);
177 	/* PHYAFE TRX optimization */
178 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000);
179 	/* Switch to page 6 */
180 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600);
181 	/* PHYAFE ADC optimization */
182 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_ANONTROL, 0x5540);
183 	/* PHYAFE Gain optimization */
184 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_GAIN_ANONTROL, 0x0400);
185 	/* PHYAFE EQ optimization */
186 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x1088);
187 
188 	if (rk630_phy_t22_get_txlevel_from_efuse(&tx_level_100M, &tx_level_10M)) {
189 		tx_level_100M = T22_TX_LEVEL_100M;
190 		tx_level_10M = T22_TX_LEVEL_10M;
191 	}
192 	/* PHYAFE TX optimization */
193 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2,
194 		  (tx_level_100M << 8) | tx_level_10M);
195 
196 	/* PHYAFE CP current optimization */
197 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_CP_CURRENT, 0x0575);
198 	/* ADC OP BIAS optimization */
199 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_OP_BIAS, 0x0000);
200 	/* Rx signal detctor level optimization */
201 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_RX_DECTOR, 0x0408);
202 	/* PHYAFE PDCW optimization */
203 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_PDCW, 0x8880);
204 
205 	/* Switch to page 8 */
206 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800);
207 	/* Disable auto-cal */
208 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AUTO_CAL, 0x0844);
209 
210 	/* Switch to page 0 */
211 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000);
212 
213 	/* Disable eee mode advertised */
214 	phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_CONTROL, 0x0007);
215 	phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_DATA_ADDRESS, 0x003c);
216 	phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_CONTROL, 0x4007);
217 	phy_write(phydev, MDIO_DEVAD_NONE, REG_MMD_ACCESS_DATA_ADDRESS, 0x0000);
218 }
219 static int rk630_phy_config_init(struct phy_device *phydev)
220 {
221 	switch (phydev->addr) {
222 	case PHY_ADDR_S40:
223 		rk630_phy_s40_config_init(phydev);
224 		break;
225 	case PHY_ADDR_T22:
226 		rk630_phy_t22_config_init(phydev);
227 		break;
228 	default:
229 		printf("Unsupported address for current phy: %d\n",
230 		       phydev->addr);
231 		return -EINVAL;
232 	}
233 
234 	genphy_config_aneg(phydev);
235 	return 0;
236 }
237 
238 static struct phy_driver RK630_driver = {
239 	.name = "Rockchip RK630",
240 	.uid = RK630_PHY_ID,
241 	.mask = 0xffffff,
242 	.features = PHY_BASIC_FEATURES,
243 	.config = &rk630_phy_config_init,
244 	.startup = &rk630_phy_startup,
245 };
246 
247 int phy_rk630_init(void)
248 {
249 	phy_register(&RK630_driver);
250 	return 0;
251 }
252