Skip to content

Commit 63edbcc

Browse files
microchip1davem330
authored andcommitted
net: phy: microchip_t1: add lan87xx_phy_init to initialize the lan87xx phy.
lan87xx_phy_init() initializes the lan87xx phy hardware including its TC10 Wake-up and Sleep features. Fixes: 3e50d2d ("Add driver for Microchip LAN87XX T1 PHYs") Signed-off-by: Yuiko Oshino <[email protected]> v0->v1: - Add more details in the commit message and source comments. - Update to the latest initialization sequences. - Add access_ereg_modify_changed(). - Fix access_ereg() to access SMI bank correctly. Signed-off-by: David S. Miller <[email protected]>
1 parent b9663b7 commit 63edbcc

File tree

1 file changed

+171
-0
lines changed

1 file changed

+171
-0
lines changed

drivers/net/phy/microchip_t1.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,21 @@
33

44
#include <linux/kernel.h>
55
#include <linux/module.h>
6+
#include <linux/delay.h>
67
#include <linux/mii.h>
78
#include <linux/phy.h>
89

10+
/* External Register Control Register */
11+
#define LAN87XX_EXT_REG_CTL (0x14)
12+
#define LAN87XX_EXT_REG_CTL_RD_CTL (0x1000)
13+
#define LAN87XX_EXT_REG_CTL_WR_CTL (0x0800)
14+
15+
/* External Register Read Data Register */
16+
#define LAN87XX_EXT_REG_RD_DATA (0x15)
17+
18+
/* External Register Write Data Register */
19+
#define LAN87XX_EXT_REG_WR_DATA (0x16)
20+
921
/* Interrupt Source Register */
1022
#define LAN87XX_INTERRUPT_SOURCE (0x18)
1123

@@ -14,9 +26,160 @@
1426
#define LAN87XX_MASK_LINK_UP (0x0004)
1527
#define LAN87XX_MASK_LINK_DOWN (0x0002)
1628

29+
/* phyaccess nested types */
30+
#define PHYACC_ATTR_MODE_READ 0
31+
#define PHYACC_ATTR_MODE_WRITE 1
32+
#define PHYACC_ATTR_MODE_MODIFY 2
33+
34+
#define PHYACC_ATTR_BANK_SMI 0
35+
#define PHYACC_ATTR_BANK_MISC 1
36+
#define PHYACC_ATTR_BANK_PCS 2
37+
#define PHYACC_ATTR_BANK_AFE 3
38+
#define PHYACC_ATTR_BANK_MAX 7
39+
1740
#define DRIVER_AUTHOR "Nisar Sayed <[email protected]>"
1841
#define DRIVER_DESC "Microchip LAN87XX T1 PHY driver"
1942

