1219974Smav/* SPDX-License-Identifier: GPL-2.0-only */
2219974Smav/*
3219974Smav * linux/mdio.h: definitions for MDIO (clause 45) transceivers
4219974Smav * Copyright 2006-2009 Solarflare Communications Inc.
5219974Smav */
6219974Smav#ifndef __LINUX_MDIO_H__
7219974Smav#define __LINUX_MDIO_H__
8219974Smav
9219974Smav#include <uapi/linux/mdio.h>
10219974Smav#include <linux/bitfield.h>
11219974Smav#include <linux/mod_devicetable.h>
12219974Smav
13219974Smavstruct gpio_desc;
14219974Smavstruct mii_bus;
15219974Smavstruct reset_control;
16219974Smav
17219974Smav/* Multiple levels of nesting are possible. However typically this is
18219974Smav * limited to nested DSA like layer, a MUX layer, and the normal
19219974Smav * user. Instead of trying to handle the general case, just define
20219974Smav * these cases.
21219974Smav */
22219974Smavenum mdio_mutex_lock_class {
23219974Smav	MDIO_MUTEX_NORMAL,
24219974Smav	MDIO_MUTEX_MUX,
25219974Smav	MDIO_MUTEX_NESTED,
26219974Smav};
27219974Smav
28219974Smavstruct mdio_device {
29219974Smav	struct device dev;
30219974Smav
31219974Smav	struct mii_bus *bus;
32219974Smav	char modalias[MDIO_NAME_SIZE];
33219974Smav
34219974Smav	int (*bus_match)(struct device *dev, struct device_driver *drv);
35219974Smav	void (*device_free)(struct mdio_device *mdiodev);
36219974Smav	void (*device_remove)(struct mdio_device *mdiodev);
37219974Smav
38223921Sae	/* Bus address of the MDIO device (0-31) */
39219974Smav	int addr;
40219974Smav	int flags;
41219974Smav	int reset_state;
42219974Smav	struct gpio_desc *reset_gpio;
43219974Smav	struct reset_control *reset_ctrl;
44219974Smav	unsigned int reset_assert_delay;
45219974Smav	unsigned int reset_deassert_delay;
46219974Smav};
47219974Smav
48219974Smavstatic inline struct mdio_device *to_mdio_device(const struct device *dev)
49219974Smav{
50219974Smav	return container_of(dev, struct mdio_device, dev);
51219974Smav}
52219974Smav
53219974Smav/* struct mdio_driver_common: Common to all MDIO drivers */
54219974Smavstruct mdio_driver_common {
55240465Smav	struct device_driver driver;
56267992Shselasky	int flags;
57240465Smav};
58219974Smav#define MDIO_DEVICE_FLAG_PHY		1
59267992Shselasky
60219974Smavstatic inline struct mdio_driver_common *
61220790Smavto_mdio_common_driver(const struct device_driver *driver)
62267992Shselasky{
63219974Smav	return container_of(driver, struct mdio_driver_common, driver);
64219974Smav}
65267992Shselasky
66219974Smav/* struct mdio_driver: Generic MDIO driver */
67219974Smavstruct mdio_driver {
68219974Smav	struct mdio_driver_common mdiodrv;
69267992Shselasky
70219974Smav	/*
71219974Smav	 * Called during discovery.  Used to set
72219974Smav	 * up device-specific structures, if any
73267992Shselasky	 */
74219974Smav	int (*probe)(struct mdio_device *mdiodev);
75219974Smav
76267992Shselasky	/* Clears up any memory if needed */
77219974Smav	void (*remove)(struct mdio_device *mdiodev);
78219974Smav
79267992Shselasky	/* Quiesces the device on system shutdown, turns off interrupts etc */
80219974Smav	void (*shutdown)(struct mdio_device *mdiodev);
81219974Smav};
82267992Shselasky
83219974Smavstatic inline struct mdio_driver *
84219974Smavto_mdio_driver(const struct device_driver *driver)
85219974Smav{
86219974Smav	return container_of(to_mdio_common_driver(driver), struct mdio_driver,
87219974Smav			    mdiodrv);
88219974Smav}
89219974Smav
90219974Smav/* device driver data */
91219974Smavstatic inline void mdiodev_set_drvdata(struct mdio_device *mdio, void *data)
92219974Smav{
93219974Smav	dev_set_drvdata(&mdio->dev, data);
94219974Smav}
95219974Smav
96219974Smavstatic inline void *mdiodev_get_drvdata(struct mdio_device *mdio)
97219974Smav{
98219974Smav	return dev_get_drvdata(&mdio->dev);
99219974Smav}
100219974Smav
101242314Smavvoid mdio_device_free(struct mdio_device *mdiodev);
102219974Smavstruct mdio_device *mdio_device_create(struct mii_bus *bus, int addr);
103242314Smavint mdio_device_register(struct mdio_device *mdiodev);
104219974Smavvoid mdio_device_remove(struct mdio_device *mdiodev);
105219974Smavvoid mdio_device_reset(struct mdio_device *mdiodev, int value);
106219974Smavint mdio_driver_register(struct mdio_driver *drv);
107219974Smavvoid mdio_driver_unregister(struct mdio_driver *drv);
108219974Smavint mdio_device_bus_match(struct device *dev, struct device_driver *drv);
109219974Smav
110219974Smavstatic inline void mdio_device_get(struct mdio_device *mdiodev)
111219974Smav{
112219974Smav	get_device(&mdiodev->dev);
113219974Smav}
114219974Smav
115219974Smavstatic inline void mdio_device_put(struct mdio_device *mdiodev)
116219974Smav{
117219974Smav	mdio_device_free(mdiodev);
118219974Smav}
119219974Smav
120219974Smavstatic inline bool mdio_phy_id_is_c45(int phy_id)
121219974Smav{
122219974Smav	return (phy_id & MDIO_PHY_ID_C45) && !(phy_id & ~MDIO_PHY_ID_C45_MASK);
123219974Smav}
124219974Smav
125219974Smavstatic inline __u16 mdio_phy_id_prtad(int phy_id)
126219974Smav{
127219974Smav	return (phy_id & MDIO_PHY_ID_PRTAD) >> 5;
128219974Smav}
129219974Smav
130219974Smavstatic inline __u16 mdio_phy_id_devad(int phy_id)
131219974Smav{
132219974Smav	return phy_id & MDIO_PHY_ID_DEVAD;
133219974Smav}
134219974Smav
135219974Smav/**
136219974Smav * struct mdio_if_info - Ethernet controller MDIO interface
137219974Smav * @prtad: PRTAD of the PHY (%MDIO_PRTAD_NONE if not present/unknown)
138219974Smav * @mmds: Mask of MMDs expected to be present in the PHY.  This must be
139219974Smav *	non-zero unless @prtad = %MDIO_PRTAD_NONE.
140219974Smav * @mode_support: MDIO modes supported.  If %MDIO_SUPPORTS_C22 is set then
141219974Smav *	MII register access will be passed through with @devad =
142219974Smav *	%MDIO_DEVAD_NONE.  If %MDIO_EMULATE_C22 is set then access to
143219974Smav *	commonly used clause 22 registers will be translated into
144219974Smav *	clause 45 registers.
145219974Smav * @dev: Net device structure
146219974Smav * @mdio_read: Register read function; returns value or negative error code
147219974Smav * @mdio_write: Register write function; returns 0 or negative error code
148219974Smav */
149219974Smavstruct mdio_if_info {
150219974Smav	int prtad;
151219974Smav	u32 mmds;
152219974Smav	unsigned mode_support;
153219974Smav
154219974Smav	struct net_device *dev;
155219974Smav	int (*mdio_read)(struct net_device *dev, int prtad, int devad,
156245326Smav			 u16 addr);
157245326Smav	int (*mdio_write)(struct net_device *dev, int prtad, int devad,
158219974Smav			  u16 addr, u16 val);
159219974Smav};
160219974Smav
161219974Smav#define MDIO_PRTAD_NONE			(-1)
162219974Smav#define MDIO_DEVAD_NONE			(-1)
163219974Smav#define MDIO_SUPPORTS_C22		1
164219974Smav#define MDIO_SUPPORTS_C45		2
165219974Smav#define MDIO_EMULATE_C22		4
166219974Smav
167219974Smavstruct ethtool_cmd;
168219974Smavstruct ethtool_pauseparam;
169219974Smavextern int mdio45_probe(struct mdio_if_info *mdio, int prtad);
170219974Smavextern int mdio_set_flag(const struct mdio_if_info *mdio,
171219974Smav			 int prtad, int devad, u16 addr, int mask,
172219974Smav			 bool sense);
173219974Smavextern int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmds);
174219974Smavextern int mdio45_nway_restart(const struct mdio_if_info *mdio);
175219974Smavextern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
176219974Smav				      struct ethtool_cmd *ecmd,
177219974Smav				      u32 npage_adv, u32 npage_lpa);
178219974Smavextern void
179219974Smavmdio45_ethtool_ksettings_get_npage(const struct mdio_if_info *mdio,
180219974Smav				   struct ethtool_link_ksettings *cmd,
181219974Smav				   u32 npage_adv, u32 npage_lpa);
182219974Smav
183219974Smav/**
184219974Smav * mdio45_ethtool_gset - get settings for ETHTOOL_GSET
185219974Smav * @mdio: MDIO interface
186219974Smav * @ecmd: Ethtool request structure
187219974Smav *
188219974Smav * Since the CSRs for auto-negotiation using next pages are not fully
189219974Smav * standardised, this function does not attempt to decode them.  Use
190219974Smav * mdio45_ethtool_gset_npage() to specify advertisement bits from next
191219974Smav * pages.
192219974Smav */
193219974Smavstatic inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio,
194219974Smav				       struct ethtool_cmd *ecmd)
195219974Smav{
196219974Smav	mdio45_ethtool_gset_npage(mdio, ecmd, 0, 0);
197219974Smav}
198219974Smav
199219974Smav/**
200219974Smav * mdio45_ethtool_ksettings_get - get settings for ETHTOOL_GLINKSETTINGS
201219974Smav * @mdio: MDIO interface
202219974Smav * @cmd: Ethtool request structure
203219974Smav *
204219974Smav * Since the CSRs for auto-negotiation using next pages are not fully
205219974Smav * standardised, this function does not attempt to decode them.  Use
206219974Smav * mdio45_ethtool_ksettings_get_npage() to specify advertisement bits
207219974Smav * from next pages.
208219974Smav */
209219974Smavstatic inline void
210219974Smavmdio45_ethtool_ksettings_get(const struct mdio_if_info *mdio,
211219974Smav			     struct ethtool_link_ksettings *cmd)
212219974Smav{
213219974Smav	mdio45_ethtool_ksettings_get_npage(mdio, cmd, 0, 0);
214219974Smav}
215219974Smav
216219974Smavextern int mdio_mii_ioctl(const struct mdio_if_info *mdio,
217219974Smav			  struct mii_ioctl_data *mii_data, int cmd);
218239175Smav
219239175Smav/**
220219974Smav * mmd_eee_cap_to_ethtool_sup_t
221219974Smav * @eee_cap: value of the MMD EEE Capability register
222219974Smav *
223219974Smav * A small helper function that translates MMD EEE Capability (3.20) bits
224219974Smav * to ethtool supported settings.
225219974Smav */
226219974Smavstatic inline u32 mmd_eee_cap_to_ethtool_sup_t(u16 eee_cap)
227219974Smav{
228219974Smav	u32 supported = 0;
229219974Smav
230219974Smav	if (eee_cap & MDIO_EEE_100TX)
231219974Smav		supported |= SUPPORTED_100baseT_Full;
232219974Smav	if (eee_cap & MDIO_EEE_1000T)
233219974Smav		supported |= SUPPORTED_1000baseT_Full;
234219974Smav	if (eee_cap & MDIO_EEE_10GT)
235219974Smav		supported |= SUPPORTED_10000baseT_Full;
236219974Smav	if (eee_cap & MDIO_EEE_1000KX)
237219974Smav		supported |= SUPPORTED_1000baseKX_Full;
238219974Smav	if (eee_cap & MDIO_EEE_10GKX4)
239219974Smav		supported |= SUPPORTED_10000baseKX4_Full;
240219974Smav	if (eee_cap & MDIO_EEE_10GKR)
241219974Smav		supported |= SUPPORTED_10000baseKR_Full;
242219974Smav
243219974Smav	return supported;
244219974Smav}
245219974Smav
246219974Smav/**
247219974Smav * mmd_eee_adv_to_ethtool_adv_t
248219974Smav * @eee_adv: value of the MMD EEE Advertisement/Link Partner Ability registers
249219974Smav *
250219974Smav * A small helper function that translates the MMD EEE Advertisment (7.60)
251219974Smav * and MMD EEE Link Partner Ability (7.61) bits to ethtool advertisement
252219974Smav * settings.
253219974Smav */
254219974Smavstatic inline u32 mmd_eee_adv_to_ethtool_adv_t(u16 eee_adv)
255219974Smav{
256219974Smav	u32 adv = 0;
257219974Smav
258219974Smav	if (eee_adv & MDIO_EEE_100TX)
259219974Smav		adv |= ADVERTISED_100baseT_Full;
260219974Smav	if (eee_adv & MDIO_EEE_1000T)
261219974Smav		adv |= ADVERTISED_1000baseT_Full;
262219974Smav	if (eee_adv & MDIO_EEE_10GT)
263219974Smav		adv |= ADVERTISED_10000baseT_Full;
264219974Smav	if (eee_adv & MDIO_EEE_1000KX)
265219974Smav		adv |= ADVERTISED_1000baseKX_Full;
266219974Smav	if (eee_adv & MDIO_EEE_10GKX4)
267219974Smav		adv |= ADVERTISED_10000baseKX4_Full;
268219974Smav	if (eee_adv & MDIO_EEE_10GKR)
269219974Smav		adv |= ADVERTISED_10000baseKR_Full;
270219974Smav
271219974Smav	return adv;
272219974Smav}
273219974Smav
274219974Smav/**
275219974Smav * ethtool_adv_to_mmd_eee_adv_t
276219974Smav * @adv: the ethtool advertisement settings
277219974Smav *
278219974Smav * A small helper function that translates ethtool advertisement settings
279234603Smav * to EEE advertisements for the MMD EEE Advertisement (7.60) and
280234603Smav * MMD EEE Link Partner Ability (7.61) registers.
281234603Smav */
282234603Smavstatic inline u16 ethtool_adv_to_mmd_eee_adv_t(u32 adv)
283219974Smav{
284219974Smav	u16 reg = 0;
285234603Smav
286234610Smav	if (adv & ADVERTISED_100baseT_Full)
287234603Smav		reg |= MDIO_EEE_100TX;
288234610Smav	if (adv & ADVERTISED_1000baseT_Full)
289219974Smav		reg |= MDIO_EEE_1000T;
290219974Smav	if (adv & ADVERTISED_10000baseT_Full)
291234458Smav		reg |= MDIO_EEE_10GT;
292234603Smav	if (adv & ADVERTISED_1000baseKX_Full)
293234458Smav		reg |= MDIO_EEE_1000KX;
294234603Smav	if (adv & ADVERTISED_10000baseKX4_Full)
295234458Smav		reg |= MDIO_EEE_10GKX4;
296234603Smav	if (adv & ADVERTISED_10000baseKR_Full)
297234458Smav		reg |= MDIO_EEE_10GKR;
298234603Smav
299219974Smav	return reg;
300219974Smav}
301234603Smav
302234603Smav/**
303234603Smav * linkmode_adv_to_mii_10gbt_adv_t
304234603Smav * @advertising: the linkmode advertisement settings
305234603Smav *
306234603Smav * A small helper function that translates linkmode advertisement
307234603Smav * settings to phy autonegotiation advertisements for the C45
308234603Smav * 10GBASE-T AN CONTROL (7.32) register.
309219974Smav */
310234603Smavstatic inline u32 linkmode_adv_to_mii_10gbt_adv_t(unsigned long *advertising)
311234603Smav{
312234603Smav	u32 result = 0;
313234603Smav
314234603Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
315234603Smav			      advertising))
316234603Smav		result |= MDIO_AN_10GBT_CTRL_ADV2_5G;
317234603Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
318234603Smav			      advertising))
319234603Smav		result |= MDIO_AN_10GBT_CTRL_ADV5G;
320219974Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
321234603Smav			      advertising))
322234603Smav		result |= MDIO_AN_10GBT_CTRL_ADV10G;
323234603Smav
324234603Smav	return result;
325219974Smav}
326219974Smav
327219974Smav/**
328219974Smav * mii_10gbt_stat_mod_linkmode_lpa_t
329219974Smav * @advertising: target the linkmode advertisement settings
330219974Smav * @lpa: value of the C45 10GBASE-T AN STATUS register
331234603Smav *
332234603Smav * A small helper function that translates C45 10GBASE-T AN STATUS register bits
333234603Smav * to linkmode advertisement settings. Other bits in advertising aren't changed.
334234603Smav */
335234603Smavstatic inline void mii_10gbt_stat_mod_linkmode_lpa_t(unsigned long *advertising,
336234603Smav						     u32 lpa)
337234603Smav{
338234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
339219974Smav			 advertising, lpa & MDIO_AN_10GBT_STAT_LP2_5G);
340219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
341234603Smav			 advertising, lpa & MDIO_AN_10GBT_STAT_LP5G);
342234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
343234603Smav			 advertising, lpa & MDIO_AN_10GBT_STAT_LP10G);
344234603Smav}
345234603Smav
346234603Smav/**
347234603Smav * mii_t1_adv_l_mod_linkmode_t
348234603Smav * @advertising: target the linkmode advertisement settings
349219974Smav * @lpa: value of the BASE-T1 Autonegotiation Advertisement [15:0] Register
350234603Smav *
351234603Smav * A small helper function that translates BASE-T1 Autonegotiation
352234603Smav * Advertisement [15:0] Register bits to linkmode advertisement settings.
353234603Smav * Other bits in advertising aren't changed.
354234603Smav */
355234603Smavstatic inline void mii_t1_adv_l_mod_linkmode_t(unsigned long *advertising, u32 lpa)
356234603Smav{
357234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising,
358234603Smav			 lpa & MDIO_AN_T1_ADV_L_PAUSE_CAP);
359234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising,
360219974Smav			 lpa & MDIO_AN_T1_ADV_L_PAUSE_ASYM);
361219974Smav}
362219974Smav
363219974Smav/**
364219974Smav * mii_t1_adv_m_mod_linkmode_t
365219974Smav * @advertising: target the linkmode advertisement settings
366219974Smav * @lpa: value of the BASE-T1 Autonegotiation Advertisement [31:16] Register
367219974Smav *
368219974Smav * A small helper function that translates BASE-T1 Autonegotiation
369219974Smav * Advertisement [31:16] Register bits to linkmode advertisement settings.
370219974Smav * Other bits in advertising aren't changed.
371219974Smav */
372219974Smavstatic inline void mii_t1_adv_m_mod_linkmode_t(unsigned long *advertising, u32 lpa)
373219974Smav{
374219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
375234603Smav			 advertising, lpa & MDIO_AN_T1_ADV_M_B10L);
376219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
377234603Smav			 advertising, lpa & MDIO_AN_T1_ADV_M_100BT1);
378234993Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
379234603Smav			 advertising, lpa & MDIO_AN_T1_ADV_M_1000BT1);
380234603Smav}
381234993Smav
382234603Smav/**
383219974Smav * linkmode_adv_to_mii_t1_adv_l_t
384234603Smav * @advertising: the linkmode advertisement settings
385234993Smav *
386234603Smav * A small helper function that translates linkmode advertisement
387234603Smav * settings to phy autonegotiation advertisements for the
388234993Smav * BASE-T1 Autonegotiation Advertisement [15:0] Register.
389234603Smav */
390219974Smavstatic inline u32 linkmode_adv_to_mii_t1_adv_l_t(unsigned long *advertising)
391234458Smav{
392234603Smav	u32 result = 0;
393234458Smav
394234458Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising))
395234458Smav		result |= MDIO_AN_T1_ADV_L_PAUSE_CAP;
396234603Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising))
397234458Smav		result |= MDIO_AN_T1_ADV_L_PAUSE_ASYM;
398234458Smav
399234603Smav	return result;
400234458Smav}
401234458Smav
402234603Smav/**
403219974Smav * linkmode_adv_to_mii_t1_adv_m_t
404234603Smav * @advertising: the linkmode advertisement settings
405234603Smav *
406234603Smav * A small helper function that translates linkmode advertisement
407234603Smav * settings to phy autonegotiation advertisements for the
408234603Smav * BASE-T1 Autonegotiation Advertisement [31:16] Register.
409234603Smav */
410234603Smavstatic inline u32 linkmode_adv_to_mii_t1_adv_m_t(unsigned long *advertising)
411234603Smav{
412234603Smav	u32 result = 0;
413234603Smav
414234603Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, advertising))
415234603Smav		result |= MDIO_AN_T1_ADV_M_B10L;
416234603Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, advertising))
417234603Smav		result |= MDIO_AN_T1_ADV_M_100BT1;
418234603Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, advertising))
419234603Smav		result |= MDIO_AN_T1_ADV_M_1000BT1;
420234603Smav
421234603Smav	return result;
422234603Smav}
423234603Smav
424234603Smav/**
425234603Smav * mii_eee_cap1_mod_linkmode_t()
426234603Smav * @adv: target the linkmode advertisement settings
427234603Smav * @val: register value
428234603Smav *
429234603Smav * A function that translates value of following registers to the linkmode:
430234603Smav * IEEE 802.3-2018 45.2.3.10 "EEE control and capability 1" register (3.20)
431219974Smav * IEEE 802.3-2018 45.2.7.13 "EEE advertisement 1" register (7.60)
432234603Smav * IEEE 802.3-2018 45.2.7.14 "EEE link partner ability 1" register (7.61)
433234603Smav */
434234603Smavstatic inline void mii_eee_cap1_mod_linkmode_t(unsigned long *adv, u32 val)
435234603Smav{
436234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
437219974Smav			 adv, val & MDIO_EEE_100TX);
438219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
439219974Smav			 adv, val & MDIO_EEE_1000T);
440234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
441219974Smav			 adv, val & MDIO_EEE_10GT);
442234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
443234603Smav			 adv, val & MDIO_EEE_1000KX);
444234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
445234603Smav			 adv, val & MDIO_EEE_10GKX4);
446234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
447234603Smav			 adv, val & MDIO_EEE_10GKR);
448234603Smav}
449234603Smav
450234603Smav/**
451234603Smav * mii_eee_cap2_mod_linkmode_sup_t()
452234603Smav * @adv: target the linkmode settings
453234603Smav * @val: register value
454219974Smav *
455234603Smav * A function that translates value of following registers to the linkmode:
456234603Smav * IEEE 802.3-2022 45.2.3.11 "EEE control and capability 2" register (3.21)
457234603Smav */
458234603Smavstatic inline void mii_eee_cap2_mod_linkmode_sup_t(unsigned long *adv, u32 val)
459234603Smav{
460234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
461234603Smav			 adv, val & MDIO_EEE_2_5GT);
462234603Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
463234603Smav			 adv, val & MDIO_EEE_5GT);
464234603Smav}
465234603Smav
466234603Smav/**
467234603Smav * mii_eee_cap2_mod_linkmode_adv_t()
468234603Smav * @adv: target the linkmode advertisement settings
469234603Smav * @val: register value
470234603Smav *
471234603Smav * A function that translates value of following registers to the linkmode:
472234603Smav * IEEE 802.3-2022 45.2.7.16 "EEE advertisement 2" register (7.62)
473234603Smav * IEEE 802.3-2022 45.2.7.17 "EEE link partner ability 2" register (7.63)
474234603Smav * Note: Currently this function is the same as mii_eee_cap2_mod_linkmode_sup_t.
475234603Smav *       For certain, not yet supported, modes however the bits differ.
476234603Smav *       Therefore create separate functions already.
477234603Smav */
478234603Smavstatic inline void mii_eee_cap2_mod_linkmode_adv_t(unsigned long *adv, u32 val)
479234603Smav{
480219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
481219974Smav			 adv, val & MDIO_EEE_2_5GT);
482219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
483219974Smav			 adv, val & MDIO_EEE_5GT);
484219974Smav}
485219974Smav
486219974Smav/**
487219974Smav * linkmode_to_mii_eee_cap1_t()
488219974Smav * @adv: the linkmode advertisement settings
489219974Smav *
490219974Smav * A function that translates linkmode to value for IEEE 802.3-2018 45.2.7.13
491219974Smav * "EEE advertisement 1" register (7.60)
492219974Smav */
493219974Smavstatic inline u32 linkmode_to_mii_eee_cap1_t(unsigned long *adv)
494242323Smav{
495242323Smav	u32 result = 0;
496242323Smav
497242323Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, adv))
498242323Smav		result |= MDIO_EEE_100TX;
499242323Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, adv))
500242323Smav		result |= MDIO_EEE_1000T;
501242323Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, adv))
502242323Smav		result |= MDIO_EEE_10GT;
503242323Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, adv))
504242323Smav		result |= MDIO_EEE_1000KX;
505242323Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, adv))
506242323Smav		result |= MDIO_EEE_10GKX4;
507242323Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, adv))
508242323Smav		result |= MDIO_EEE_10GKR;
509242323Smav
510242323Smav	return result;
511242323Smav}
512242323Smav
513242323Smav/**
514242323Smav * linkmode_to_mii_eee_cap2_t()
515242323Smav * @adv: the linkmode advertisement settings
516242323Smav *
517242323Smav * A function that translates linkmode to value for IEEE 802.3-2022 45.2.7.16
518242323Smav * "EEE advertisement 2" register (7.62)
519242323Smav */
520242323Smavstatic inline u32 linkmode_to_mii_eee_cap2_t(unsigned long *adv)
521242323Smav{
522219974Smav	u32 result = 0;
523219974Smav
524219974Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, adv))
525219974Smav		result |= MDIO_EEE_2_5GT;
526219974Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, adv))
527219974Smav		result |= MDIO_EEE_5GT;
528219974Smav
529219974Smav	return result;
530245326Smav}
531245363Smav
532245326Smav/**
533219974Smav * mii_10base_t1_adv_mod_linkmode_t()
534219974Smav * @adv: linkmode advertisement settings
535219974Smav * @val: register value
536219974Smav *
537219974Smav * A function that translates IEEE 802.3cg-2019 45.2.7.26 "10BASE-T1 AN status"
538219974Smav * register (7.527) value to the linkmode.
539219974Smav */
540219974Smavstatic inline void mii_10base_t1_adv_mod_linkmode_t(unsigned long *adv, u16 val)
541219974Smav{
542219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
543219974Smav			 adv, val & MDIO_AN_10BT1_AN_CTRL_ADV_EEE_T1L);
544219974Smav}
545219974Smav
546219974Smav/**
547219974Smav * linkmode_adv_to_mii_10base_t1_t()
548219974Smav * @adv: linkmode advertisement settings
549219974Smav *
550219974Smav * A function that translates the linkmode to IEEE 802.3cg-2019 45.2.7.25
551219974Smav * "10BASE-T1 AN control" register (7.526) value.
552219974Smav */
553219974Smavstatic inline u32 linkmode_adv_to_mii_10base_t1_t(unsigned long *adv)
554219974Smav{
555219974Smav	u32 result = 0;
556219974Smav
557219974Smav	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT, adv))
558219974Smav		result |= MDIO_AN_10BT1_AN_CTRL_ADV_EEE_T1L;
559219974Smav
560219974Smav	return result;
561219974Smav}
562219974Smav
563219974Smav/**
564219974Smav * mii_c73_mod_linkmode - convert a Clause 73 advertisement to linkmodes
565219974Smav * @adv: linkmode advertisement setting
566219974Smav * @lpa: array of three u16s containing the advertisement
567219974Smav *
568219974Smav * Convert an IEEE 802.3 Clause 73 advertisement to ethtool link modes.
569219974Smav */
570219974Smavstatic inline void mii_c73_mod_linkmode(unsigned long *adv, u16 *lpa)
571219974Smav{
572219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,
573219974Smav			 adv, lpa[0] & MDIO_AN_C73_0_PAUSE);
574219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
575219974Smav			 adv, lpa[0] & MDIO_AN_C73_0_ASM_DIR);
576219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
577219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_1000BASE_KX);
578219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
579219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_10GBASE_KX4);
580219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
581219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_40GBASE_KR4);
582219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
583219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_40GBASE_CR4);
584219974Smav	/* 100GBASE_CR10 and 100GBASE_KP4 not implemented */
585219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
586219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_100GBASE_KR4);
587219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
588219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_100GBASE_CR4);
589219974Smav	/* 25GBASE_R_S not implemented */
590219974Smav	/* The 25GBASE_R bit can be used for 25Gbase KR or CR modes */
591219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
592219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_25GBASE_R);
593219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
594219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_25GBASE_R);
595219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
596219974Smav			 adv, lpa[1] & MDIO_AN_C73_1_10GBASE_KR);
597219974Smav	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
598219974Smav			 adv, lpa[2] & MDIO_AN_C73_2_2500BASE_KX);
599219974Smav	/* 5GBASE_KR not implemented */
600219974Smav}
601219974Smav
602219974Smavint __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
603219974Smavint __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
604219974Smavint __mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask,
605219974Smav		     u16 set);
606219974Smavint __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
607219974Smav			     u16 mask, u16 set);
608219974Smav
609219974Smavint mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
610219974Smavint mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum);
611219974Smavint mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
612219974Smavint mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val);
613219974Smavint mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask,
614219974Smav		   u16 set);
615219974Smavint mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
616219974Smav			   u16 mask, u16 set);
617219974Smavint __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum);
618219974Smavint mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum);
619219974Smavint mdiobus_c45_read_nested(struct mii_bus *bus, int addr, int devad,
620219974Smav			     u32 regnum);
621219974Smavint __mdiobus_c45_write(struct mii_bus *bus, int addr,  int devad, u32 regnum,
622219974Smav			u16 val);
623219974Smavint mdiobus_c45_write(struct mii_bus *bus, int addr,  int devad, u32 regnum,
624219974Smav		      u16 val);
625219974Smavint mdiobus_c45_write_nested(struct mii_bus *bus, int addr,  int devad,
626219974Smav			     u32 regnum, u16 val);
627219974Smavint mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum,
628219974Smav		       u16 mask, u16 set);
629219974Smav
630219974Smavint mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, int devad,
631219974Smav			       u32 regnum, u16 mask, u16 set);
632219974Smav
633219974Smavstatic inline int __mdiodev_read(struct mdio_device *mdiodev, u32 regnum)
634219974Smav{
635219974Smav	return __mdiobus_read(mdiodev->bus, mdiodev->addr, regnum);
636219974Smav}
637219974Smav
638219974Smavstatic inline int __mdiodev_write(struct mdio_device *mdiodev, u32 regnum,
639219974Smav				  u16 val)
640219974Smav{
641219974Smav	return __mdiobus_write(mdiodev->bus, mdiodev->addr, regnum, val);
642219974Smav}
643219974Smav
644219974Smavstatic inline int __mdiodev_modify(struct mdio_device *mdiodev, u32 regnum,
645219974Smav				   u16 mask, u16 set)
646219974Smav{
647219974Smav	return __mdiobus_modify(mdiodev->bus, mdiodev->addr, regnum, mask, set);
648219974Smav}
649219974Smav
650219974Smavstatic inline int __mdiodev_modify_changed(struct mdio_device *mdiodev,
651219974Smav					   u32 regnum, u16 mask, u16 set)
652219974Smav{
653219974Smav	return __mdiobus_modify_changed(mdiodev->bus, mdiodev->addr, regnum,
654219974Smav					mask, set);
655219974Smav}
656219974Smav
657219974Smavstatic inline int mdiodev_read(struct mdio_device *mdiodev, u32 regnum)
658219974Smav{
659219974Smav	return mdiobus_read(mdiodev->bus, mdiodev->addr, regnum);
660219974Smav}
661219974Smav
662219974Smavstatic inline int mdiodev_write(struct mdio_device *mdiodev, u32 regnum,
663219974Smav				u16 val)
664219974Smav{
665219974Smav	return mdiobus_write(mdiodev->bus, mdiodev->addr, regnum, val);
666219974Smav}
667219974Smav
668219974Smavstatic inline int mdiodev_modify(struct mdio_device *mdiodev, u32 regnum,
669219974Smav				 u16 mask, u16 set)
670219974Smav{
671219974Smav	return mdiobus_modify(mdiodev->bus, mdiodev->addr, regnum, mask, set);
672219974Smav}
673219974Smav
674219974Smavstatic inline int mdiodev_modify_changed(struct mdio_device *mdiodev,
675219974Smav					 u32 regnum, u16 mask, u16 set)
676219974Smav{
677219974Smav	return mdiobus_modify_changed(mdiodev->bus, mdiodev->addr, regnum,
678219974Smav				      mask, set);
679219974Smav}
680219974Smav
681219974Smavstatic inline int mdiodev_c45_modify(struct mdio_device *mdiodev, int devad,
682219974Smav				     u32 regnum, u16 mask, u16 set)
683219974Smav{
684219974Smav	return mdiobus_c45_modify(mdiodev->bus, mdiodev->addr, devad, regnum,
685219974Smav				  mask, set);
686219974Smav}
687219974Smav
688219974Smavstatic inline int mdiodev_c45_modify_changed(struct mdio_device *mdiodev,
689219974Smav					     int devad, u32 regnum, u16 mask,
690219974Smav					     u16 set)
691219974Smav{
692219974Smav	return mdiobus_c45_modify_changed(mdiodev->bus, mdiodev->addr, devad,
693219974Smav					  regnum, mask, set);
694219974Smav}
695219974Smav
696219974Smavstatic inline int mdiodev_c45_read(struct mdio_device *mdiodev, int devad,
697219974Smav				   u16 regnum)
698219974Smav{
699219974Smav	return mdiobus_c45_read(mdiodev->bus, mdiodev->addr, devad, regnum);
700219974Smav}
701219974Smav
702219974Smavstatic inline int mdiodev_c45_write(struct mdio_device *mdiodev, u32 devad,
703219974Smav				    u16 regnum, u16 val)
704219974Smav{
705219974Smav	return mdiobus_c45_write(mdiodev->bus, mdiodev->addr, devad, regnum,
706219974Smav				 val);
707219974Smav}
708219974Smav
709219974Smavint mdiobus_register_device(struct mdio_device *mdiodev);
710219974Smavint mdiobus_unregister_device(struct mdio_device *mdiodev);
711219974Smavbool mdiobus_is_registered_device(struct mii_bus *bus, int addr);
712219974Smavstruct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr);
713219974Smav
714219974Smav/**
715219974Smav * mdio_module_driver() - Helper macro for registering mdio drivers
716219974Smav * @_mdio_driver: driver to register
717219974Smav *
718219974Smav * Helper macro for MDIO drivers which do not do anything special in module
719219974Smav * init/exit. Each module may only use this macro once, and calling it
720219974Smav * replaces module_init() and module_exit().
721219974Smav */
722219974Smav#define mdio_module_driver(_mdio_driver)				\
723219974Smavstatic int __init mdio_module_init(void)				\
724219974Smav{									\
725219974Smav	return mdio_driver_register(&_mdio_driver);			\
726219974Smav}									\
727219974Smavmodule_init(mdio_module_init);						\
728219974Smavstatic void __exit mdio_module_exit(void)				\
729219974Smav{									\
730219974Smav	mdio_driver_unregister(&_mdio_driver);				\
731219974Smav}									\
732219974Smavmodule_exit(mdio_module_exit)
733219974Smav
734219974Smav#endif /* __LINUX_MDIO_H__ */
735219974Smav