xref: /rk3399_rockchip-uboot/drivers/net/phy/rockchip-fephy.c (revision cf51737fc4fd1e190fd2f560411ac79ec60f3825)
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