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