43+
struct access_ereg_val {
44+
u8 mode;
45+
u8 bank;
46+
u8 offset;
47+
u16 val;
48+
u16 mask;
49+
};
50+
51+
static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank,
52+
u8 offset, u16 val)
53+
{
54+
u16 ereg = 0;
55+
int rc = 0;
56+
57+
if (mode > PHYACC_ATTR_MODE_WRITE || bank > PHYACC_ATTR_BANK_MAX)
58+
return -EINVAL;
59+
60+
if (bank == PHYACC_ATTR_BANK_SMI) {
61+
if (mode == PHYACC_ATTR_MODE_WRITE)
62+
rc = phy_write(phydev, offset, val);
63+
else
64+
rc = phy_read(phydev, offset);
65+
return rc;
66+
}
67+
68+
if (mode == PHYACC_ATTR_MODE_WRITE) {
69+
ereg = LAN87XX_EXT_REG_CTL_WR_CTL;
70+
rc = phy_write(phydev, LAN87XX_EXT_REG_WR_DATA, val);
71+
if (rc < 0)
72+
return rc;
73+
} else {
74+
ereg = LAN87XX_EXT_REG_CTL_RD_CTL;
75+
}
76+
77+
ereg |= (bank << 8) | offset;
78+
79+
rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, ereg);
80+
if (rc < 0)
81+
return rc;
82+
83+
if (mode == PHYACC_ATTR_MODE_READ)
84+
rc = phy_read(phydev, LAN87XX_EXT_REG_RD_DATA);
85+
86+
return rc;
87+
}
88+
89+
static int access_ereg_modify_changed(struct phy_device *phydev,
90+
u8 bank, u8 offset, u16 val, u16 mask)
91+
{
92+
int new = 0, rc = 0;
93+
94+
if (bank > PHYACC_ATTR_BANK_MAX)
95+
return -EINVAL;
96+
97+
rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ, bank, offset, val);
98+
if (rc < 0)
99+
return rc;
100+
101+
new = val | (rc & (mask ^ 0xFFFF));
102+
rc = access_ereg(phydev, PHYACC_ATTR_MODE_WRITE, bank, offset, new);
103+
104+
return rc;
105+
}
106+
107+
static int lan87xx_phy_init(struct phy_device *phydev)
108+
{
109+
static const struct access_ereg_val init[] = {
110+
/* TX Amplitude = 5 */
111+
{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_AFE, 0x0B,
112+
0x000A, 0x001E},
113+
/* Clear SMI interrupts */
114+
{PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, 0x18,
115+
0, 0},
116+
/* Clear MISC interrupts */
117+
{PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC, 0x08,
118+
0, 0},
119+
/* Turn on TC10 Ring Oscillator (ROSC) */
120+
{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_MISC, 0x20,
121+
0x0020, 0x0020},
122+
/* WUR Detect Length to 1.2uS, LPC Detect Length to 1.09uS */
123+
{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_PCS, 0x20,
124+
0x283C, 0},
125+
/* Wake_In Debounce Length to 39uS, Wake_Out Length to 79uS */
126+
{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x21,
127+
0x274F, 0},
128+
/* Enable Auto Wake Forward to Wake_Out, ROSC on, Sleep,
129+
* and Wake_In to wake PHY
130+
*/
131+
{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x20,
132+
0x80A7, 0},
133+
/* Enable WUP Auto Fwd, Enable Wake on MDI, Wakeup Debouncer
134+
* to 128 uS
135+
*/
136+
{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x24,
137+
0xF110, 0},
138+
/* Enable HW Init */
139+
{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_SMI, 0x1A,
140+
0x0100, 0x0100},
141+
};
142+
int rc, i;
143+
144+
/* Start manual initialization procedures in Managed Mode */
145+
rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
146+
0x1a, 0x0000, 0x0100);
147+
if (rc < 0)
148+
return rc;
149+
150+
/* Soft Reset the SMI block */
151+
rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
152+
0x00, 0x8000, 0x8000);
153+
if (rc < 0)
154+
return rc;
155+
156+
/* Check to see if the self-clearing bit is cleared */
157+
usleep_range(1000, 2000);
158+
rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
159+
PHYACC_ATTR_BANK_SMI, 0x00, 0);
160+
if (rc < 0)
161+
return rc;
162+
if ((rc & 0x8000) != 0)
163+
return -ETIMEDOUT;
164+
165+
/* PHY Initialization */
166+
for (i = 0; i < ARRAY_SIZE(init); i++) {
167+
if (init[i].mode == PHYACC_ATTR_MODE_MODIFY) {
168+
rc = access_ereg_modify_changed(phydev, init[i].bank,
169+
init[i].offset,
170+
init[i].val,
171+
init[i].mask);
172+
} else {
173+
rc = access_ereg(phydev, init[i].mode, init[i].bank,
174+
init[i].offset, init[i].val);
175+
}
176+
if (rc < 0)
177+
return rc;
178+
}
179+
180+
return 0;
181+
}
182+
20183
static int lan87xx_phy_config_intr(struct phy_device *phydev)
21184
{
22185
int rc, val = 0;
@@ -40,6 +203,13 @@ static int lan87xx_phy_ack_interrupt(struct phy_device *phydev)
40203
return rc < 0 ? rc : 0;
41204
}
42205

206+
static int lan87xx_config_init(struct phy_device *phydev)
207+
{
208+
int rc = lan87xx_phy_init(phydev);
209+
210+
return rc < 0 ? rc : 0;
211+
}
212+
43213
static struct phy_driver microchip_t1_phy_driver[] = {
44214
{
45215
.phy_id = 0x0007c150,
@@ -48,6 +218,7 @@ static struct phy_driver microchip_t1_phy_driver[] = {
48218

49219
.features = PHY_BASIC_T1_FEATURES,
50220

221+
.config_init = lan87xx_config_init,
51222
.config_aneg = genphy_config_aneg,
52223

53224
.ack_interrupt = lan87xx_phy_ack_interrupt,

0 commit comments

Comments
 (0)