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