1*a5fd13adSJohn Haechten /*
2*a5fd13adSJohn Haechten * Microsemi PHY drivers
3*a5fd13adSJohn Haechten *
4*a5fd13adSJohn Haechten * SPDX-License-Identifier: The MIT License (MIT)
5*a5fd13adSJohn Haechten *
6*a5fd13adSJohn Haechten * Copyright (c) 2016 Microsemi Corporation
7*a5fd13adSJohn Haechten *
8*a5fd13adSJohn Haechten * Author: John Haechten
9*a5fd13adSJohn Haechten *
10*a5fd13adSJohn Haechten */
11*a5fd13adSJohn Haechten
12*a5fd13adSJohn Haechten #include <miiphy.h>
13*a5fd13adSJohn Haechten #include <bitfield.h>
14*a5fd13adSJohn Haechten
15*a5fd13adSJohn Haechten /* Microsemi PHY ID's */
16*a5fd13adSJohn Haechten #define PHY_ID_VSC8530 0x00070560
17*a5fd13adSJohn Haechten #define PHY_ID_VSC8531 0x00070570
18*a5fd13adSJohn Haechten #define PHY_ID_VSC8540 0x00070760
19*a5fd13adSJohn Haechten #define PHY_ID_VSC8541 0x00070770
20*a5fd13adSJohn Haechten
21*a5fd13adSJohn Haechten /* Microsemi VSC85xx PHY Register Pages */
22*a5fd13adSJohn Haechten #define MSCC_EXT_PAGE_ACCESS 31 /* Page Access Register */
23*a5fd13adSJohn Haechten #define MSCC_PHY_PAGE_STD 0x0000 /* Standard registers */
24*a5fd13adSJohn Haechten #define MSCC_PHY_PAGE_EXT1 0x0001 /* Extended registers - page 1 */
25*a5fd13adSJohn Haechten #define MSCC_PHY_PAGE_EXT2 0x0002 /* Extended registers - page 2 */
26*a5fd13adSJohn Haechten #define MSCC_PHY_PAGE_EXT3 0x0003 /* Extended registers - page 3 */
27*a5fd13adSJohn Haechten #define MSCC_PHY_PAGE_EXT4 0x0004 /* Extended registers - page 4 */
28*a5fd13adSJohn Haechten #define MSCC_PHY_PAGE_GPIO 0x0010 /* GPIO registers */
29*a5fd13adSJohn Haechten #define MSCC_PHY_PAGE_TEST 0x2A30 /* TEST Page registers */
30*a5fd13adSJohn Haechten #define MSCC_PHY_PAGE_TR 0x52B5 /* Token Ring Page registers */
31*a5fd13adSJohn Haechten
32*a5fd13adSJohn Haechten /* Std Page Register 28 - PHY AUX Control/Status */
33*a5fd13adSJohn Haechten #define MIIM_AUX_CNTRL_STAT_REG 28
34*a5fd13adSJohn Haechten #define MIIM_AUX_CNTRL_STAT_ACTIPHY_TO (0x0004)
35*a5fd13adSJohn Haechten #define MIIM_AUX_CNTRL_STAT_F_DUPLEX (0x0020)
36*a5fd13adSJohn Haechten #define MIIM_AUX_CNTRL_STAT_SPEED_MASK (0x0018)
37*a5fd13adSJohn Haechten #define MIIM_AUX_CNTRL_STAT_SPEED_POS (3)
38*a5fd13adSJohn Haechten #define MIIM_AUX_CNTRL_STAT_SPEED_10M (0x0)
39*a5fd13adSJohn Haechten #define MIIM_AUX_CNTRL_STAT_SPEED_100M (0x1)
40*a5fd13adSJohn Haechten #define MIIM_AUX_CNTRL_STAT_SPEED_1000M (0x2)
41*a5fd13adSJohn Haechten
42*a5fd13adSJohn Haechten /* Std Page Register 23 - Extended PHY CTRL_1 */
43*a5fd13adSJohn Haechten #define MSCC_PHY_EXT_PHY_CNTL_1_REG 23
44*a5fd13adSJohn Haechten #define MAC_IF_SELECTION_MASK (0x1800)
45*a5fd13adSJohn Haechten #define MAC_IF_SELECTION_GMII (0)
46*a5fd13adSJohn Haechten #define MAC_IF_SELECTION_RMII (1)
47*a5fd13adSJohn Haechten #define MAC_IF_SELECTION_RGMII (2)
48*a5fd13adSJohn Haechten #define MAC_IF_SELECTION_POS (11)
49*a5fd13adSJohn Haechten #define MAC_IF_SELECTION_WIDTH (2)
50*a5fd13adSJohn Haechten
51*a5fd13adSJohn Haechten /* Extended Page 2 Register 20E2 */
52*a5fd13adSJohn Haechten #define MSCC_PHY_RGMII_CNTL_REG 20
53*a5fd13adSJohn Haechten #define VSC_FAST_LINK_FAIL2_ENA_MASK (0x8000)
54*a5fd13adSJohn Haechten #define RX_CLK_OUT_MASK (0x0800)
55*a5fd13adSJohn Haechten #define RX_CLK_OUT_POS (11)
56*a5fd13adSJohn Haechten #define RX_CLK_OUT_WIDTH (1)
57*a5fd13adSJohn Haechten #define RX_CLK_OUT_NORMAL (0)
58*a5fd13adSJohn Haechten #define RX_CLK_OUT_DISABLE (1)
59*a5fd13adSJohn Haechten #define RGMII_RX_CLK_DELAY_POS (4)
60*a5fd13adSJohn Haechten #define RGMII_RX_CLK_DELAY_WIDTH (3)
61*a5fd13adSJohn Haechten #define RGMII_RX_CLK_DELAY_MASK (0x0070)
62*a5fd13adSJohn Haechten #define RGMII_TX_CLK_DELAY_POS (0)
63*a5fd13adSJohn Haechten #define RGMII_TX_CLK_DELAY_WIDTH (3)
64*a5fd13adSJohn Haechten #define RGMII_TX_CLK_DELAY_MASK (0x0007)
65*a5fd13adSJohn Haechten
66*a5fd13adSJohn Haechten /* Extended Page 2 Register 27E2 */
67*a5fd13adSJohn Haechten #define MSCC_PHY_WOL_MAC_CONTROL 27
68*a5fd13adSJohn Haechten #define EDGE_RATE_CNTL_POS (5)
69*a5fd13adSJohn Haechten #define EDGE_RATE_CNTL_WIDTH (3)
70*a5fd13adSJohn Haechten #define EDGE_RATE_CNTL_MASK (0x00E0)
71*a5fd13adSJohn Haechten #define RMII_CLK_OUT_ENABLE_POS (4)
72*a5fd13adSJohn Haechten #define RMII_CLK_OUT_ENABLE_WIDTH (1)
73*a5fd13adSJohn Haechten #define RMII_CLK_OUT_ENABLE_MASK (0x10)
74*a5fd13adSJohn Haechten
75*a5fd13adSJohn Haechten /* Token Ring Page 0x52B5 Registers */
76*a5fd13adSJohn Haechten #define MSCC_PHY_REG_TR_ADDR_16 16
77*a5fd13adSJohn Haechten #define MSCC_PHY_REG_TR_DATA_17 17
78*a5fd13adSJohn Haechten #define MSCC_PHY_REG_TR_DATA_18 18
79*a5fd13adSJohn Haechten
80*a5fd13adSJohn Haechten /* Token Ring - Read Value in */
81*a5fd13adSJohn Haechten #define MSCC_PHY_TR_16_READ (0xA000)
82*a5fd13adSJohn Haechten /* Token Ring - Write Value out */
83*a5fd13adSJohn Haechten #define MSCC_PHY_TR_16_WRITE (0x8000)
84*a5fd13adSJohn Haechten
85*a5fd13adSJohn Haechten /* Token Ring Registers */
86*a5fd13adSJohn Haechten #define MSCC_PHY_TR_LINKDETCTRL_POS (3)
87*a5fd13adSJohn Haechten #define MSCC_PHY_TR_LINKDETCTRL_WIDTH (2)
88*a5fd13adSJohn Haechten #define MSCC_PHY_TR_LINKDETCTRL_VAL (3)
89*a5fd13adSJohn Haechten #define MSCC_PHY_TR_LINKDETCTRL_MASK (0x0018)
90*a5fd13adSJohn Haechten #define MSCC_PHY_TR_LINKDETCTRL_ADDR (0x07F8)
91*a5fd13adSJohn Haechten
92*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGATHRESH100_POS (0)
93*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGATHRESH100_WIDTH (7)
94*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGATHRESH100_VAL (0x0018)
95*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGATHRESH100_MASK (0x007f)
96*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGATHRESH100_ADDR (0x0FA4)
97*a5fd13adSJohn Haechten
98*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_U_POS (0)
99*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_U_WIDTH (1)
100*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_U_MASK (0x0001)
101*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_U_VAL (0)
102*a5fd13adSJohn Haechten
103*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_L_POS (12)
104*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_L_WIDTH (4)
105*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_L_MASK (0xf000)
106*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_L_VAL (0x0001)
107*a5fd13adSJohn Haechten #define MSCC_PHY_TR_VGAGAIN10_ADDR (0x0F92)
108*a5fd13adSJohn Haechten
109*a5fd13adSJohn Haechten /* General Timeout Values */
110*a5fd13adSJohn Haechten #define MSCC_PHY_RESET_TIMEOUT (100)
111*a5fd13adSJohn Haechten #define MSCC_PHY_MICRO_TIMEOUT (500)
112*a5fd13adSJohn Haechten
113*a5fd13adSJohn Haechten /* RGMII/GMII Clock Delay (Skew) Options */ enum vsc_phy_rgmii_skew {
114*a5fd13adSJohn Haechten VSC_PHY_RGMII_DELAY_200_PS,
115*a5fd13adSJohn Haechten VSC_PHY_RGMII_DELAY_800_PS,
116*a5fd13adSJohn Haechten VSC_PHY_RGMII_DELAY_1100_PS,
117*a5fd13adSJohn Haechten VSC_PHY_RGMII_DELAY_1700_PS,
118*a5fd13adSJohn Haechten VSC_PHY_RGMII_DELAY_2000_PS,
119*a5fd13adSJohn Haechten VSC_PHY_RGMII_DELAY_2300_PS,
120*a5fd13adSJohn Haechten VSC_PHY_RGMII_DELAY_2600_PS,
121*a5fd13adSJohn Haechten VSC_PHY_RGMII_DELAY_3400_PS,
122*a5fd13adSJohn Haechten };
123*a5fd13adSJohn Haechten
124*a5fd13adSJohn Haechten /* MAC i/f Clock Edge Rage Control (Slew), See Reg27E2 */ enum
125*a5fd13adSJohn Haechten vsc_phy_clk_slew {
126*a5fd13adSJohn Haechten VSC_PHY_CLK_SLEW_RATE_0,
127*a5fd13adSJohn Haechten VSC_PHY_CLK_SLEW_RATE_1,
128*a5fd13adSJohn Haechten VSC_PHY_CLK_SLEW_RATE_2,
129*a5fd13adSJohn Haechten VSC_PHY_CLK_SLEW_RATE_3,
130*a5fd13adSJohn Haechten VSC_PHY_CLK_SLEW_RATE_4,
131*a5fd13adSJohn Haechten VSC_PHY_CLK_SLEW_RATE_5,
132*a5fd13adSJohn Haechten VSC_PHY_CLK_SLEW_RATE_6,
133*a5fd13adSJohn Haechten VSC_PHY_CLK_SLEW_RATE_7,
134*a5fd13adSJohn Haechten };
135*a5fd13adSJohn Haechten
136*a5fd13adSJohn Haechten
mscc_vsc8531_vsc8541_init_scripts(struct phy_device * phydev)137*a5fd13adSJohn Haechten static int mscc_vsc8531_vsc8541_init_scripts(struct phy_device *phydev)
138*a5fd13adSJohn Haechten {
139*a5fd13adSJohn Haechten u16 reg_val;
140*a5fd13adSJohn Haechten
141*a5fd13adSJohn Haechten /* Set to Access Token Ring Registers */
142*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE,
143*a5fd13adSJohn Haechten MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR);
144*a5fd13adSJohn Haechten
145*a5fd13adSJohn Haechten /* Update LinkDetectCtrl default to optimized values */
146*a5fd13adSJohn Haechten /* Determined during Silicon Validation Testing */
147*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
148*a5fd13adSJohn Haechten (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_READ));
149*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17);
150*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_LINKDETCTRL_POS,
151*a5fd13adSJohn Haechten MSCC_PHY_TR_LINKDETCTRL_WIDTH,
152*a5fd13adSJohn Haechten MSCC_PHY_TR_LINKDETCTRL_VAL);
153*a5fd13adSJohn Haechten
154*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val);
155*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
156*a5fd13adSJohn Haechten (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_WRITE));
157*a5fd13adSJohn Haechten
158*a5fd13adSJohn Haechten /* Update VgaThresh100 defaults to optimized values */
159*a5fd13adSJohn Haechten /* Determined during Silicon Validation Testing */
160*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
161*a5fd13adSJohn Haechten (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_READ));
162*a5fd13adSJohn Haechten
163*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
164*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGATHRESH100_POS,
165*a5fd13adSJohn Haechten MSCC_PHY_TR_VGATHRESH100_WIDTH,
166*a5fd13adSJohn Haechten MSCC_PHY_TR_VGATHRESH100_VAL);
167*a5fd13adSJohn Haechten
168*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val);
169*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
170*a5fd13adSJohn Haechten (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_WRITE));
171*a5fd13adSJohn Haechten
172*a5fd13adSJohn Haechten /* Update VgaGain10 defaults to optimized values */
173*a5fd13adSJohn Haechten /* Determined during Silicon Validation Testing */
174*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
175*a5fd13adSJohn Haechten (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_READ));
176*a5fd13adSJohn Haechten
177*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18);
178*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_U_POS,
179*a5fd13adSJohn Haechten MSCC_PHY_TR_VGAGAIN10_U_WIDTH,
180*a5fd13adSJohn Haechten MSCC_PHY_TR_VGAGAIN10_U_VAL);
181*a5fd13adSJohn Haechten
182*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val);
183*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17);
184*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_L_POS,
185*a5fd13adSJohn Haechten MSCC_PHY_TR_VGAGAIN10_L_WIDTH,
186*a5fd13adSJohn Haechten MSCC_PHY_TR_VGAGAIN10_L_VAL);
187*a5fd13adSJohn Haechten
188*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val);
189*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16,
190*a5fd13adSJohn Haechten (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_WRITE));
191*a5fd13adSJohn Haechten
192*a5fd13adSJohn Haechten /* Set back to Access Standard Page Registers */
193*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
194*a5fd13adSJohn Haechten MSCC_PHY_PAGE_STD);
195*a5fd13adSJohn Haechten
196*a5fd13adSJohn Haechten return 0;
197*a5fd13adSJohn Haechten }
198*a5fd13adSJohn Haechten
mscc_parse_status(struct phy_device * phydev)199*a5fd13adSJohn Haechten static int mscc_parse_status(struct phy_device *phydev)
200*a5fd13adSJohn Haechten {
201*a5fd13adSJohn Haechten u16 speed;
202*a5fd13adSJohn Haechten u16 mii_reg;
203*a5fd13adSJohn Haechten
204*a5fd13adSJohn Haechten mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_AUX_CNTRL_STAT_REG);
205*a5fd13adSJohn Haechten
206*a5fd13adSJohn Haechten if (mii_reg & MIIM_AUX_CNTRL_STAT_F_DUPLEX)
207*a5fd13adSJohn Haechten phydev->duplex = DUPLEX_FULL;
208*a5fd13adSJohn Haechten else
209*a5fd13adSJohn Haechten phydev->duplex = DUPLEX_HALF;
210*a5fd13adSJohn Haechten
211*a5fd13adSJohn Haechten speed = mii_reg & MIIM_AUX_CNTRL_STAT_SPEED_MASK;
212*a5fd13adSJohn Haechten speed = speed >> MIIM_AUX_CNTRL_STAT_SPEED_POS;
213*a5fd13adSJohn Haechten
214*a5fd13adSJohn Haechten switch (speed) {
215*a5fd13adSJohn Haechten case MIIM_AUX_CNTRL_STAT_SPEED_1000M:
216*a5fd13adSJohn Haechten phydev->speed = SPEED_1000;
217*a5fd13adSJohn Haechten break;
218*a5fd13adSJohn Haechten case MIIM_AUX_CNTRL_STAT_SPEED_100M:
219*a5fd13adSJohn Haechten phydev->speed = SPEED_100;
220*a5fd13adSJohn Haechten break;
221*a5fd13adSJohn Haechten case MIIM_AUX_CNTRL_STAT_SPEED_10M:
222*a5fd13adSJohn Haechten phydev->speed = SPEED_10;
223*a5fd13adSJohn Haechten break;
224*a5fd13adSJohn Haechten default:
225*a5fd13adSJohn Haechten phydev->speed = SPEED_10;
226*a5fd13adSJohn Haechten break;
227*a5fd13adSJohn Haechten }
228*a5fd13adSJohn Haechten
229*a5fd13adSJohn Haechten return 0;
230*a5fd13adSJohn Haechten }
231*a5fd13adSJohn Haechten
mscc_startup(struct phy_device * phydev)232*a5fd13adSJohn Haechten static int mscc_startup(struct phy_device *phydev)
233*a5fd13adSJohn Haechten {
234*a5fd13adSJohn Haechten int retval;
235*a5fd13adSJohn Haechten
236*a5fd13adSJohn Haechten retval = genphy_update_link(phydev);
237*a5fd13adSJohn Haechten
238*a5fd13adSJohn Haechten if (retval)
239*a5fd13adSJohn Haechten return retval;
240*a5fd13adSJohn Haechten
241*a5fd13adSJohn Haechten return mscc_parse_status(phydev);
242*a5fd13adSJohn Haechten }
243*a5fd13adSJohn Haechten
mscc_phy_soft_reset(struct phy_device * phydev)244*a5fd13adSJohn Haechten static int mscc_phy_soft_reset(struct phy_device *phydev)
245*a5fd13adSJohn Haechten {
246*a5fd13adSJohn Haechten int retval = 0;
247*a5fd13adSJohn Haechten u16 timeout = MSCC_PHY_RESET_TIMEOUT;
248*a5fd13adSJohn Haechten u16 reg_val = 0;
249*a5fd13adSJohn Haechten
250*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
251*a5fd13adSJohn Haechten MSCC_PHY_PAGE_STD);
252*a5fd13adSJohn Haechten
253*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
254*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (reg_val | BMCR_RESET));
255*a5fd13adSJohn Haechten
256*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
257*a5fd13adSJohn Haechten
258*a5fd13adSJohn Haechten while ((reg_val & BMCR_RESET) && (timeout > 0)) {
259*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
260*a5fd13adSJohn Haechten timeout--;
261*a5fd13adSJohn Haechten udelay(1000); /* 1 ms */
262*a5fd13adSJohn Haechten }
263*a5fd13adSJohn Haechten
264*a5fd13adSJohn Haechten if (timeout == 0) {
265*a5fd13adSJohn Haechten printf("MSCC PHY Soft_Reset Error: mac i/f = 0x%x\n",
266*a5fd13adSJohn Haechten phydev->interface);
267*a5fd13adSJohn Haechten retval = -ETIME;
268*a5fd13adSJohn Haechten }
269*a5fd13adSJohn Haechten
270*a5fd13adSJohn Haechten return retval;
271*a5fd13adSJohn Haechten }
272*a5fd13adSJohn Haechten
vsc8531_vsc8541_mac_config(struct phy_device * phydev)273*a5fd13adSJohn Haechten static int vsc8531_vsc8541_mac_config(struct phy_device *phydev)
274*a5fd13adSJohn Haechten {
275*a5fd13adSJohn Haechten u16 reg_val = 0;
276*a5fd13adSJohn Haechten u16 mac_if = 0;
277*a5fd13adSJohn Haechten u16 rx_clk_out = 0;
278*a5fd13adSJohn Haechten
279*a5fd13adSJohn Haechten /* For VSC8530/31 the only MAC modes are RMII/RGMII. */
280*a5fd13adSJohn Haechten /* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */
281*a5fd13adSJohn Haechten /* Setup MAC Configuration */
282*a5fd13adSJohn Haechten switch (phydev->interface) {
283*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_MII:
284*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_GMII:
285*a5fd13adSJohn Haechten /* Set Reg23.12:11=0 */
286*a5fd13adSJohn Haechten mac_if = MAC_IF_SELECTION_GMII;
287*a5fd13adSJohn Haechten /* Set Reg20E2.11=1 */
288*a5fd13adSJohn Haechten rx_clk_out = RX_CLK_OUT_DISABLE;
289*a5fd13adSJohn Haechten break;
290*a5fd13adSJohn Haechten
291*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_RMII:
292*a5fd13adSJohn Haechten /* Set Reg23.12:11=1 */
293*a5fd13adSJohn Haechten mac_if = MAC_IF_SELECTION_RMII;
294*a5fd13adSJohn Haechten /* Set Reg20E2.11=0 */
295*a5fd13adSJohn Haechten rx_clk_out = RX_CLK_OUT_NORMAL;
296*a5fd13adSJohn Haechten break;
297*a5fd13adSJohn Haechten
298*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_RGMII:
299*a5fd13adSJohn Haechten /* Set Reg23.12:11=2 */
300*a5fd13adSJohn Haechten mac_if = MAC_IF_SELECTION_RGMII;
301*a5fd13adSJohn Haechten /* Set Reg20E2.11=0 */
302*a5fd13adSJohn Haechten rx_clk_out = RX_CLK_OUT_NORMAL;
303*a5fd13adSJohn Haechten break;
304*a5fd13adSJohn Haechten
305*a5fd13adSJohn Haechten default:
306*a5fd13adSJohn Haechten printf("MSCC PHY - INVALID MAC i/f Config: mac i/f = 0x%x\n",
307*a5fd13adSJohn Haechten phydev->interface);
308*a5fd13adSJohn Haechten return -EINVAL;
309*a5fd13adSJohn Haechten }
310*a5fd13adSJohn Haechten
311*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
312*a5fd13adSJohn Haechten MSCC_PHY_PAGE_STD);
313*a5fd13adSJohn Haechten
314*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
315*a5fd13adSJohn Haechten MSCC_PHY_EXT_PHY_CNTL_1_REG);
316*a5fd13adSJohn Haechten /* Set MAC i/f bits Reg23.12:11 */
317*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, MAC_IF_SELECTION_POS,
318*a5fd13adSJohn Haechten MAC_IF_SELECTION_WIDTH, mac_if);
319*a5fd13adSJohn Haechten /* Update Reg23.12:11 */
320*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE,
321*a5fd13adSJohn Haechten MSCC_PHY_EXT_PHY_CNTL_1_REG, reg_val);
322*a5fd13adSJohn Haechten /* Setup ExtPg_2 Register Access */
323*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE,
324*a5fd13adSJohn Haechten MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXT2);
325*a5fd13adSJohn Haechten /* Read Reg20E2 */
326*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE,
327*a5fd13adSJohn Haechten MSCC_PHY_RGMII_CNTL_REG);
328*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, RX_CLK_OUT_POS,
329*a5fd13adSJohn Haechten RX_CLK_OUT_WIDTH, rx_clk_out);
330*a5fd13adSJohn Haechten /* Update Reg20E2.11 */
331*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE,
332*a5fd13adSJohn Haechten MSCC_PHY_RGMII_CNTL_REG, reg_val);
333*a5fd13adSJohn Haechten /* Before leaving - Change back to Std Page Register Access */
334*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
335*a5fd13adSJohn Haechten MSCC_PHY_PAGE_STD);
336*a5fd13adSJohn Haechten
337*a5fd13adSJohn Haechten return 0;
338*a5fd13adSJohn Haechten }
339*a5fd13adSJohn Haechten
vsc8531_config(struct phy_device * phydev)340*a5fd13adSJohn Haechten static int vsc8531_config(struct phy_device *phydev)
341*a5fd13adSJohn Haechten {
342*a5fd13adSJohn Haechten int retval = -EINVAL;
343*a5fd13adSJohn Haechten u16 reg_val;
344*a5fd13adSJohn Haechten u16 rmii_clk_out;
345*a5fd13adSJohn Haechten enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
346*a5fd13adSJohn Haechten enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
347*a5fd13adSJohn Haechten enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
348*a5fd13adSJohn Haechten
349*a5fd13adSJohn Haechten /* For VSC8530/31 and VSC8540/41 the init scripts are the same */
350*a5fd13adSJohn Haechten mscc_vsc8531_vsc8541_init_scripts(phydev);
351*a5fd13adSJohn Haechten
352*a5fd13adSJohn Haechten /* For VSC8530/31 the only MAC modes are RMII/RGMII. */
353*a5fd13adSJohn Haechten switch (phydev->interface) {
354*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_RMII:
355*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_RGMII:
356*a5fd13adSJohn Haechten retval = vsc8531_vsc8541_mac_config(phydev);
357*a5fd13adSJohn Haechten if (retval != 0)
358*a5fd13adSJohn Haechten return retval;
359*a5fd13adSJohn Haechten
360*a5fd13adSJohn Haechten retval = mscc_phy_soft_reset(phydev);
361*a5fd13adSJohn Haechten if (retval != 0)
362*a5fd13adSJohn Haechten return retval;
363*a5fd13adSJohn Haechten break;
364*a5fd13adSJohn Haechten default:
365*a5fd13adSJohn Haechten printf("PHY 8530/31 MAC i/f Config Error: mac i/f = 0x%x\n",
366*a5fd13adSJohn Haechten phydev->interface);
367*a5fd13adSJohn Haechten return -EINVAL;
368*a5fd13adSJohn Haechten }
369*a5fd13adSJohn Haechten /* Default RMII Clk Output to 0=OFF/1=ON */
370*a5fd13adSJohn Haechten rmii_clk_out = 0;
371*a5fd13adSJohn Haechten
372*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
373*a5fd13adSJohn Haechten MSCC_PHY_PAGE_EXT2);
374*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
375*a5fd13adSJohn Haechten
376*a5fd13adSJohn Haechten /* Reg20E2 - Update RGMII RX_Clk Skews. */
377*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
378*a5fd13adSJohn Haechten RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
379*a5fd13adSJohn Haechten /* Reg20E2 - Update RGMII TX_Clk Skews. */
380*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
381*a5fd13adSJohn Haechten RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
382*a5fd13adSJohn Haechten
383*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
384*a5fd13adSJohn Haechten
385*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
386*a5fd13adSJohn Haechten /* Reg27E2 - Update Clk Slew Rate. */
387*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
388*a5fd13adSJohn Haechten EDGE_RATE_CNTL_WIDTH, edge_rate);
389*a5fd13adSJohn Haechten /* Reg27E2 - Update RMII Clk Out. */
390*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS,
391*a5fd13adSJohn Haechten RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out);
392*a5fd13adSJohn Haechten /* Update Reg27E2 */
393*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
394*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
395*a5fd13adSJohn Haechten MSCC_PHY_PAGE_STD);
396*a5fd13adSJohn Haechten
397*a5fd13adSJohn Haechten return genphy_config_aneg(phydev);
398*a5fd13adSJohn Haechten }
399*a5fd13adSJohn Haechten
vsc8541_config(struct phy_device * phydev)400*a5fd13adSJohn Haechten static int vsc8541_config(struct phy_device *phydev)
401*a5fd13adSJohn Haechten {
402*a5fd13adSJohn Haechten int retval = -EINVAL;
403*a5fd13adSJohn Haechten u16 reg_val;
404*a5fd13adSJohn Haechten u16 rmii_clk_out;
405*a5fd13adSJohn Haechten enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS;
406*a5fd13adSJohn Haechten enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS;
407*a5fd13adSJohn Haechten enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4;
408*a5fd13adSJohn Haechten
409*a5fd13adSJohn Haechten /* For VSC8530/31 and VSC8540/41 the init scripts are the same */
410*a5fd13adSJohn Haechten mscc_vsc8531_vsc8541_init_scripts(phydev);
411*a5fd13adSJohn Haechten
412*a5fd13adSJohn Haechten /* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */
413*a5fd13adSJohn Haechten switch (phydev->interface) {
414*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_MII:
415*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_GMII:
416*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_RMII:
417*a5fd13adSJohn Haechten case PHY_INTERFACE_MODE_RGMII:
418*a5fd13adSJohn Haechten retval = vsc8531_vsc8541_mac_config(phydev);
419*a5fd13adSJohn Haechten if (retval != 0)
420*a5fd13adSJohn Haechten return retval;
421*a5fd13adSJohn Haechten
422*a5fd13adSJohn Haechten retval = mscc_phy_soft_reset(phydev);
423*a5fd13adSJohn Haechten if (retval != 0)
424*a5fd13adSJohn Haechten return retval;
425*a5fd13adSJohn Haechten break;
426*a5fd13adSJohn Haechten default:
427*a5fd13adSJohn Haechten printf("PHY 8541 MAC i/f config Error: mac i/f = 0x%x\n",
428*a5fd13adSJohn Haechten phydev->interface);
429*a5fd13adSJohn Haechten return -EINVAL;
430*a5fd13adSJohn Haechten }
431*a5fd13adSJohn Haechten /* Default RMII Clk Output to 0=OFF/1=ON */
432*a5fd13adSJohn Haechten rmii_clk_out = 0;
433*a5fd13adSJohn Haechten
434*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
435*a5fd13adSJohn Haechten MSCC_PHY_PAGE_EXT2);
436*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG);
437*a5fd13adSJohn Haechten /* Reg20E2 - Update RGMII RX_Clk Skews. */
438*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS,
439*a5fd13adSJohn Haechten RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew);
440*a5fd13adSJohn Haechten /* Reg20E2 - Update RGMII TX_Clk Skews. */
441*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS,
442*a5fd13adSJohn Haechten RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew);
443*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val);
444*a5fd13adSJohn Haechten
445*a5fd13adSJohn Haechten reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL);
446*a5fd13adSJohn Haechten /* Reg27E2 - Update Clk Slew Rate. */
447*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS,
448*a5fd13adSJohn Haechten EDGE_RATE_CNTL_WIDTH, edge_rate);
449*a5fd13adSJohn Haechten /* Reg27E2 - Update RMII Clk Out. */
450*a5fd13adSJohn Haechten reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS,
451*a5fd13adSJohn Haechten RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out);
452*a5fd13adSJohn Haechten /* Update Reg27E2 */
453*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
454*a5fd13adSJohn Haechten phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS,
455*a5fd13adSJohn Haechten MSCC_PHY_PAGE_STD);
456*a5fd13adSJohn Haechten
457*a5fd13adSJohn Haechten return genphy_config_aneg(phydev);
458*a5fd13adSJohn Haechten }
459*a5fd13adSJohn Haechten
460*a5fd13adSJohn Haechten static struct phy_driver VSC8530_driver = {
461*a5fd13adSJohn Haechten .name = "Microsemi VSC8530",
462*a5fd13adSJohn Haechten .uid = PHY_ID_VSC8530,
463*a5fd13adSJohn Haechten .mask = 0x000ffff0,
464*a5fd13adSJohn Haechten .features = PHY_BASIC_FEATURES,
465*a5fd13adSJohn Haechten .config = &vsc8531_config,
466*a5fd13adSJohn Haechten .startup = &mscc_startup,
467*a5fd13adSJohn Haechten .shutdown = &genphy_shutdown,
468*a5fd13adSJohn Haechten };
469*a5fd13adSJohn Haechten
470*a5fd13adSJohn Haechten static struct phy_driver VSC8531_driver = {
471*a5fd13adSJohn Haechten .name = "Microsemi VSC8531",
472*a5fd13adSJohn Haechten .uid = PHY_ID_VSC8531,
473*a5fd13adSJohn Haechten .mask = 0x000ffff0,
474*a5fd13adSJohn Haechten .features = PHY_GBIT_FEATURES,
475*a5fd13adSJohn Haechten .config = &vsc8531_config,
476*a5fd13adSJohn Haechten .startup = &mscc_startup,
477*a5fd13adSJohn Haechten .shutdown = &genphy_shutdown,
478*a5fd13adSJohn Haechten };
479*a5fd13adSJohn Haechten
480*a5fd13adSJohn Haechten static struct phy_driver VSC8540_driver = {
481*a5fd13adSJohn Haechten .name = "Microsemi VSC8540",
482*a5fd13adSJohn Haechten .uid = PHY_ID_VSC8540,
483*a5fd13adSJohn Haechten .mask = 0x000ffff0,
484*a5fd13adSJohn Haechten .features = PHY_BASIC_FEATURES,
485*a5fd13adSJohn Haechten .config = &vsc8541_config,
486*a5fd13adSJohn Haechten .startup = &mscc_startup,
487*a5fd13adSJohn Haechten .shutdown = &genphy_shutdown,
488*a5fd13adSJohn Haechten };
489*a5fd13adSJohn Haechten
490*a5fd13adSJohn Haechten static struct phy_driver VSC8541_driver = {
491*a5fd13adSJohn Haechten .name = "Microsemi VSC8541",
492*a5fd13adSJohn Haechten .uid = PHY_ID_VSC8541,
493*a5fd13adSJohn Haechten .mask = 0x000ffff0,
494*a5fd13adSJohn Haechten .features = PHY_GBIT_FEATURES,
495*a5fd13adSJohn Haechten .config = &vsc8541_config,
496*a5fd13adSJohn Haechten .startup = &mscc_startup,
497*a5fd13adSJohn Haechten .shutdown = &genphy_shutdown,
498*a5fd13adSJohn Haechten };
499*a5fd13adSJohn Haechten
phy_mscc_init(void)500*a5fd13adSJohn Haechten int phy_mscc_init(void)
501*a5fd13adSJohn Haechten {
502*a5fd13adSJohn Haechten phy_register(&VSC8530_driver);
503*a5fd13adSJohn Haechten phy_register(&VSC8531_driver);
504*a5fd13adSJohn Haechten phy_register(&VSC8540_driver);
505*a5fd13adSJohn Haechten phy_register(&VSC8541_driver);
506*a5fd13adSJohn Haechten
507*a5fd13adSJohn Haechten return 0;
508*a5fd13adSJohn Haechten }
509