... | ... | ||
---|---|---|---|
13 | one the firmware is loaded. | 13 | one the firmware is loaded. |
14 | 14 | ||
15 | In practice: | 15 | In practice: |
16 | - MMD 0x7 ID 0x7500 0x9410 -> FW LOAD -> ID 0x7500 0x9422 | 16 | - MMD 0x7 ID 0x7500 0x9410 -> FW LOAD -> ID 0x7500 0x9422 |
17 | 17 | ||
18 | To handle this, we apply a simple approach where the PHY | 18 | To handle this, we operate on .match_phy_device where |
19 | is registered a first time, with the PHY driver maching for | 19 | we check the PHY ID, if the ID match the generic one, |
20 | the generic PHY ID (0x7500 0x9410), probing and loading the fw. | 20 | we load the firmware and we return 0 (PHY driver doesn't |
21 | The PHY driver enable the new option "needs_reregister" in phy_device. | 21 | match). Then PHY core will try the next PHY driver in the list |
22 | and this time the PHY is correctly filled in and we register | ||
23 | for it. | ||
22 | 24 | ||
23 | This special option will detach the PHY driver from the PHY device, | 25 | To help in the matching and not modify part of the PHY device |
24 | scan the MDIO BUS for that address and attach it again. This is | 26 | struct, .match_phy_device is extended to provide also the |
25 | done entirely in one go at the phy_register_device time. | 27 | current phy_driver is trying to match for. This add the |
28 | extra benefits that some other PHY can simplify their | ||
29 | .match_phy_device OP. | ||
26 | 30 | ||
27 | At the second time the driver will match the more specific PHY ID | 31 | Changes v5: |
28 | (0x7500 0x9422) as the PHY now provides it now that is had the FW | 32 | - Add Reviewed-by tag from Rob |
29 | loaded. | 33 | - Fix subject in DT patch |
30 | 34 | - Fix wrong Suggested-by tag in patch 1 | |
31 | We can assume the PHY doesn't change Vendor or Family after | 35 | - Rework nxp patch to 80 column |
32 | the PHY is loaded (that wouldn't make sense) and in the extreme | 36 | Changes v4: |
33 | case this happen, no PHY will be matched and the generic one is | 37 | - Add Reviewed-by tag |
34 | loaded. | 38 | - Better handle PHY ID scan in as21xxx |
35 | 39 | - Also simplify nxp driver and fix .match_phy_device | |
40 | Changes v3: | ||
41 | - Correct typo intergate->integrate | ||
42 | - Try to reduce to 80 column (where possible... define become | ||
43 | unreasable if split) | ||
44 | - Rework to new .match_phy_device implementation | ||
45 | - Init active_low_led and fix other minor smatch war | ||
46 | - Drop inline tag (kbot doesn't like it but not reported by checkpatch???) | ||
36 | Changes v2: | 47 | Changes v2: |
37 | - Move to RFC as net-next closed :( | 48 | - Move to RFC as net-next closed :( |
38 | - Add lock for IPC command | 49 | - Add lock for IPC command |
39 | - Better check size values from IPC | 50 | - Better check size values from IPC |
40 | - Add PHY ID for all supported PHYs | 51 | - Add PHY ID for all supported PHYs |
... | ... | ||
45 | for generic PHY ID) | 56 | for generic PHY ID) |
46 | - Better document C22 in C45 | 57 | - Better document C22 in C45 |
47 | - Document PHY name logic | 58 | - Document PHY name logic |
48 | - Introduce patch to load PHY 2 times | 59 | - Introduce patch to load PHY 2 times |
49 | 60 | ||
50 | Christian Marangi (3): | 61 | Christian Marangi (6): |
51 | net: phy: permit PHYs to register a second time | 62 | net: phy: pass PHY driver to .match_phy_device OP |
63 | net: phy: bcm87xx: simplify .match_phy_device OP | ||
64 | net: phy: nxp-c45-tja11xx: simplify .match_phy_device OP | ||
65 | net: phy: introduce genphy_match_phy_device() | ||
52 | net: phy: Add support for Aeonsemi AS21xxx PHYs | 66 | net: phy: Add support for Aeonsemi AS21xxx PHYs |
53 | dt-bindings: net: Document support for Aeonsemi PHYs | 67 | dt-bindings: net: Document support for Aeonsemi PHYs |
54 | 68 | ||
55 | .../bindings/net/aeonsemi,as21xxx.yaml | 122 +++ | 69 | .../bindings/net/aeonsemi,as21xxx.yaml | 122 ++ |
56 | MAINTAINERS | 7 + | 70 | MAINTAINERS | 7 + |
57 | drivers/net/phy/Kconfig | 12 + | 71 | drivers/net/phy/Kconfig | 12 + |
58 | drivers/net/phy/Makefile | 1 + | 72 | drivers/net/phy/Makefile | 1 + |
59 | drivers/net/phy/as21xxx.c | 973 ++++++++++++++++++ | 73 | drivers/net/phy/as21xxx.c | 1067 +++++++++++++++++ |
60 | drivers/net/phy/phy_device.c | 27 + | 74 | drivers/net/phy/bcm87xx.c | 14 +- |
61 | include/linux/phy.h | 5 + | 75 | drivers/net/phy/icplus.c | 6 +- |
62 | 7 files changed, 1147 insertions(+) | 76 | drivers/net/phy/marvell10g.c | 12 +- |
77 | drivers/net/phy/micrel.c | 6 +- | ||
78 | drivers/net/phy/nxp-c45-tja11xx.c | 41 +- | ||
79 | drivers/net/phy/nxp-tja11xx.c | 6 +- | ||
80 | drivers/net/phy/phy_device.c | 52 +- | ||
81 | drivers/net/phy/realtek/realtek_main.c | 27 +- | ||
82 | drivers/net/phy/teranetics.c | 3 +- | ||
83 | include/linux/phy.h | 6 +- | ||
84 | 15 files changed, 1316 insertions(+), 66 deletions(-) | ||
63 | create mode 100644 Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml | 85 | create mode 100644 Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml |
64 | create mode 100644 drivers/net/phy/as21xxx.c | 86 | create mode 100644 drivers/net/phy/as21xxx.c |
65 | 87 | ||
66 | -- | 88 | -- |
67 | 2.48.1 | 89 | 2.48.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Pass PHY driver pointer to .match_phy_device OP in addition to phydev. | ||
2 | Having access to the PHY driver struct might be useful to check the | ||
3 | PHY ID of the driver is being matched for in case the PHY ID scanned in | ||
4 | the phydev is not consistent. | ||
1 | 5 | ||
6 | A scenario for this is a PHY that change PHY ID after a firmware is | ||
7 | loaded, in such case, the PHY ID stored in PHY device struct is not | ||
8 | valid anymore and PHY will manually scan the ID in the match_phy_device | ||
9 | function. | ||
10 | |||
11 | Having the PHY driver info is also useful for those PHY driver that | ||
12 | implement multiple simple .match_phy_device OP to match specific MMD PHY | ||
13 | ID. With this extra info if the parsing logic is the same, the matching | ||
14 | function can be generalized by using the phy_id in the PHY driver | ||
15 | instead of hardcoding. | ||
16 | |||
17 | Suggested-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | ||
18 | Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | ||
19 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | ||
20 | --- | ||
21 | drivers/net/phy/bcm87xx.c | 6 ++++-- | ||
22 | drivers/net/phy/icplus.c | 6 ++++-- | ||
23 | drivers/net/phy/marvell10g.c | 12 ++++++++---- | ||
24 | drivers/net/phy/micrel.c | 6 ++++-- | ||
25 | drivers/net/phy/nxp-c45-tja11xx.c | 12 ++++++++---- | ||
26 | drivers/net/phy/nxp-tja11xx.c | 6 ++++-- | ||
27 | drivers/net/phy/phy_device.c | 2 +- | ||
28 | drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++--------- | ||
29 | drivers/net/phy/teranetics.c | 3 ++- | ||
30 | include/linux/phy.h | 3 ++- | ||
31 | 10 files changed, 55 insertions(+), 28 deletions(-) | ||
32 | |||
33 | diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/drivers/net/phy/bcm87xx.c | ||
36 | +++ b/drivers/net/phy/bcm87xx.c | ||
37 | @@ -XXX,XX +XXX,XX @@ static irqreturn_t bcm87xx_handle_interrupt(struct phy_device *phydev) | ||
38 | return IRQ_HANDLED; | ||
39 | } | ||
40 | |||
41 | -static int bcm8706_match_phy_device(struct phy_device *phydev) | ||
42 | +static int bcm8706_match_phy_device(struct phy_device *phydev, | ||
43 | + const struct phy_driver *phydrv) | ||
44 | { | ||
45 | return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706; | ||
46 | } | ||
47 | |||
48 | -static int bcm8727_match_phy_device(struct phy_device *phydev) | ||
49 | +static int bcm8727_match_phy_device(struct phy_device *phydev, | ||
50 | + const struct phy_driver *phydrv) | ||
51 | { | ||
52 | return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8727; | ||
53 | } | ||
54 | diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c | ||
55 | index XXXXXXX..XXXXXXX 100644 | ||
56 | --- a/drivers/net/phy/icplus.c | ||
57 | +++ b/drivers/net/phy/icplus.c | ||
58 | @@ -XXX,XX +XXX,XX @@ static int ip101a_g_match_phy_device(struct phy_device *phydev, bool ip101a) | ||
59 | return ip101a == !ret; | ||
60 | } | ||
61 | |||
62 | -static int ip101a_match_phy_device(struct phy_device *phydev) | ||
63 | +static int ip101a_match_phy_device(struct phy_device *phydev, | ||
64 | + const struct phy_driver *phydrv) | ||
65 | { | ||
66 | return ip101a_g_match_phy_device(phydev, true); | ||
67 | } | ||
68 | |||
69 | -static int ip101g_match_phy_device(struct phy_device *phydev) | ||
70 | +static int ip101g_match_phy_device(struct phy_device *phydev, | ||
71 | + const struct phy_driver *phydrv) | ||
72 | { | ||
73 | return ip101a_g_match_phy_device(phydev, false); | ||
74 | } | ||
75 | diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/drivers/net/phy/marvell10g.c | ||
78 | +++ b/drivers/net/phy/marvell10g.c | ||
79 | @@ -XXX,XX +XXX,XX @@ static int mv3310_get_number_of_ports(struct phy_device *phydev) | ||
80 | return ret + 1; | ||
81 | } | ||
82 | |||
83 | -static int mv3310_match_phy_device(struct phy_device *phydev) | ||
84 | +static int mv3310_match_phy_device(struct phy_device *phydev, | ||
85 | + const struct phy_driver *phydrv) | ||
86 | { | ||
87 | if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] & | ||
88 | MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310) | ||
89 | @@ -XXX,XX +XXX,XX @@ static int mv3310_match_phy_device(struct phy_device *phydev) | ||
90 | return mv3310_get_number_of_ports(phydev) == 1; | ||
91 | } | ||
92 | |||
93 | -static int mv3340_match_phy_device(struct phy_device *phydev) | ||
94 | +static int mv3340_match_phy_device(struct phy_device *phydev, | ||
95 | + const struct phy_driver *phydrv) | ||
96 | { | ||
97 | if ((phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] & | ||
98 | MARVELL_PHY_ID_MASK) != MARVELL_PHY_ID_88X3310) | ||
99 | @@ -XXX,XX +XXX,XX @@ static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g) | ||
100 | return !!(val & MDIO_PCS_SPEED_5G) == has_5g; | ||
101 | } | ||
102 | |||
103 | -static int mv2110_match_phy_device(struct phy_device *phydev) | ||
104 | +static int mv2110_match_phy_device(struct phy_device *phydev, | ||
105 | + const struct phy_driver *phydrv) | ||
106 | { | ||
107 | return mv211x_match_phy_device(phydev, true); | ||
108 | } | ||
109 | |||
110 | -static int mv2111_match_phy_device(struct phy_device *phydev) | ||
111 | +static int mv2111_match_phy_device(struct phy_device *phydev, | ||
112 | + const struct phy_driver *phydrv) | ||
113 | { | ||
114 | return mv211x_match_phy_device(phydev, false); | ||
115 | } | ||
116 | diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c | ||
117 | index XXXXXXX..XXXXXXX 100644 | ||
118 | --- a/drivers/net/phy/micrel.c | ||
119 | +++ b/drivers/net/phy/micrel.c | ||
120 | @@ -XXX,XX +XXX,XX @@ static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev, | ||
121 | return !ret; | ||
122 | } | ||
123 | |||
124 | -static int ksz8051_match_phy_device(struct phy_device *phydev) | ||
125 | +static int ksz8051_match_phy_device(struct phy_device *phydev, | ||
126 | + const struct phy_driver *phydrv) | ||
127 | { | ||
128 | return ksz8051_ksz8795_match_phy_device(phydev, true); | ||
129 | } | ||
130 | @@ -XXX,XX +XXX,XX @@ static int ksz8061_config_init(struct phy_device *phydev) | ||
131 | return kszphy_config_init(phydev); | ||
132 | } | ||
133 | |||
134 | -static int ksz8795_match_phy_device(struct phy_device *phydev) | ||
135 | +static int ksz8795_match_phy_device(struct phy_device *phydev, | ||
136 | + const struct phy_driver *phydrv) | ||
137 | { | ||
138 | return ksz8051_ksz8795_match_phy_device(phydev, false); | ||
139 | } | ||
140 | diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c | ||
141 | index XXXXXXX..XXXXXXX 100644 | ||
142 | --- a/drivers/net/phy/nxp-c45-tja11xx.c | ||
143 | +++ b/drivers/net/phy/nxp-c45-tja11xx.c | ||
144 | @@ -XXX,XX +XXX,XX @@ static int nxp_c45_macsec_ability(struct phy_device *phydev) | ||
145 | return macsec_ability; | ||
146 | } | ||
147 | |||
148 | -static int tja1103_match_phy_device(struct phy_device *phydev) | ||
149 | +static int tja1103_match_phy_device(struct phy_device *phydev, | ||
150 | + const struct phy_driver *phydrv) | ||
151 | { | ||
152 | return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) && | ||
153 | !nxp_c45_macsec_ability(phydev); | ||
154 | } | ||
155 | |||
156 | -static int tja1104_match_phy_device(struct phy_device *phydev) | ||
157 | +static int tja1104_match_phy_device(struct phy_device *phydev, | ||
158 | + const struct phy_driver *phydrv) | ||
159 | { | ||
160 | return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) && | ||
161 | nxp_c45_macsec_ability(phydev); | ||
162 | } | ||
163 | |||
164 | -static int tja1120_match_phy_device(struct phy_device *phydev) | ||
165 | +static int tja1120_match_phy_device(struct phy_device *phydev, | ||
166 | + const struct phy_driver *phydrv) | ||
167 | { | ||
168 | return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, PHY_ID_MASK) && | ||
169 | !nxp_c45_macsec_ability(phydev); | ||
170 | } | ||
171 | |||
172 | -static int tja1121_match_phy_device(struct phy_device *phydev) | ||
173 | +static int tja1121_match_phy_device(struct phy_device *phydev, | ||
174 | + const struct phy_driver *phydrv) | ||
175 | { | ||
176 | return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, PHY_ID_MASK) && | ||
177 | nxp_c45_macsec_ability(phydev); | ||
178 | diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c | ||
179 | index XXXXXXX..XXXXXXX 100644 | ||
180 | --- a/drivers/net/phy/nxp-tja11xx.c | ||
181 | +++ b/drivers/net/phy/nxp-tja11xx.c | ||
182 | @@ -XXX,XX +XXX,XX @@ static int tja1102_match_phy_device(struct phy_device *phydev, bool port0) | ||
183 | return !ret; | ||
184 | } | ||
185 | |||
186 | -static int tja1102_p0_match_phy_device(struct phy_device *phydev) | ||
187 | +static int tja1102_p0_match_phy_device(struct phy_device *phydev, | ||
188 | + const struct phy_driver *phydrv) | ||
189 | { | ||
190 | return tja1102_match_phy_device(phydev, true); | ||
191 | } | ||
192 | |||
193 | -static int tja1102_p1_match_phy_device(struct phy_device *phydev) | ||
194 | +static int tja1102_p1_match_phy_device(struct phy_device *phydev, | ||
195 | + const struct phy_driver *phydrv) | ||
196 | { | ||
197 | return tja1102_match_phy_device(phydev, false); | ||
198 | } | ||
199 | diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c | ||
200 | index XXXXXXX..XXXXXXX 100644 | ||
201 | --- a/drivers/net/phy/phy_device.c | ||
202 | +++ b/drivers/net/phy/phy_device.c | ||
203 | @@ -XXX,XX +XXX,XX @@ static int phy_bus_match(struct device *dev, const struct device_driver *drv) | ||
204 | return 0; | ||
205 | |||
206 | if (phydrv->match_phy_device) | ||
207 | - return phydrv->match_phy_device(phydev); | ||
208 | + return phydrv->match_phy_device(phydev, phydrv); | ||
209 | |||
210 | if (phydev->is_c45) { | ||
211 | for (i = 1; i < num_ids; i++) { | ||
212 | diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c | ||
213 | index XXXXXXX..XXXXXXX 100644 | ||
214 | --- a/drivers/net/phy/realtek/realtek_main.c | ||
215 | +++ b/drivers/net/phy/realtek/realtek_main.c | ||
216 | @@ -XXX,XX +XXX,XX @@ static bool rtlgen_supports_mmd(struct phy_device *phydev) | ||
217 | return val > 0; | ||
218 | } | ||
219 | |||
220 | -static int rtlgen_match_phy_device(struct phy_device *phydev) | ||
221 | +static int rtlgen_match_phy_device(struct phy_device *phydev, | ||
222 | + const struct phy_driver *phydrv) | ||
223 | { | ||
224 | return phydev->phy_id == RTL_GENERIC_PHYID && | ||
225 | !rtlgen_supports_2_5gbps(phydev); | ||
226 | } | ||
227 | |||
228 | -static int rtl8226_match_phy_device(struct phy_device *phydev) | ||
229 | +static int rtl8226_match_phy_device(struct phy_device *phydev, | ||
230 | + const struct phy_driver *phydrv) | ||
231 | { | ||
232 | return phydev->phy_id == RTL_GENERIC_PHYID && | ||
233 | rtlgen_supports_2_5gbps(phydev) && | ||
234 | @@ -XXX,XX +XXX,XX @@ static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, | ||
235 | return !is_c45 && (id == phydev->phy_id); | ||
236 | } | ||
237 | |||
238 | -static int rtl8221b_match_phy_device(struct phy_device *phydev) | ||
239 | +static int rtl8221b_match_phy_device(struct phy_device *phydev, | ||
240 | + const struct phy_driver *phydrv) | ||
241 | { | ||
242 | return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); | ||
243 | } | ||
244 | |||
245 | -static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) | ||
246 | +static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev, | ||
247 | + const struct phy_driver *phydrv) | ||
248 | { | ||
249 | return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); | ||
250 | } | ||
251 | |||
252 | -static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev) | ||
253 | +static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev, | ||
254 | + const struct phy_driver *phydrv) | ||
255 | { | ||
256 | return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true); | ||
257 | } | ||
258 | |||
259 | -static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev) | ||
260 | +static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev, | ||
261 | + const struct phy_driver *phydrv) | ||
262 | { | ||
263 | return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false); | ||
264 | } | ||
265 | |||
266 | -static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) | ||
267 | +static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev, | ||
268 | + const struct phy_driver *phydrv) | ||
269 | { | ||
270 | return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); | ||
271 | } | ||
272 | |||
273 | -static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) | ||
274 | +static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev, | ||
275 | + const struct phy_driver *phydrv) | ||
276 | { | ||
277 | if (phydev->is_c45) | ||
278 | return false; | ||
279 | @@ -XXX,XX +XXX,XX @@ static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) | ||
280 | return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); | ||
281 | } | ||
282 | |||
283 | -static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) | ||
284 | +static int rtl8251b_c45_match_phy_device(struct phy_device *phydev, | ||
285 | + const struct phy_driver *phydrv) | ||
286 | { | ||
287 | return rtlgen_is_c45_match(phydev, RTL_8251B, true); | ||
288 | } | ||
289 | diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c | ||
290 | index XXXXXXX..XXXXXXX 100644 | ||
291 | --- a/drivers/net/phy/teranetics.c | ||
292 | +++ b/drivers/net/phy/teranetics.c | ||
293 | @@ -XXX,XX +XXX,XX @@ static int teranetics_read_status(struct phy_device *phydev) | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | -static int teranetics_match_phy_device(struct phy_device *phydev) | ||
298 | +static int teranetics_match_phy_device(struct phy_device *phydev, | ||
299 | + const struct phy_driver *phydrv) | ||
300 | { | ||
301 | return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020; | ||
302 | } | ||
303 | diff --git a/include/linux/phy.h b/include/linux/phy.h | ||
304 | index XXXXXXX..XXXXXXX 100644 | ||
305 | --- a/include/linux/phy.h | ||
306 | +++ b/include/linux/phy.h | ||
307 | @@ -XXX,XX +XXX,XX @@ struct phy_driver { | ||
308 | * driver for the given phydev. If NULL, matching is based on | ||
309 | * phy_id and phy_id_mask. | ||
310 | */ | ||
311 | - int (*match_phy_device)(struct phy_device *phydev); | ||
312 | + int (*match_phy_device)(struct phy_device *phydev, | ||
313 | + const struct phy_driver *phydrv); | ||
314 | |||
315 | /** | ||
316 | * @set_wol: Some devices (e.g. qnap TS-119P II) require PHY | ||
317 | -- | ||
318 | 2.48.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Simplify .match_phy_device OP by using a generic function and using the | ||
2 | new phy_id PHY driver info instead of hardcoding the matching PHY ID. | ||
1 | 3 | ||
4 | Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | ||
5 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | ||
6 | --- | ||
7 | drivers/net/phy/bcm87xx.c | 14 ++++---------- | ||
8 | 1 file changed, 4 insertions(+), 10 deletions(-) | ||
9 | |||
10 | diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/drivers/net/phy/bcm87xx.c | ||
13 | +++ b/drivers/net/phy/bcm87xx.c | ||
14 | @@ -XXX,XX +XXX,XX @@ static irqreturn_t bcm87xx_handle_interrupt(struct phy_device *phydev) | ||
15 | return IRQ_HANDLED; | ||
16 | } | ||
17 | |||
18 | -static int bcm8706_match_phy_device(struct phy_device *phydev, | ||
19 | +static int bcm87xx_match_phy_device(struct phy_device *phydev, | ||
20 | const struct phy_driver *phydrv) | ||
21 | { | ||
22 | - return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8706; | ||
23 | -} | ||
24 | - | ||
25 | -static int bcm8727_match_phy_device(struct phy_device *phydev, | ||
26 | - const struct phy_driver *phydrv) | ||
27 | -{ | ||
28 | - return phydev->c45_ids.device_ids[4] == PHY_ID_BCM8727; | ||
29 | + return phydev->c45_ids.device_ids[4] == phydrv->phy_id; | ||
30 | } | ||
31 | |||
32 | static struct phy_driver bcm87xx_driver[] = { | ||
33 | @@ -XXX,XX +XXX,XX @@ static struct phy_driver bcm87xx_driver[] = { | ||
34 | .read_status = bcm87xx_read_status, | ||
35 | .config_intr = bcm87xx_config_intr, | ||
36 | .handle_interrupt = bcm87xx_handle_interrupt, | ||
37 | - .match_phy_device = bcm8706_match_phy_device, | ||
38 | + .match_phy_device = bcm87xx_match_phy_device, | ||
39 | }, { | ||
40 | .phy_id = PHY_ID_BCM8727, | ||
41 | .phy_id_mask = 0xffffffff, | ||
42 | @@ -XXX,XX +XXX,XX @@ static struct phy_driver bcm87xx_driver[] = { | ||
43 | .read_status = bcm87xx_read_status, | ||
44 | .config_intr = bcm87xx_config_intr, | ||
45 | .handle_interrupt = bcm87xx_handle_interrupt, | ||
46 | - .match_phy_device = bcm8727_match_phy_device, | ||
47 | + .match_phy_device = bcm87xx_match_phy_device, | ||
48 | } }; | ||
49 | |||
50 | module_phy_driver(bcm87xx_driver); | ||
51 | -- | ||
52 | 2.48.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Simplify .match_phy_device OP by using a generic function and using the | ||
2 | new phy_id PHY driver info instead of hardcoding the matching PHY ID | ||
3 | with new variant for macsec and no_macsec PHYs. | ||
1 | 4 | ||
5 | Also make use of PHY_ID_MATCH_MODEL macro and drop PHY_ID_MASK define to | ||
6 | introduce phy_id and phy_id_mask again in phy_driver struct. | ||
7 | |||
8 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | ||
9 | --- | ||
10 | drivers/net/phy/nxp-c45-tja11xx.c | 45 ++++++++++++++----------------- | ||
11 | 1 file changed, 20 insertions(+), 25 deletions(-) | ||
12 | |||
13 | diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/drivers/net/phy/nxp-c45-tja11xx.c | ||
16 | +++ b/drivers/net/phy/nxp-c45-tja11xx.c | ||
17 | @@ -XXX,XX +XXX,XX @@ | ||
18 | |||
19 | #include "nxp-c45-tja11xx.h" | ||
20 | |||
21 | -#define PHY_ID_MASK GENMASK(31, 4) | ||
22 | /* Same id: TJA1103, TJA1104 */ | ||
23 | #define PHY_ID_TJA_1103 0x001BB010 | ||
24 | /* Same id: TJA1120, TJA1121 */ | ||
25 | @@ -XXX,XX +XXX,XX @@ static int nxp_c45_macsec_ability(struct phy_device *phydev) | ||
26 | return macsec_ability; | ||
27 | } | ||
28 | |||
29 | -static int tja1103_match_phy_device(struct phy_device *phydev, | ||
30 | - const struct phy_driver *phydrv) | ||
31 | +static int tja11xx_no_macsec_match_phy_device(struct phy_device *phydev, | ||
32 | + const struct phy_driver *phydrv) | ||
33 | { | ||
34 | - return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) && | ||
35 | - !nxp_c45_macsec_ability(phydev); | ||
36 | -} | ||
37 | + if (!phy_id_compare(phydev->phy_id, phydrv->phy_id, | ||
38 | + phydrv->phy_id_mask)) | ||
39 | + return 0; | ||
40 | |||
41 | -static int tja1104_match_phy_device(struct phy_device *phydev, | ||
42 | - const struct phy_driver *phydrv) | ||
43 | -{ | ||
44 | - return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1103, PHY_ID_MASK) && | ||
45 | - nxp_c45_macsec_ability(phydev); | ||
46 | + return !nxp_c45_macsec_ability(phydev); | ||
47 | } | ||
48 | |||
49 | -static int tja1120_match_phy_device(struct phy_device *phydev, | ||
50 | - const struct phy_driver *phydrv) | ||
51 | +static int tja11xx_macsec_match_phy_device(struct phy_device *phydev, | ||
52 | + const struct phy_driver *phydrv) | ||
53 | { | ||
54 | - return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, PHY_ID_MASK) && | ||
55 | - !nxp_c45_macsec_ability(phydev); | ||
56 | -} | ||
57 | + if (!phy_id_compare(phydev->phy_id, phydrv->phy_id, | ||
58 | + phydrv->phy_id_mask)) | ||
59 | + return 0; | ||
60 | |||
61 | -static int tja1121_match_phy_device(struct phy_device *phydev, | ||
62 | - const struct phy_driver *phydrv) | ||
63 | -{ | ||
64 | - return phy_id_compare(phydev->phy_id, PHY_ID_TJA_1120, PHY_ID_MASK) && | ||
65 | - nxp_c45_macsec_ability(phydev); | ||
66 | + return nxp_c45_macsec_ability(phydev); | ||
67 | } | ||
68 | |||
69 | static const struct nxp_c45_regmap tja1120_regmap = { | ||
70 | @@ -XXX,XX +XXX,XX @@ static const struct nxp_c45_phy_data tja1120_phy_data = { | ||
71 | |||
72 | static struct phy_driver nxp_c45_driver[] = { | ||
73 | { | ||
74 | + PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103), | ||
75 | .name = "NXP C45 TJA1103", | ||
76 | .get_features = nxp_c45_get_features, | ||
77 | .driver_data = &tja1103_phy_data, | ||
78 | @@ -XXX,XX +XXX,XX @@ static struct phy_driver nxp_c45_driver[] = { | ||
79 | .get_sqi = nxp_c45_get_sqi, | ||
80 | .get_sqi_max = nxp_c45_get_sqi_max, | ||
81 | .remove = nxp_c45_remove, | ||
82 | - .match_phy_device = tja1103_match_phy_device, | ||
83 | + .match_phy_device = tja11xx_no_macsec_match_phy_device, | ||
84 | }, | ||
85 | { | ||
86 | + PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103), | ||
87 | .name = "NXP C45 TJA1104", | ||
88 | .get_features = nxp_c45_get_features, | ||
89 | .driver_data = &tja1103_phy_data, | ||
90 | @@ -XXX,XX +XXX,XX @@ static struct phy_driver nxp_c45_driver[] = { | ||
91 | .get_sqi = nxp_c45_get_sqi, | ||
92 | .get_sqi_max = nxp_c45_get_sqi_max, | ||
93 | .remove = nxp_c45_remove, | ||
94 | - .match_phy_device = tja1104_match_phy_device, | ||
95 | + .match_phy_device = tja11xx_macsec_match_phy_device, | ||
96 | }, | ||
97 | { | ||
98 | + PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120), | ||
99 | .name = "NXP C45 TJA1120", | ||
100 | .get_features = nxp_c45_get_features, | ||
101 | .driver_data = &tja1120_phy_data, | ||
102 | @@ -XXX,XX +XXX,XX @@ static struct phy_driver nxp_c45_driver[] = { | ||
103 | .get_sqi = nxp_c45_get_sqi, | ||
104 | .get_sqi_max = nxp_c45_get_sqi_max, | ||
105 | .remove = nxp_c45_remove, | ||
106 | - .match_phy_device = tja1120_match_phy_device, | ||
107 | + .match_phy_device = tja11xx_no_macsec_match_phy_device, | ||
108 | }, | ||
109 | { | ||
110 | + PHY_ID_MATCH_MODEL(PHY_ID_TJA_1120), | ||
111 | .name = "NXP C45 TJA1121", | ||
112 | .get_features = nxp_c45_get_features, | ||
113 | .driver_data = &tja1120_phy_data, | ||
114 | @@ -XXX,XX +XXX,XX @@ static struct phy_driver nxp_c45_driver[] = { | ||
115 | .get_sqi = nxp_c45_get_sqi, | ||
116 | .get_sqi_max = nxp_c45_get_sqi_max, | ||
117 | .remove = nxp_c45_remove, | ||
118 | - .match_phy_device = tja1121_match_phy_device, | ||
119 | + .match_phy_device = tja11xx_macsec_match_phy_device, | ||
120 | }, | ||
121 | }; | ||
122 | |||
123 | -- | ||
124 | 2.48.1 | diff view generated by jsdifflib |
1 | Some PHY might needs to register AGAIN after a firmware is loaded to | 1 | Introduce new API, genphy_match_phy_device(), to provide a way to check |
---|---|---|---|
2 | correctly provide the real PHY ID. | 2 | to match a PHY driver for a PHY device based on the info stored in the |
3 | PHY device struct. | ||
3 | 4 | ||
4 | It was found that some PHY expose on the BUS with a PHY ID that change | 5 | The function generalize the logic used in phy_bus_match() to check the |
5 | as soon as the PHY firmware is loaded and started. | 6 | PHY ID whether if C45 or C22 ID should be used for matching. |
6 | 7 | ||
7 | To better handle this case and provide to the system correct info on | 8 | This is useful for custom .match_phy_device function that wants to use |
8 | what PHY is actually present on the BUS, introduce a new option for PHY | 9 | the generic logic under some condition. (example a PHY is already setup |
9 | device, needs_reregister, that register the PHY device 2 times. | 10 | and provide the correct PHY ID) |
10 | |||
11 | With needs_reregister enabled, in phy_device_register() the PHY is first | ||
12 | registered with the driver detected for the PHY ID. The PHY driver is | ||
13 | then released and the PHY ID for the PHY address is rescanned. | ||
14 | The phy_id and c45_ids entry are updated for the PHY device and finally | ||
15 | the PHY is registered again with the more specific PHY driver. (matching | ||
16 | the new PHY ID) | ||
17 | |||
18 | It's assumed that loading the firmware doesn't cause the PHY ID to change | ||
19 | to different vendor or PHY of different family (provided by different | ||
20 | drivers) | ||
21 | 11 | ||
22 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | 12 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> |
23 | --- | 13 | --- |
24 | drivers/net/phy/phy_device.c | 27 +++++++++++++++++++++++++++ | 14 | drivers/net/phy/phy_device.c | 52 +++++++++++++++++++++++++----------- |
25 | include/linux/phy.h | 5 +++++ | 15 | include/linux/phy.h | 3 +++ |
26 | 2 files changed, 32 insertions(+) | 16 | 2 files changed, 40 insertions(+), 15 deletions(-) |
27 | 17 | ||
28 | diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c | 18 | diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c |
29 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
30 | --- a/drivers/net/phy/phy_device.c | 20 | --- a/drivers/net/phy/phy_device.c |
31 | +++ b/drivers/net/phy/phy_device.c | 21 | +++ b/drivers/net/phy/phy_device.c |
32 | @@ -XXX,XX +XXX,XX @@ int phy_device_register(struct phy_device *phydev) | 22 | @@ -XXX,XX +XXX,XX @@ static int phy_scan_fixups(struct phy_device *phydev) |
33 | goto out; | 23 | return 0; |
24 | } | ||
25 | |||
26 | -static int phy_bus_match(struct device *dev, const struct device_driver *drv) | ||
27 | +/** | ||
28 | + * genphy_match_phy_device - match a PHY device with a PHY driver | ||
29 | + * @phydev: target phy_device struct | ||
30 | + * @phydrv: target phy_driver struct | ||
31 | + * | ||
32 | + * Description: Checks whether the given PHY device matches the specified | ||
33 | + * PHY driver. For Clause 45 PHYs, iterates over the available device | ||
34 | + * identifiers and compares them against the driver's expected PHY ID, | ||
35 | + * applying the provided mask. For Clause 22 PHYs, a direct ID comparison | ||
36 | + * is performed. | ||
37 | + * | ||
38 | + * Return: 1 if the PHY device matches the driver, 0 otherwise. | ||
39 | + */ | ||
40 | +int genphy_match_phy_device(struct phy_device *phydev, | ||
41 | + const struct phy_driver *phydrv) | ||
42 | { | ||
43 | - struct phy_device *phydev = to_phy_device(dev); | ||
44 | - const struct phy_driver *phydrv = to_phy_driver(drv); | ||
45 | - const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids); | ||
46 | - int i; | ||
47 | - | ||
48 | - if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)) | ||
49 | - return 0; | ||
50 | - | ||
51 | - if (phydrv->match_phy_device) | ||
52 | - return phydrv->match_phy_device(phydev, phydrv); | ||
53 | - | ||
54 | if (phydev->is_c45) { | ||
55 | + const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids); | ||
56 | + int i; | ||
57 | + | ||
58 | for (i = 1; i < num_ids; i++) { | ||
59 | if (phydev->c45_ids.device_ids[i] == 0xffffffff) | ||
60 | continue; | ||
61 | @@ -XXX,XX +XXX,XX @@ static int phy_bus_match(struct device *dev, const struct device_driver *drv) | ||
62 | phydrv->phy_id, phydrv->phy_id_mask)) | ||
63 | return 1; | ||
64 | } | ||
65 | + | ||
66 | return 0; | ||
67 | - } else { | ||
68 | - return phy_id_compare(phydev->phy_id, phydrv->phy_id, | ||
69 | - phydrv->phy_id_mask); | ||
34 | } | 70 | } |
35 | |||
36 | + /* Some PHY might needs to register AGAIN after a firmware | ||
37 | + * is loaded to correctly provide the real PHY ID. | ||
38 | + * For PHY that needs this, release the PHY driver, rescan | ||
39 | + * the MDIO bus for the PHY address and attach a driver | ||
40 | + * again. | ||
41 | + * This second time, the real PHY is provided and the | ||
42 | + * more specific PHY driver OPs are used. | ||
43 | + */ | ||
44 | + if (phydev->needs_reregister) { | ||
45 | + device_release_driver(&phydev->mdio.dev); | ||
46 | + | 71 | + |
47 | + if (phydev->is_c45) | 72 | + return phy_id_compare(phydev->phy_id, phydrv->phy_id, |
48 | + get_phy_c45_ids(phydev->mdio.bus, | 73 | + phydrv->phy_id_mask); |
49 | + phydev->mdio.addr, | 74 | +} |
50 | + &phydev->c45_ids); | 75 | +EXPORT_SYMBOL_GPL(genphy_match_phy_device); |
51 | + else | ||
52 | + get_phy_c22_id(phydev->mdio.bus, | ||
53 | + phydev->mdio.addr, | ||
54 | + &phydev->phy_id); | ||
55 | + | 76 | + |
56 | + err = device_attach(&phydev->mdio.dev); | 77 | +static int phy_bus_match(struct device *dev, const struct device_driver *drv) |
57 | + if (err <= 0) { | 78 | +{ |
58 | + phydev_err(phydev, "failed to reattach\n"); | 79 | + struct phy_device *phydev = to_phy_device(dev); |
59 | + goto out; | 80 | + const struct phy_driver *phydrv = to_phy_driver(drv); |
60 | + } | ||
61 | + } | ||
62 | + | 81 | + |
63 | return 0; | 82 | + if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)) |
64 | 83 | + return 0; | |
65 | out: | 84 | + |
85 | + if (phydrv->match_phy_device) | ||
86 | + return phydrv->match_phy_device(phydev, phydrv); | ||
87 | + | ||
88 | + return genphy_match_phy_device(phydev, phydrv); | ||
89 | } | ||
90 | |||
91 | static ssize_t | ||
66 | diff --git a/include/linux/phy.h b/include/linux/phy.h | 92 | diff --git a/include/linux/phy.h b/include/linux/phy.h |
67 | index XXXXXXX..XXXXXXX 100644 | 93 | index XXXXXXX..XXXXXXX 100644 |
68 | --- a/include/linux/phy.h | 94 | --- a/include/linux/phy.h |
69 | +++ b/include/linux/phy.h | 95 | +++ b/include/linux/phy.h |
70 | @@ -XXX,XX +XXX,XX @@ struct macsec_ops; | 96 | @@ -XXX,XX +XXX,XX @@ char *phy_attached_info_irq(struct phy_device *phydev) |
71 | * @mac_managed_pm: Set true if MAC driver takes of suspending/resuming PHY | 97 | __malloc; |
72 | * @wol_enabled: Set to true if the PHY or the attached MAC have Wake-on-LAN | 98 | void phy_attached_info(struct phy_device *phydev); |
73 | * enabled. | 99 | |
74 | + * @needs_reregister: Set to true if the PHY needs to register AGAIN after | 100 | +int genphy_match_phy_device(struct phy_device *phydev, |
75 | + * first registration. This is to handle special case where the | 101 | + const struct phy_driver *phydrv); |
76 | + * PHY needs to load a firmware to correctly communicate the | 102 | + |
77 | + * specific PHY ID. | 103 | /* Clause 22 PHY */ |
78 | * @state: State of the PHY for management purposes | 104 | int genphy_read_abilities(struct phy_device *phydev); |
79 | * @dev_flags: Device-specific flags used by the PHY driver. | 105 | int genphy_setup_forced(struct phy_device *phydev); |
80 | * | ||
81 | @@ -XXX,XX +XXX,XX @@ struct phy_device { | ||
82 | unsigned is_on_sfp_module:1; | ||
83 | unsigned mac_managed_pm:1; | ||
84 | unsigned wol_enabled:1; | ||
85 | + unsigned needs_reregister; | ||
86 | |||
87 | unsigned autoneg:1; | ||
88 | /* The most recently read link state */ | ||
89 | -- | 106 | -- |
90 | 2.48.1 | 107 | 2.48.1 | diff view generated by jsdifflib |
1 | Add support for Aeonsemi AS21xxx 10G C45 PHYs. These PHYs intergate | 1 | Add support for Aeonsemi AS21xxx 10G C45 PHYs. These PHYs integrate |
---|---|---|---|
2 | an IPC to setup some configuration and require special handling to | 2 | an IPC to setup some configuration and require special handling to |
3 | sync with the parity bit. The parity bit is a way the IPC use to | 3 | sync with the parity bit. The parity bit is a way the IPC use to |
4 | follow correct order of command sent. | 4 | follow correct order of command sent. |
5 | 5 | ||
6 | Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1, | 6 | Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1, |
... | ... | ||
25 | 5: 5G, 2.5G | 25 | 5: 5G, 2.5G |
26 | 2: 2.5G | 26 | 2: 2.5G |
27 | 27 | ||
28 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | 28 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> |
29 | --- | 29 | --- |
30 | MAINTAINERS | 6 + | 30 | MAINTAINERS | 6 + |
31 | drivers/net/phy/Kconfig | 12 + | 31 | drivers/net/phy/Kconfig | 12 + |
32 | drivers/net/phy/Makefile | 1 + | 32 | drivers/net/phy/Makefile | 1 + |
33 | drivers/net/phy/as21xxx.c | 973 ++++++++++++++++++++++++++++++++++++++ | 33 | drivers/net/phy/as21xxx.c | 1067 +++++++++++++++++++++++++++++++++++++ |
34 | 4 files changed, 992 insertions(+) | 34 | 4 files changed, 1086 insertions(+) |
35 | create mode 100644 drivers/net/phy/as21xxx.c | 35 | create mode 100644 drivers/net/phy/as21xxx.c |
36 | 36 | ||
37 | diff --git a/MAINTAINERS b/MAINTAINERS | 37 | diff --git a/MAINTAINERS b/MAINTAINERS |
38 | index XXXXXXX..XXXXXXX 100644 | 38 | index XXXXXXX..XXXXXXX 100644 |
39 | --- a/MAINTAINERS | 39 | --- a/MAINTAINERS |
... | ... | ||
385 | + BIT(TRIGGER_NETDEV_RX), | 385 | + BIT(TRIGGER_NETDEV_RX), |
386 | + .val = VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT | 386 | + .val = VEND1_LED_REG_A_EVENT_ON_NG_BLINK_ACT |
387 | + } | 387 | + } |
388 | +}; | 388 | +}; |
389 | + | 389 | + |
390 | +static int aeon_firmware_boot(struct phy_device *phydev, const u8 *data, size_t size) | 390 | +static int aeon_firmware_boot(struct phy_device *phydev, const u8 *data, |
391 | + size_t size) | ||
391 | +{ | 392 | +{ |
392 | + int i, ret; | 393 | + int i, ret; |
393 | + u16 val; | 394 | + u16 val; |
394 | + | 395 | + |
395 | + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL, | 396 | + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL, |
... | ... | ||
400 | + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_FW_START_ADDR, | 401 | + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_FW_START_ADDR, |
401 | + AEON_BOOT_ADDR); | 402 | + AEON_BOOT_ADDR); |
402 | + if (ret) | 403 | + if (ret) |
403 | + return ret; | 404 | + return ret; |
404 | + | 405 | + |
405 | + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD, | 406 | + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, |
407 | + VEND1_GLB_REG_MDIO_INDIRECT_ADDRCMD, | ||
406 | + 0x3ffc, 0xc000); | 408 | + 0x3ffc, 0xc000); |
407 | + if (ret) | 409 | + if (ret) |
408 | + return ret; | 410 | + return ret; |
409 | + | 411 | + |
410 | + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_MDIO_INDIRECT_STATUS); | 412 | + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, |
413 | + VEND1_GLB_REG_MDIO_INDIRECT_STATUS); | ||
411 | + if (val > 1) { | 414 | + if (val > 1) { |
412 | + phydev_err(phydev, "wrong origin mdio_indirect_status: %x\n", val); | 415 | + phydev_err(phydev, "wrong origin mdio_indirect_status: %x\n", val); |
413 | + return -EINVAL; | 416 | + return -EINVAL; |
414 | + } | 417 | + } |
415 | + | 418 | + |
416 | + /* Firmware is always aligned to u16 */ | 419 | + /* Firmware is always aligned to u16 */ |
417 | + for (i = 0; i < size; i += 2) { | 420 | + for (i = 0; i < size; i += 2) { |
418 | + val = data[i + 1] << 8 | data[i]; | 421 | + val = data[i + 1] << 8 | data[i]; |
419 | + | 422 | + |
420 | + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_MDIO_INDIRECT_LOAD, val); | 423 | + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, |
424 | + VEND1_GLB_REG_MDIO_INDIRECT_LOAD, val); | ||
421 | + if (ret) | 425 | + if (ret) |
422 | + return ret; | 426 | + return ret; |
423 | + } | 427 | + } |
424 | + | 428 | + |
425 | + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR, | 429 | + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, |
430 | + VEND1_GLB_REG_CPU_RESET_ADDR_LO_BASEADDR, | ||
426 | + lower_16_bits(AEON_CPU_BOOT_ADDR)); | 431 | + lower_16_bits(AEON_CPU_BOOT_ADDR)); |
427 | + if (ret) | 432 | + if (ret) |
428 | + return ret; | 433 | + return ret; |
429 | + | 434 | + |
430 | + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR, | 435 | + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, |
436 | + VEND1_GLB_REG_CPU_RESET_ADDR_HI_BASEADDR, | ||
431 | + upper_16_bits(AEON_CPU_BOOT_ADDR)); | 437 | + upper_16_bits(AEON_CPU_BOOT_ADDR)); |
432 | + if (ret) | 438 | + if (ret) |
433 | + return ret; | 439 | + return ret; |
434 | + | 440 | + |
435 | + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL, | 441 | + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLB_REG_CPU_CTRL, |
... | ... | ||
460 | + release_firmware(fw); | 466 | + release_firmware(fw); |
461 | + | 467 | + |
462 | + return ret; | 468 | + return ret; |
463 | +} | 469 | +} |
464 | + | 470 | + |
465 | +static inline int aeon_ipcs_wait_cmd(struct phy_device *phydev, bool parity_status) | 471 | +static int aeon_ipcs_wait_cmd(struct phy_device *phydev, bool parity_status) |
466 | +{ | 472 | +{ |
467 | + u16 val; | 473 | + u16 val; |
468 | + | 474 | + |
469 | + /* Exit condition logic: | 475 | + /* Exit condition logic: |
470 | + * - Wait for parity bit equal | 476 | + * - Wait for parity bit equal |
... | ... | ||
476 | + (val & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_PROCESS && | 482 | + (val & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_PROCESS && |
477 | + (val & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_BUSY, | 483 | + (val & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_BUSY, |
478 | + AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false); | 484 | + AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false); |
479 | +} | 485 | +} |
480 | + | 486 | + |
481 | +static int aeon_ipc_send_cmd(struct phy_device *phydev, u32 cmd, | 487 | +static int aeon_ipc_send_cmd(struct phy_device *phydev, |
482 | + u16 *ret_sts) | 488 | + struct as21xxx_priv *priv, |
483 | +{ | 489 | + u16 cmd, u16 *ret_sts) |
484 | + struct as21xxx_priv *priv = phydev->priv; | 490 | +{ |
485 | + bool curr_parity; | 491 | + bool curr_parity; |
486 | + int ret; | 492 | + int ret; |
487 | + | 493 | + |
488 | + /* The IPC sync by using a single parity bit. | 494 | + /* The IPC sync by using a single parity bit. |
489 | + * Each CMD have alternately this bit set or clear | 495 | + * Each CMD have alternately this bit set or clear |
... | ... | ||
517 | + if (ret < 0) | 523 | + if (ret < 0) |
518 | + return ret; | 524 | + return ret; |
519 | + | 525 | + |
520 | + *ret_sts = ret; | 526 | + *ret_sts = ret; |
521 | + if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS) | 527 | + if ((*ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_SUCCESS) |
522 | + return -EFAULT; | 528 | + return -EINVAL; |
523 | + | 529 | + |
524 | + return 0; | 530 | + return 0; |
525 | +} | 531 | +} |
526 | + | 532 | + |
527 | +static int aeon_ipc_send_msg(struct phy_device *phydev, u16 opcode, | 533 | +static int aeon_ipc_send_msg(struct phy_device *phydev, |
528 | + u16 *data, unsigned int data_len, u16 *ret_sts) | 534 | + u16 opcode, u16 *data, unsigned int data_len, |
535 | + u16 *ret_sts) | ||
529 | +{ | 536 | +{ |
530 | + struct as21xxx_priv *priv = phydev->priv; | 537 | + struct as21xxx_priv *priv = phydev->priv; |
531 | + u32 cmd; | 538 | + u16 cmd; |
532 | + int ret; | 539 | + int ret; |
533 | + int i; | 540 | + int i; |
534 | + | 541 | + |
535 | + /* IPC have a max of 8 register to transfer data, | 542 | + /* IPC have a max of 8 register to transfer data, |
536 | + * make sure we never exceed this. | 543 | + * make sure we never exceed this. |
... | ... | ||
544 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i), | 551 | + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_IPC_DATA(i), |
545 | + data[i]); | 552 | + data[i]); |
546 | + | 553 | + |
547 | + cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) | | 554 | + cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, data_len) | |
548 | + FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode); | 555 | + FIELD_PREP(AEON_IPC_CMD_OPCODE, opcode); |
549 | + ret = aeon_ipc_send_cmd(phydev, cmd, ret_sts); | 556 | + ret = aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts); |
550 | + if (ret) | 557 | + if (ret) |
551 | + phydev_err(phydev, "failed to send ipc msg for %x: %d\n", opcode, ret); | 558 | + phydev_err(phydev, "failed to send ipc msg for %x: %d\n", |
559 | + opcode, ret); | ||
552 | + | 560 | + |
553 | + mutex_unlock(&priv->ipc_lock); | 561 | + mutex_unlock(&priv->ipc_lock); |
554 | + | 562 | + |
555 | + return ret; | 563 | + return ret; |
556 | +} | 564 | +} |
557 | + | 565 | + |
558 | +static int aeon_ipc_rcv_msg(struct phy_device *phydev, u16 ret_sts, | 566 | +static int aeon_ipc_rcv_msg(struct phy_device *phydev, |
559 | + u16 *data) | 567 | + u16 ret_sts, u16 *data) |
560 | +{ | 568 | +{ |
561 | + unsigned int size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts); | ||
562 | + struct as21xxx_priv *priv = phydev->priv; | 569 | + struct as21xxx_priv *priv = phydev->priv; |
570 | + unsigned int size; | ||
563 | + int ret; | 571 | + int ret; |
564 | + int i; | 572 | + int i; |
565 | + | 573 | + |
566 | + if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR) | 574 | + if ((ret_sts & AEON_IPC_STS_STATUS) == AEON_IPC_STS_STATUS_ERROR) |
567 | + return -EINVAL; | 575 | + return -EINVAL; |
568 | + | 576 | + |
569 | + /* Prevent IPC from stack smashing the kernel */ | 577 | + /* Prevent IPC from stack smashing the kernel */ |
578 | + size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts); | ||
570 | + if (size > AEON_IPC_DATA_MAX) | 579 | + if (size > AEON_IPC_DATA_MAX) |
571 | + return -EINVAL; | 580 | + return -EINVAL; |
572 | + | 581 | + |
573 | + mutex_lock(&priv->ipc_lock); | 582 | + mutex_lock(&priv->ipc_lock); |
574 | + | 583 | + |
... | ... | ||
586 | + mutex_unlock(&priv->ipc_lock); | 595 | + mutex_unlock(&priv->ipc_lock); |
587 | + | 596 | + |
588 | + return size; | 597 | + return size; |
589 | +} | 598 | +} |
590 | + | 599 | + |
600 | +static int aeon_ipc_noop(struct phy_device *phydev, | ||
601 | + struct as21xxx_priv *priv, u16 *ret_sts) | ||
602 | +{ | ||
603 | + u16 cmd; | ||
604 | + | ||
605 | + cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) | | ||
606 | + FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP); | ||
607 | + | ||
608 | + return aeon_ipc_send_cmd(phydev, priv, cmd, ret_sts); | ||
609 | +} | ||
610 | + | ||
591 | +/* Logic to sync parity bit with IPC. | 611 | +/* Logic to sync parity bit with IPC. |
592 | + * We send 2 NOP cmd with same partity and we wait for IPC | 612 | + * We send 2 NOP cmd with same partity and we wait for IPC |
593 | + * to handle the packet only for the second one. This way | 613 | + * to handle the packet only for the second one. This way |
594 | + * we make sure we are sync for every next cmd. | 614 | + * we make sure we are sync for every next cmd. |
595 | + */ | 615 | + */ |
596 | +static int aeon_ipc_sync_parity(struct phy_device *phydev) | 616 | +static int aeon_ipc_sync_parity(struct phy_device *phydev, |
597 | +{ | 617 | + struct as21xxx_priv *priv) |
598 | + struct as21xxx_priv *priv = phydev->priv; | 618 | +{ |
599 | + u16 ret_sts; | 619 | + u16 ret_sts; |
600 | + u32 cmd; | ||
601 | + int ret; | 620 | + int ret; |
602 | + | 621 | + |
603 | + mutex_lock(&priv->ipc_lock); | 622 | + mutex_lock(&priv->ipc_lock); |
604 | + | 623 | + |
605 | + /* Send NOP with no parity */ | 624 | + /* Send NOP with no parity */ |
606 | + cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) | | 625 | + aeon_ipc_noop(phydev, priv, NULL); |
607 | + FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP); | ||
608 | + aeon_ipc_send_cmd(phydev, cmd, NULL); | ||
609 | + | 626 | + |
610 | + /* Reset packet parity */ | 627 | + /* Reset packet parity */ |
611 | + priv->parity_status = false; | 628 | + priv->parity_status = false; |
612 | + | 629 | + |
613 | + /* Send second NOP with no parity */ | 630 | + /* Send second NOP with no parity */ |
614 | + ret = aeon_ipc_send_cmd(phydev, cmd, &ret_sts); | 631 | + ret = aeon_ipc_noop(phydev, priv, &ret_sts); |
615 | + | 632 | + |
616 | + mutex_unlock(&priv->ipc_lock); | 633 | + mutex_unlock(&priv->ipc_lock); |
617 | + | 634 | + |
618 | + /* We expect to return -EFAULT */ | 635 | + /* We expect to return -EINVAL */ |
619 | + if (ret != -EFAULT) | 636 | + if (ret != -EINVAL) |
620 | + return ret; | 637 | + return ret; |
621 | + | 638 | + |
622 | + if ((ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_READY) | 639 | + if ((ret_sts & AEON_IPC_STS_STATUS) != AEON_IPC_STS_STATUS_READY) { |
640 | + phydev_err(phydev, "Invalid IPC status on sync parity: %x\n", | ||
641 | + ret_sts); | ||
623 | + return -EINVAL; | 642 | + return -EINVAL; |
643 | + } | ||
624 | + | 644 | + |
625 | + return 0; | 645 | + return 0; |
626 | +} | 646 | +} |
627 | + | 647 | + |
628 | +static int aeon_ipc_get_fw_version(struct phy_device *phydev) | 648 | +static int aeon_ipc_get_fw_version(struct phy_device *phydev) |
629 | +{ | 649 | +{ |
630 | + u16 ret_data[8], data[1]; | 650 | + u16 ret_data[8], data[1]; |
631 | + u16 ret_sts; | 651 | + u16 ret_sts; |
632 | + int ret; | 652 | + int ret; |
633 | + | 653 | + |
634 | + data[0] = IPC_INFO_VERSION; | 654 | + data[0] = IPC_INFO_VERSION; |
635 | + ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data, sizeof(data), | 655 | + ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data, |
636 | + &ret_sts); | 656 | + sizeof(data), &ret_sts); |
637 | + if (ret) | 657 | + if (ret) |
638 | + return ret; | 658 | + return ret; |
639 | + | 659 | + |
640 | + ret = aeon_ipc_rcv_msg(phydev, ret_sts, ret_data); | 660 | + ret = aeon_ipc_rcv_msg(phydev, ret_sts, ret_data); |
641 | + if (ret < 0) | 661 | + if (ret < 0) |
... | ... | ||
672 | + ret = devm_mutex_init(&phydev->mdio.dev, | 692 | + ret = devm_mutex_init(&phydev->mdio.dev, |
673 | + &priv->ipc_lock); | 693 | + &priv->ipc_lock); |
674 | + if (ret) | 694 | + if (ret) |
675 | + return ret; | 695 | + return ret; |
676 | + | 696 | + |
677 | + ret = aeon_firmware_load(phydev); | 697 | + ret = aeon_ipc_sync_parity(phydev, priv); |
678 | + if (ret) | 698 | + if (ret) |
679 | + return ret; | 699 | + return ret; |
680 | + | 700 | + |
681 | + ret = aeon_ipc_sync_parity(phydev); | 701 | + ret = aeon_ipc_get_fw_version(phydev); |
682 | + if (ret) | 702 | + if (ret) |
683 | + return ret; | 703 | + return ret; |
684 | + | 704 | + |
705 | + /* Enable PTP clk if not already Enabled */ | ||
685 | + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK, | 706 | + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK, |
686 | + VEND1_PTP_CLK_EN); | 707 | + VEND1_PTP_CLK_EN); |
687 | + if (ret) | 708 | + if (ret) |
688 | + return ret; | 709 | + return ret; |
689 | + | 710 | + |
690 | + ret = aeon_dpc_ra_enable(phydev); | 711 | + return aeon_dpc_ra_enable(phydev); |
691 | + if (ret) | ||
692 | + return ret; | ||
693 | + | ||
694 | + ret = aeon_ipc_get_fw_version(phydev); | ||
695 | + if (ret) | ||
696 | + return ret; | ||
697 | + | ||
698 | + phydev->needs_reregister = true; | ||
699 | + | ||
700 | + return 0; | ||
701 | +} | 712 | +} |
702 | + | 713 | + |
703 | +static int as21xxx_read_link(struct phy_device *phydev, int *bmcr) | 714 | +static int as21xxx_read_link(struct phy_device *phydev, int *bmcr) |
704 | +{ | 715 | +{ |
705 | + int status; | 716 | + int status; |
... | ... | ||
868 | +} | 879 | +} |
869 | + | 880 | + |
870 | +static int as21xxx_led_hw_control_get(struct phy_device *phydev, u8 index, | 881 | +static int as21xxx_led_hw_control_get(struct phy_device *phydev, u8 index, |
871 | + unsigned long *rules) | 882 | + unsigned long *rules) |
872 | +{ | 883 | +{ |
873 | + u16 val; | 884 | + int i, val; |
874 | + int i; | ||
875 | + | 885 | + |
876 | + if (index > AEON_MAX_LDES) | 886 | + if (index > AEON_MAX_LDES) |
877 | + return -EINVAL; | 887 | + return -EINVAL; |
878 | + | 888 | + |
879 | + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_LED_REG(index)); | 889 | + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_LED_REG(index)); |
... | ... | ||
913 | +} | 923 | +} |
914 | + | 924 | + |
915 | +static int as21xxx_led_polarity_set(struct phy_device *phydev, int index, | 925 | +static int as21xxx_led_polarity_set(struct phy_device *phydev, int index, |
916 | + unsigned long modes) | 926 | + unsigned long modes) |
917 | +{ | 927 | +{ |
918 | + bool led_active_low; | 928 | + bool led_active_low = false; |
919 | + u16 mask, val = 0; | 929 | + u16 mask, val = 0; |
920 | + u32 mode; | 930 | + u32 mode; |
921 | + | 931 | + |
922 | + if (index > AEON_MAX_LDES) | 932 | + if (index > AEON_MAX_LDES) |
923 | + return -EINVAL; | 933 | + return -EINVAL; |
... | ... | ||
942 | + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, | 952 | + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, |
943 | + VEND1_GLB_REG_CPU_CTRL, | 953 | + VEND1_GLB_REG_CPU_CTRL, |
944 | + mask, val); | 954 | + mask, val); |
945 | +} | 955 | +} |
946 | + | 956 | + |
957 | +static int as21xxx_match_phy_device(struct phy_device *phydev, | ||
958 | + const struct phy_driver *phydrv) | ||
959 | +{ | ||
960 | + struct as21xxx_priv *priv; | ||
961 | + u16 ret_sts; | ||
962 | + u32 phy_id; | ||
963 | + int ret; | ||
964 | + | ||
965 | + /* Skip PHY that are not AS21xxx or already have firmware loaded */ | ||
966 | + if (phydev->c45_ids.device_ids[MDIO_MMD_PCS] != PHY_ID_AS21XXX) | ||
967 | + return genphy_match_phy_device(phydev, phydrv); | ||
968 | + | ||
969 | + /* Read PHY ID to handle firmware just loaded */ | ||
970 | + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1); | ||
971 | + if (ret < 0) | ||
972 | + return ret; | ||
973 | + phy_id = ret << 16; | ||
974 | + | ||
975 | + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID2); | ||
976 | + if (ret < 0) | ||
977 | + return ret; | ||
978 | + phy_id |= ret; | ||
979 | + | ||
980 | + /* With PHY ID not the generic AS21xxx one assume | ||
981 | + * the firmware just loaded | ||
982 | + */ | ||
983 | + if (phy_id != PHY_ID_AS21XXX) | ||
984 | + return phy_id == phydrv->phy_id; | ||
985 | + | ||
986 | + /* Allocate temp priv and load the firmware */ | ||
987 | + priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
988 | + if (!priv) | ||
989 | + return -ENOMEM; | ||
990 | + | ||
991 | + mutex_init(&priv->ipc_lock); | ||
992 | + | ||
993 | + ret = aeon_firmware_load(phydev); | ||
994 | + if (ret) | ||
995 | + goto out; | ||
996 | + | ||
997 | + /* Sync parity... */ | ||
998 | + ret = aeon_ipc_sync_parity(phydev, priv); | ||
999 | + if (ret) | ||
1000 | + goto out; | ||
1001 | + | ||
1002 | + /* ...and send a third NOOP cmd to wait for firmware finish loading */ | ||
1003 | + ret = aeon_ipc_noop(phydev, priv, &ret_sts); | ||
1004 | + if (ret) | ||
1005 | + goto out; | ||
1006 | + | ||
1007 | +out: | ||
1008 | + mutex_destroy(&priv->ipc_lock); | ||
1009 | + kfree(priv); | ||
1010 | + | ||
1011 | + /* Return not maching anyway as PHY ID will change after | ||
1012 | + * firmware is loaded. This relies on the driver probe | ||
1013 | + * order where the first PHY driver probed is the | ||
1014 | + * generic one. | ||
1015 | + */ | ||
1016 | + return ret; | ||
1017 | +} | ||
1018 | + | ||
947 | +static struct phy_driver as21xxx_drivers[] = { | 1019 | +static struct phy_driver as21xxx_drivers[] = { |
948 | + { | 1020 | + { |
949 | + /* PHY expose in C45 as 0x7500 0x9410 | 1021 | + /* PHY expose in C45 as 0x7500 0x9410 |
950 | + * before firmware is loaded. | 1022 | + * before firmware is loaded. |
1023 | + * This driver entry must be attempted first to load | ||
1024 | + * the firmware and thus update the ID registers. | ||
951 | + */ | 1025 | + */ |
952 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX), | 1026 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX), |
953 | + .name = "Aeonsemi AS21xxx", | 1027 | + .name = "Aeonsemi AS21xxx", |
954 | + .probe = as21xxx_probe, | 1028 | + .match_phy_device = as21xxx_match_phy_device, |
955 | + }, | 1029 | + }, |
956 | + { | 1030 | + { |
957 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21011JB1), | 1031 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21011JB1), |
958 | + .name = "Aeonsemi AS21011JB1", | 1032 | + .name = "Aeonsemi AS21011JB1", |
1033 | + .probe = as21xxx_probe, | ||
1034 | + .match_phy_device = as21xxx_match_phy_device, | ||
959 | + .read_status = as21xxx_read_status, | 1035 | + .read_status = as21xxx_read_status, |
960 | + .led_brightness_set = as21xxx_led_brightness_set, | 1036 | + .led_brightness_set = as21xxx_led_brightness_set, |
961 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1037 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
962 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1038 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
963 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1039 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
964 | + .led_polarity_set = as21xxx_led_polarity_set, | 1040 | + .led_polarity_set = as21xxx_led_polarity_set, |
965 | + }, | 1041 | + }, |
966 | + { | 1042 | + { |
967 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1), | 1043 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1), |
968 | + .name = "Aeonsemi AS21011PB1", | 1044 | + .name = "Aeonsemi AS21011PB1", |
1045 | + .probe = as21xxx_probe, | ||
1046 | + .match_phy_device = as21xxx_match_phy_device, | ||
969 | + .read_status = as21xxx_read_status, | 1047 | + .read_status = as21xxx_read_status, |
970 | + .led_brightness_set = as21xxx_led_brightness_set, | 1048 | + .led_brightness_set = as21xxx_led_brightness_set, |
971 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1049 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
972 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1050 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
973 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1051 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
974 | + .led_polarity_set = as21xxx_led_polarity_set, | 1052 | + .led_polarity_set = as21xxx_led_polarity_set, |
975 | + }, | 1053 | + }, |
976 | + { | 1054 | + { |
977 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1), | 1055 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1), |
978 | + .name = "Aeonsemi AS21010PB1", | 1056 | + .name = "Aeonsemi AS21010PB1", |
1057 | + .probe = as21xxx_probe, | ||
1058 | + .match_phy_device = as21xxx_match_phy_device, | ||
979 | + .read_status = as21xxx_read_status, | 1059 | + .read_status = as21xxx_read_status, |
980 | + .led_brightness_set = as21xxx_led_brightness_set, | 1060 | + .led_brightness_set = as21xxx_led_brightness_set, |
981 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1061 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
982 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1062 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
983 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1063 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
984 | + .led_polarity_set = as21xxx_led_polarity_set, | 1064 | + .led_polarity_set = as21xxx_led_polarity_set, |
985 | + }, | 1065 | + }, |
986 | + { | 1066 | + { |
987 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1), | 1067 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1), |
988 | + .name = "Aeonsemi AS21010JB1", | 1068 | + .name = "Aeonsemi AS21010JB1", |
1069 | + .probe = as21xxx_probe, | ||
1070 | + .match_phy_device = as21xxx_match_phy_device, | ||
989 | + .read_status = as21xxx_read_status, | 1071 | + .read_status = as21xxx_read_status, |
990 | + .led_brightness_set = as21xxx_led_brightness_set, | 1072 | + .led_brightness_set = as21xxx_led_brightness_set, |
991 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1073 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
992 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1074 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
993 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1075 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
994 | + .led_polarity_set = as21xxx_led_polarity_set, | 1076 | + .led_polarity_set = as21xxx_led_polarity_set, |
995 | + }, | 1077 | + }, |
996 | + { | 1078 | + { |
997 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1), | 1079 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1), |
998 | + .name = "Aeonsemi AS21210PB1", | 1080 | + .name = "Aeonsemi AS21210PB1", |
1081 | + .probe = as21xxx_probe, | ||
1082 | + .match_phy_device = as21xxx_match_phy_device, | ||
999 | + .read_status = as21xxx_read_status, | 1083 | + .read_status = as21xxx_read_status, |
1000 | + .led_brightness_set = as21xxx_led_brightness_set, | 1084 | + .led_brightness_set = as21xxx_led_brightness_set, |
1001 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1085 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
1002 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1086 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
1003 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1087 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
1004 | + .led_polarity_set = as21xxx_led_polarity_set, | 1088 | + .led_polarity_set = as21xxx_led_polarity_set, |
1005 | + }, | 1089 | + }, |
1006 | + { | 1090 | + { |
1007 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1), | 1091 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1), |
1008 | + .name = "Aeonsemi AS21510JB1", | 1092 | + .name = "Aeonsemi AS21510JB1", |
1093 | + .probe = as21xxx_probe, | ||
1094 | + .match_phy_device = as21xxx_match_phy_device, | ||
1009 | + .read_status = as21xxx_read_status, | 1095 | + .read_status = as21xxx_read_status, |
1010 | + .led_brightness_set = as21xxx_led_brightness_set, | 1096 | + .led_brightness_set = as21xxx_led_brightness_set, |
1011 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1097 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
1012 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1098 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
1013 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1099 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
1014 | + .led_polarity_set = as21xxx_led_polarity_set, | 1100 | + .led_polarity_set = as21xxx_led_polarity_set, |
1015 | + }, | 1101 | + }, |
1016 | + { | 1102 | + { |
1017 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1), | 1103 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1), |
1018 | + .name = "Aeonsemi AS21510PB1", | 1104 | + .name = "Aeonsemi AS21510PB1", |
1105 | + .probe = as21xxx_probe, | ||
1106 | + .match_phy_device = as21xxx_match_phy_device, | ||
1019 | + .read_status = as21xxx_read_status, | 1107 | + .read_status = as21xxx_read_status, |
1020 | + .led_brightness_set = as21xxx_led_brightness_set, | 1108 | + .led_brightness_set = as21xxx_led_brightness_set, |
1021 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1109 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
1022 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1110 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
1023 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1111 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
1024 | + .led_polarity_set = as21xxx_led_polarity_set, | 1112 | + .led_polarity_set = as21xxx_led_polarity_set, |
1025 | + }, | 1113 | + }, |
1026 | + { | 1114 | + { |
1027 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1), | 1115 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1), |
1028 | + .name = "Aeonsemi AS21511JB1", | 1116 | + .name = "Aeonsemi AS21511JB1", |
1117 | + .probe = as21xxx_probe, | ||
1118 | + .match_phy_device = as21xxx_match_phy_device, | ||
1029 | + .read_status = as21xxx_read_status, | 1119 | + .read_status = as21xxx_read_status, |
1030 | + .led_brightness_set = as21xxx_led_brightness_set, | 1120 | + .led_brightness_set = as21xxx_led_brightness_set, |
1031 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1121 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
1032 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1122 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
1033 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1123 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
1034 | + .led_polarity_set = as21xxx_led_polarity_set, | 1124 | + .led_polarity_set = as21xxx_led_polarity_set, |
1035 | + }, | 1125 | + }, |
1036 | + { | 1126 | + { |
1037 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1), | 1127 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1), |
1038 | + .name = "Aeonsemi AS21210JB1", | 1128 | + .name = "Aeonsemi AS21210JB1", |
1129 | + .probe = as21xxx_probe, | ||
1130 | + .match_phy_device = as21xxx_match_phy_device, | ||
1039 | + .read_status = as21xxx_read_status, | 1131 | + .read_status = as21xxx_read_status, |
1040 | + .led_brightness_set = as21xxx_led_brightness_set, | 1132 | + .led_brightness_set = as21xxx_led_brightness_set, |
1041 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1133 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
1042 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1134 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
1043 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1135 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
1044 | + .led_polarity_set = as21xxx_led_polarity_set, | 1136 | + .led_polarity_set = as21xxx_led_polarity_set, |
1045 | + }, | 1137 | + }, |
1046 | + { | 1138 | + { |
1047 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1), | 1139 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1), |
1048 | + .name = "Aeonsemi AS21511PB1", | 1140 | + .name = "Aeonsemi AS21511PB1", |
1141 | + .probe = as21xxx_probe, | ||
1142 | + .match_phy_device = as21xxx_match_phy_device, | ||
1049 | + .read_status = as21xxx_read_status, | 1143 | + .read_status = as21xxx_read_status, |
1050 | + .led_brightness_set = as21xxx_led_brightness_set, | 1144 | + .led_brightness_set = as21xxx_led_brightness_set, |
1051 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, | 1145 | + .led_hw_is_supported = as21xxx_led_hw_is_supported, |
1052 | + .led_hw_control_set = as21xxx_led_hw_control_set, | 1146 | + .led_hw_control_set = as21xxx_led_hw_control_set, |
1053 | + .led_hw_control_get = as21xxx_led_hw_control_get, | 1147 | + .led_hw_control_get = as21xxx_led_hw_control_get, |
... | ... | diff view generated by jsdifflib |
1 | Document support for Aeonsemi PHYs and the requirement of a firmware to | 1 | Add Aeonsemi PHYs and the requirement of a firmware to correctly work. |
---|---|---|---|
2 | correctly work. Also document the max number of LEDs supported and what | 2 | Also document the max number of LEDs supported and what PHY ID expose |
3 | PHY ID expose when no firmware is loaded. | 3 | when no firmware is loaded. |
4 | 4 | ||
5 | Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1, | 5 | Supported PHYs AS21011JB1, AS21011PB1, AS21010JB1, AS21010PB1, |
6 | AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1, | 6 | AS21511JB1, AS21511PB1, AS21510JB1, AS21510PB1, AS21210JB1, |
7 | AS21210PB1 that all register with the PHY ID 0x7500 0x9410 on C45 | 7 | AS21210PB1 that all register with the PHY ID 0x7500 0x9410 on C45 |
8 | registers before the firmware is loaded. | 8 | registers before the firmware is loaded. |
9 | 9 | ||
10 | Reviewed-by: Rob Herring (Arm) <robh@kernel.org> | ||
10 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | 11 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> |
11 | --- | 12 | --- |
12 | .../bindings/net/aeonsemi,as21xxx.yaml | 122 ++++++++++++++++++ | 13 | .../bindings/net/aeonsemi,as21xxx.yaml | 122 ++++++++++++++++++ |
13 | MAINTAINERS | 1 + | 14 | MAINTAINERS | 1 + |
14 | 2 files changed, 123 insertions(+) | 15 | 2 files changed, 123 insertions(+) |
... | ... | diff view generated by jsdifflib |