1 // SPDX-License-Identifier: GPL-2.0+
2 /**
3 *
4 * Driver for ROCKCHIP Fast Ethernet PHYs
5 *
6 * Copyright (c) 2025, 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 ROCKCHIP_FEPHY_ID 0x06808101
23
24 #define MII_INTERNAL_CTRL_STATUS 17
25 #define SMI_ADDR_CFGCNTL 20
26 #define SMI_ADDR_TSTREAD1 21
27 #define SMI_ADDR_TSTREAD2 22
28 #define SMI_ADDR_TSTWRITE 23
29 #define MII_LED_CTRL 25
30 #define MII_INT_STATUS 29
31 #define MII_INT_MASK 30
32 #define MII_SPECIAL_CONTROL_STATUS 31
33
34 #define MII_AUTO_MDIX_EN BIT(7)
35 #define MII_MDIX_EN BIT(6)
36
37 #define MII_SPEED_10 BIT(2)
38 #define MII_SPEED_100 BIT(3)
39
40 #define CFGCNTL_WRITE_ADDR 0
41 #define CFGCNTL_READ_ADDR 5
42 #define CFGCNTL_GROUP_SEL 11
43 #define CFGCNTL_RD (BIT(15) | BIT(10))
44 #define CFGCNTL_WR (BIT(14) | BIT(10))
45
46 #define CFGCNTL_WRITE(group, reg) (CFGCNTL_WR | ((group) << CFGCNTL_GROUP_SEL) \
47 | ((reg) << CFGCNTL_WRITE_ADDR))
48 #define CFGCNTL_READ(group, reg) (CFGCNTL_RD | ((group) << CFGCNTL_GROUP_SEL) \
49 | ((reg) << CFGCNTL_READ_ADDR))
50
51 #define GAIN_PRE GENMASK(5, 2)
52 #define WR_ADDR_A7CFG 0x18
53
54 enum {
55 GROUP_CFG0 = 0,
56 GROUP_WOL,
57 GROUP_CFG0_READ,
58 GROUP_BIST,
59 GROUP_AFE,
60 GROUP_CFG1
61 };
62
rockchip_fephy_group_read(struct phy_device * phydev,u8 group,u32 reg)63 static int rockchip_fephy_group_read(struct phy_device *phydev, u8 group, u32 reg)
64 {
65 int ret;
66
67 ret = phy_write(phydev, MDIO_DEVAD_NONE, SMI_ADDR_CFGCNTL, CFGCNTL_READ(group, reg));
68 if (ret)
69 return ret;
70
71 if (group)
72 return phy_read(phydev, MDIO_DEVAD_NONE, SMI_ADDR_TSTREAD1);
73 else
74 return (phy_read(phydev, MDIO_DEVAD_NONE, SMI_ADDR_TSTREAD1) |
75 (phy_read(phydev, MDIO_DEVAD_NONE, SMI_ADDR_TSTREAD2) << 16));
76 }
77
rockchip_fephy_group_write(struct phy_device * phydev,u8 group,u32 reg,u16 val)78 static int rockchip_fephy_group_write(struct phy_device *phydev, u8 group,
79 u32 reg, u16 val)
80 {
81 int ret;
82
83 ret = phy_write(phydev, MDIO_DEVAD_NONE, SMI_ADDR_TSTWRITE, val);
84 if (ret)
85 return ret;
86
87 return phy_write(phydev, MDIO_DEVAD_NONE, SMI_ADDR_CFGCNTL, CFGCNTL_WRITE(group, reg));
88 }
89
rockchip_fephy_startup(struct phy_device * phydev)90 static int rockchip_fephy_startup(struct phy_device *phydev)
91 {
92 int ret;
93
94 /* Read the Status (2x to make sure link is right) */
95 ret = genphy_update_link(phydev);
96 if (ret)
97 return ret;
98
99 /* Read the Status (2x to make sure link is right) */
100 phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
101
102 return genphy_parse_link(phydev);
103 }
104
rockchip_fephy_config_init(struct phy_device * phydev)105 static int rockchip_fephy_config_init(struct phy_device *phydev)
106 {
107 int ret;
108
109 /* LED Control, default:0x7f */
110 ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_LED_CTRL, 0x7aa);
111 if (ret)
112 return ret;
113
114 /* off-energy level0 threshold */
115 ret = rockchip_fephy_group_write(phydev, GROUP_CFG0, 0xa, 0x6664);
116 if (ret)
117 return ret;
118
119 /* 100M amplitude control */
120 ret = rockchip_fephy_group_write(phydev, GROUP_CFG0, 0x18, 0xc);
121 if (ret)
122 return ret;
123
124 /* 24M */
125 {
126 int sel;
127
128 /* pll cp cur sel */
129 sel = rockchip_fephy_group_read(phydev, GROUP_AFE, 0x3);
130 if (sel < 0)
131 return sel;
132 ret = rockchip_fephy_group_write(phydev, GROUP_AFE, 0x3, sel | 0x2);
133 if (ret)
134 return ret;
135
136 /* pll lpf res sel */
137 ret = rockchip_fephy_group_write(phydev, GROUP_CFG0, 0x1a, 0x6);
138 if (ret)
139 return ret;
140 }
141
142 return ret;
143 }
144
145 static struct phy_driver rockchip_fephy_driver = {
146 .name = "Rockchip FEPHY",
147 .uid = ROCKCHIP_FEPHY_ID,
148 .mask = 0xfffffff,
149 .features = PHY_BASIC_FEATURES,
150 .config = &rockchip_fephy_config_init,
151 .startup = &rockchip_fephy_startup,
152 };
153
phy_rockchip_fephy_init(void)154 int phy_rockchip_fephy_init(void)
155 {
156 phy_register(&rockchip_fephy_driver);
157 return 0;
158 }
159