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