xref: /rk3399_rockchip-uboot/drivers/net/phy/rk630phy.c (revision e55dfbd47140353ad2ac122e706d44b699c8162a)
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 <linux/bitops.h>
20 #include <phy.h>
21 
22 #define RK630_PHY_ID				0x00441400
23 
24 /* PAGE 0 */
25 #define REG_INTERRUPT_STATUS			0X10
26 #define REG_INTERRUPT_MASK			0X11
27 #define REG_GLOBAL_CONFIGURATION		0X13
28 #define REG_MAC_ADDRESS0			0x16
29 #define REG_MAC_ADDRESS1			0x17
30 #define REG_MAC_ADDRESS2			0x18
31 
32 #define REG_PAGE_SEL				0x1F
33 
34 /* PAGE 1 */
35 #define REG_PAGE1_APS_CTRL			0x12
36 #define REG_PAGE1_UAPS_CONFIGURE		0X13
37 #define REG_PAGE1_EEE_CONFIGURE			0x17
38 
39 /* PAGE 2 */
40 #define REG_PAGE2_AFE_CTRL			0x18
41 
42 /* PAGE 6 */
43 #define REG_PAGE6_ADC_ANONTROL			0x10
44 #define REG_PAGE6_AFE_RX_CTRL			0x13
45 #define REG_PAGE6_AFE_TX_CTRL			0x14
46 #define REG_PAGE6_AFE_DRIVER2			0x15
47 
48 /* PAGE 8 */
49 #define REG_PAGE8_AFE_CTRL			0x18
50 
51 static void rk630_phy_ieee_set(struct phy_device *phydev, bool enable)
52 {
53 	u32 value;
54 
55 	/* Switch to page 1 */
56 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100);
57 	value = phy_read(phydev, MDIO_DEVAD_NONE, REG_PAGE1_EEE_CONFIGURE);
58 	if (enable)
59 		value |= BIT(3);
60 	else
61 		value &= ~BIT(3);
62 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_EEE_CONFIGURE, value);
63 	/* Switch to page 0 */
64 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000);
65 }
66 
67 static void rk630_phy_set_uaps(struct phy_device *phydev)
68 {
69 	u32 value;
70 
71 	/* Switch to page 1 */
72 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100);
73 	value = phy_read(phydev, MDIO_DEVAD_NONE, REG_PAGE1_UAPS_CONFIGURE);
74 	value |= BIT(15);
75 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_UAPS_CONFIGURE, value);
76 	/* Switch to page 0 */
77 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000);
78 }
79 
80 static int rk630_phy_config_init(struct phy_device *phydev)
81 {
82 	u32 value;
83 
84 	phy_write(phydev, 0, MDIO_DEVAD_NONE,
85 		  phy_read(phydev, MDIO_DEVAD_NONE, 0) & ~BIT(13));
86 
87 	/* Switch to page 1 */
88 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0100);
89 	/* Disable APS */
90 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE1_APS_CTRL, 0x4824);
91 	/* Switch to page 2 */
92 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0200);
93 	/* PHYAFE TRX optimization */
94 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE2_AFE_CTRL, 0x0000);
95 	/* Switch to page 6 */
96 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600);
97 	/* PHYAFE TX optimization */
98 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_TX_CTRL, 0x708f);
99 	/* PHYAFE RX optimization */
100 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_RX_CTRL, 0xf000);
101 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, 0x1530);
102 
103 	/* Switch to page 8 */
104 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0800);
105 	/* PHYAFE TRX optimization */
106 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE8_AFE_CTRL, 0x00bc);
107 
108 	/* Adjust tx level, bypass */
109 	value = phy_read(phydev, MDIO_DEVAD_NONE, 0x1d);
110 	value |= BIT(11);
111 	phy_write(phydev, 0x1d, MDIO_DEVAD_NONE, value);
112 	/* switch to page6 */
113 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0600);
114 	/* Enable tx level control */
115 	value = phy_read(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_ANONTROL);
116 	value &= ~BIT(6);
117 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_ADC_ANONTROL, value);
118 	/* Set tx level */
119 	value = phy_read(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2);
120 	value &= ~GENMASK(15, 8);
121 	value |= 0x121a;
122 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE6_AFE_DRIVER2, value);
123 
124 	/* Switch to page 0 */
125 	phy_write(phydev, MDIO_DEVAD_NONE, REG_PAGE_SEL, 0x0000);
126 
127 	rk630_phy_ieee_set(phydev, true);
128 	/*
129 	 * Ultra Auto-Power Saving Mode (UAPS) is designed to
130 	 * save power when cable is not plugged into PHY.
131 	 */
132 	rk630_phy_set_uaps(phydev);
133 
134 	return 0;
135 }
136 
137 static int rk630_phy_probe(struct phy_device *phydev)
138 {
139 	return 0;
140 }
141 
142 static struct phy_driver RK630_driver = {
143 	.name = "Rockchip RK630",
144 	.uid = RK630_PHY_ID,
145 	.mask = 0xffffff,
146 	.features = PHY_BASIC_FEATURES,
147 	.probe = &rk630_phy_probe,
148 	.config = &rk630_phy_config_init,
149 	.shutdown = &genphy_shutdown,
150 };
151 
152 int phy_rk630_init(void)
153 {
154 	phy_register(&RK630_driver);
155 
156 	return 0;
157 }
158