xref: /OK3568_Linux_fs/kernel/drivers/net/phy/swphy.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Software PHY emulation
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Code taken from fixed_phy.c by Russell King.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Vitaly Bordug <vbordug@ru.mvista.com>
8*4882a593Smuzhiyun  *         Anton Vorontsov <avorontsov@ru.mvista.com>
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Copyright (c) 2006-2007 MontaVista Software, Inc.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun #include <linux/export.h>
13*4882a593Smuzhiyun #include <linux/mii.h>
14*4882a593Smuzhiyun #include <linux/phy.h>
15*4882a593Smuzhiyun #include <linux/phy_fixed.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "swphy.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define MII_REGS_NUM 29
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun struct swmii_regs {
22*4882a593Smuzhiyun 	u16 bmsr;
23*4882a593Smuzhiyun 	u16 lpa;
24*4882a593Smuzhiyun 	u16 lpagb;
25*4882a593Smuzhiyun 	u16 estat;
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun enum {
29*4882a593Smuzhiyun 	SWMII_SPEED_10 = 0,
30*4882a593Smuzhiyun 	SWMII_SPEED_100,
31*4882a593Smuzhiyun 	SWMII_SPEED_1000,
32*4882a593Smuzhiyun 	SWMII_DUPLEX_HALF = 0,
33*4882a593Smuzhiyun 	SWMII_DUPLEX_FULL,
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /*
37*4882a593Smuzhiyun  * These two tables get bitwise-anded together to produce the final result.
38*4882a593Smuzhiyun  * This means the speed table must contain both duplex settings, and the
39*4882a593Smuzhiyun  * duplex table must contain all speed settings.
40*4882a593Smuzhiyun  */
41*4882a593Smuzhiyun static const struct swmii_regs speed[] = {
42*4882a593Smuzhiyun 	[SWMII_SPEED_10] = {
43*4882a593Smuzhiyun 		.lpa   = LPA_10FULL | LPA_10HALF,
44*4882a593Smuzhiyun 	},
45*4882a593Smuzhiyun 	[SWMII_SPEED_100] = {
46*4882a593Smuzhiyun 		.bmsr  = BMSR_100FULL | BMSR_100HALF,
47*4882a593Smuzhiyun 		.lpa   = LPA_100FULL | LPA_100HALF,
48*4882a593Smuzhiyun 	},
49*4882a593Smuzhiyun 	[SWMII_SPEED_1000] = {
50*4882a593Smuzhiyun 		.bmsr  = BMSR_ESTATEN,
51*4882a593Smuzhiyun 		.lpagb = LPA_1000FULL | LPA_1000HALF,
52*4882a593Smuzhiyun 		.estat = ESTATUS_1000_TFULL | ESTATUS_1000_THALF,
53*4882a593Smuzhiyun 	},
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun static const struct swmii_regs duplex[] = {
57*4882a593Smuzhiyun 	[SWMII_DUPLEX_HALF] = {
58*4882a593Smuzhiyun 		.bmsr  = BMSR_ESTATEN | BMSR_100HALF,
59*4882a593Smuzhiyun 		.lpa   = LPA_10HALF | LPA_100HALF,
60*4882a593Smuzhiyun 		.lpagb = LPA_1000HALF,
61*4882a593Smuzhiyun 		.estat = ESTATUS_1000_THALF,
62*4882a593Smuzhiyun 	},
63*4882a593Smuzhiyun 	[SWMII_DUPLEX_FULL] = {
64*4882a593Smuzhiyun 		.bmsr  = BMSR_ESTATEN | BMSR_100FULL,
65*4882a593Smuzhiyun 		.lpa   = LPA_10FULL | LPA_100FULL,
66*4882a593Smuzhiyun 		.lpagb = LPA_1000FULL,
67*4882a593Smuzhiyun 		.estat = ESTATUS_1000_TFULL,
68*4882a593Smuzhiyun 	},
69*4882a593Smuzhiyun };
70*4882a593Smuzhiyun 
swphy_decode_speed(int speed)71*4882a593Smuzhiyun static int swphy_decode_speed(int speed)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	switch (speed) {
74*4882a593Smuzhiyun 	case 1000:
75*4882a593Smuzhiyun 		return SWMII_SPEED_1000;
76*4882a593Smuzhiyun 	case 100:
77*4882a593Smuzhiyun 		return SWMII_SPEED_100;
78*4882a593Smuzhiyun 	case 10:
79*4882a593Smuzhiyun 		return SWMII_SPEED_10;
80*4882a593Smuzhiyun 	default:
81*4882a593Smuzhiyun 		return -EINVAL;
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /**
86*4882a593Smuzhiyun  * swphy_validate_state - validate the software phy status
87*4882a593Smuzhiyun  * @state: software phy status
88*4882a593Smuzhiyun  *
89*4882a593Smuzhiyun  * This checks that we can represent the state stored in @state can be
90*4882a593Smuzhiyun  * represented in the emulated MII registers.  Returns 0 if it can,
91*4882a593Smuzhiyun  * otherwise returns -EINVAL.
92*4882a593Smuzhiyun  */
swphy_validate_state(const struct fixed_phy_status * state)93*4882a593Smuzhiyun int swphy_validate_state(const struct fixed_phy_status *state)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	int err;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	if (state->link) {
98*4882a593Smuzhiyun 		err = swphy_decode_speed(state->speed);
99*4882a593Smuzhiyun 		if (err < 0) {
100*4882a593Smuzhiyun 			pr_warn("swphy: unknown speed\n");
101*4882a593Smuzhiyun 			return -EINVAL;
102*4882a593Smuzhiyun 		}
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 	return 0;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(swphy_validate_state);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /**
109*4882a593Smuzhiyun  * swphy_read_reg - return a MII register from the fixed phy state
110*4882a593Smuzhiyun  * @reg: MII register
111*4882a593Smuzhiyun  * @state: fixed phy status
112*4882a593Smuzhiyun  *
113*4882a593Smuzhiyun  * Return the MII @reg register generated from the fixed phy state @state.
114*4882a593Smuzhiyun  */
swphy_read_reg(int reg,const struct fixed_phy_status * state)115*4882a593Smuzhiyun int swphy_read_reg(int reg, const struct fixed_phy_status *state)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	int speed_index, duplex_index;
118*4882a593Smuzhiyun 	u16 bmsr = BMSR_ANEGCAPABLE;
119*4882a593Smuzhiyun 	u16 estat = 0;
120*4882a593Smuzhiyun 	u16 lpagb = 0;
121*4882a593Smuzhiyun 	u16 lpa = 0;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if (reg > MII_REGS_NUM)
124*4882a593Smuzhiyun 		return -1;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	speed_index = swphy_decode_speed(state->speed);
127*4882a593Smuzhiyun 	if (WARN_ON(speed_index < 0))
128*4882a593Smuzhiyun 		return 0;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr;
133*4882a593Smuzhiyun 	estat |= speed[speed_index].estat & duplex[duplex_index].estat;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (state->link) {
136*4882a593Smuzhiyun 		bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 		lpa   |= speed[speed_index].lpa   & duplex[duplex_index].lpa;
139*4882a593Smuzhiyun 		lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 		if (state->pause)
142*4882a593Smuzhiyun 			lpa |= LPA_PAUSE_CAP;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 		if (state->asym_pause)
145*4882a593Smuzhiyun 			lpa |= LPA_PAUSE_ASYM;
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	switch (reg) {
149*4882a593Smuzhiyun 	case MII_BMCR:
150*4882a593Smuzhiyun 		return BMCR_ANENABLE;
151*4882a593Smuzhiyun 	case MII_BMSR:
152*4882a593Smuzhiyun 		return bmsr;
153*4882a593Smuzhiyun 	case MII_PHYSID1:
154*4882a593Smuzhiyun 	case MII_PHYSID2:
155*4882a593Smuzhiyun 		return 0;
156*4882a593Smuzhiyun 	case MII_LPA:
157*4882a593Smuzhiyun 		return lpa;
158*4882a593Smuzhiyun 	case MII_STAT1000:
159*4882a593Smuzhiyun 		return lpagb;
160*4882a593Smuzhiyun 	case MII_ESTATUS:
161*4882a593Smuzhiyun 		return estat;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	/*
164*4882a593Smuzhiyun 	 * We do not support emulating Clause 45 over Clause 22 register
165*4882a593Smuzhiyun 	 * reads.  Return an error instead of bogus data.
166*4882a593Smuzhiyun 	 */
167*4882a593Smuzhiyun 	case MII_MMD_CTRL:
168*4882a593Smuzhiyun 	case MII_MMD_DATA:
169*4882a593Smuzhiyun 		return -1;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	default:
172*4882a593Smuzhiyun 		return 0xffff;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(swphy_read_reg);
176