... | ... | ||
---|---|---|---|
26 | struct, .match_phy_device is extended to provide also the | 26 | struct, .match_phy_device is extended to provide also the |
27 | current phy_driver is trying to match for. This add the | 27 | current phy_driver is trying to match for. This add the |
28 | extra benefits that some other PHY can simplify their | 28 | extra benefits that some other PHY can simplify their |
29 | .match_phy_device OP. | 29 | .match_phy_device OP. |
30 | 30 | ||
31 | Changes v5: | ||
32 | - Add Reviewed-by tag from Rob | ||
33 | - Fix subject in DT patch | ||
34 | - Fix wrong Suggested-by tag in patch 1 | ||
35 | - Rework nxp patch to 80 column | ||
36 | Changes v4: | ||
37 | - Add Reviewed-by tag | ||
38 | - Better handle PHY ID scan in as21xxx | ||
39 | - Also simplify nxp driver and fix .match_phy_device | ||
31 | Changes v3: | 40 | Changes v3: |
32 | - Correct typo intergate->intergate | 41 | - Correct typo intergate->integrate |
33 | - Try to reduce to 80 column (where possible... define become | 42 | - Try to reduce to 80 column (where possible... define become |
34 | unreasable if split) | 43 | unreasable if split) |
35 | - Rework to new .match_phy_device implementation | 44 | - Rework to new .match_phy_device implementation |
36 | - Init active_low_led and fix other minor smatch war | 45 | - Init active_low_led and fix other minor smatch war |
37 | - Drop inline tag (kbot doesn't like it but not reported by checkpatch???) | 46 | - Drop inline tag (kbot doesn't like it but not reported by checkpatch???) |
... | ... | ||
47 | for generic PHY ID) | 56 | for generic PHY ID) |
48 | - Better document C22 in C45 | 57 | - Better document C22 in C45 |
49 | - Document PHY name logic | 58 | - Document PHY name logic |
50 | - Introduce patch to load PHY 2 times | 59 | - Introduce patch to load PHY 2 times |
51 | 60 | ||
52 | Christian Marangi (4): | 61 | Christian Marangi (6): |
53 | net: phy: pass PHY driver to .match_phy_device OP | 62 | net: phy: pass PHY driver to .match_phy_device OP |
54 | net: phy: bcm87xx: simplify .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() | ||
55 | net: phy: Add support for Aeonsemi AS21xxx PHYs | 66 | net: phy: Add support for Aeonsemi AS21xxx PHYs |
56 | dt-bindings: net: Document support for Aeonsemi PHYs | 67 | dt-bindings: net: Document support for Aeonsemi PHYs |
57 | 68 | ||
58 | .../bindings/net/aeonsemi,as21xxx.yaml | 122 ++ | 69 | .../bindings/net/aeonsemi,as21xxx.yaml | 122 ++ |
59 | MAINTAINERS | 7 + | 70 | MAINTAINERS | 7 + |
60 | drivers/net/phy/Kconfig | 12 + | 71 | drivers/net/phy/Kconfig | 12 + |
61 | drivers/net/phy/Makefile | 1 + | 72 | drivers/net/phy/Makefile | 1 + |
62 | drivers/net/phy/as21xxx.c | 1048 +++++++++++++++++ | 73 | drivers/net/phy/as21xxx.c | 1067 +++++++++++++++++ |
63 | drivers/net/phy/bcm87xx.c | 14 +- | 74 | drivers/net/phy/bcm87xx.c | 14 +- |
64 | drivers/net/phy/icplus.c | 6 +- | 75 | drivers/net/phy/icplus.c | 6 +- |
65 | drivers/net/phy/marvell10g.c | 12 +- | 76 | drivers/net/phy/marvell10g.c | 12 +- |
66 | drivers/net/phy/micrel.c | 6 +- | 77 | drivers/net/phy/micrel.c | 6 +- |
78 | drivers/net/phy/nxp-c45-tja11xx.c | 41 +- | ||
67 | drivers/net/phy/nxp-tja11xx.c | 6 +- | 79 | drivers/net/phy/nxp-tja11xx.c | 6 +- |
68 | drivers/net/phy/phy_device.c | 2 +- | 80 | drivers/net/phy/phy_device.c | 52 +- |
69 | drivers/net/phy/realtek/realtek_main.c | 27 +- | 81 | drivers/net/phy/realtek/realtek_main.c | 27 +- |
70 | drivers/net/phy/teranetics.c | 3 +- | 82 | drivers/net/phy/teranetics.c | 3 +- |
71 | include/linux/phy.h | 3 +- | 83 | include/linux/phy.h | 6 +- |
72 | 14 files changed, 1238 insertions(+), 31 deletions(-) | 84 | 15 files changed, 1316 insertions(+), 66 deletions(-) |
73 | create mode 100644 Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml | 85 | create mode 100644 Documentation/devicetree/bindings/net/aeonsemi,as21xxx.yaml |
74 | create mode 100644 drivers/net/phy/as21xxx.c | 86 | create mode 100644 drivers/net/phy/as21xxx.c |
75 | 87 | ||
76 | -- | 88 | -- |
77 | 2.48.1 | 89 | 2.48.1 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
12 | implement multiple simple .match_phy_device OP to match specific MMD PHY | 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 | 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 | 14 | function can be generalized by using the phy_id in the PHY driver |
15 | instead of hardcoding. | 15 | instead of hardcoding. |
16 | 16 | ||
17 | Suggested-by: Russell King (Oracle) <linux@armlinux.org.uk> | 17 | Suggested-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> |
18 | Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | ||
18 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | 19 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> |
19 | --- | 20 | --- |
20 | drivers/net/phy/bcm87xx.c | 6 ++++-- | 21 | drivers/net/phy/bcm87xx.c | 6 ++++-- |
21 | drivers/net/phy/icplus.c | 6 ++++-- | 22 | drivers/net/phy/icplus.c | 6 ++++-- |
22 | drivers/net/phy/marvell10g.c | 12 ++++++++---- | 23 | drivers/net/phy/marvell10g.c | 12 ++++++++---- |
23 | drivers/net/phy/micrel.c | 6 ++++-- | 24 | drivers/net/phy/micrel.c | 6 ++++-- |
25 | drivers/net/phy/nxp-c45-tja11xx.c | 12 ++++++++---- | ||
24 | drivers/net/phy/nxp-tja11xx.c | 6 ++++-- | 26 | drivers/net/phy/nxp-tja11xx.c | 6 ++++-- |
25 | drivers/net/phy/phy_device.c | 2 +- | 27 | drivers/net/phy/phy_device.c | 2 +- |
26 | drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++--------- | 28 | drivers/net/phy/realtek/realtek_main.c | 27 +++++++++++++++++--------- |
27 | drivers/net/phy/teranetics.c | 3 ++- | 29 | drivers/net/phy/teranetics.c | 3 ++- |
28 | include/linux/phy.h | 3 ++- | 30 | include/linux/phy.h | 3 ++- |
29 | 9 files changed, 47 insertions(+), 24 deletions(-) | 31 | 10 files changed, 55 insertions(+), 28 deletions(-) |
30 | 32 | ||
31 | diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c | 33 | diff --git a/drivers/net/phy/bcm87xx.c b/drivers/net/phy/bcm87xx.c |
32 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/drivers/net/phy/bcm87xx.c | 35 | --- a/drivers/net/phy/bcm87xx.c |
34 | +++ b/drivers/net/phy/bcm87xx.c | 36 | +++ b/drivers/net/phy/bcm87xx.c |
... | ... | ||
133 | +static int ksz8795_match_phy_device(struct phy_device *phydev, | 135 | +static int ksz8795_match_phy_device(struct phy_device *phydev, |
134 | + const struct phy_driver *phydrv) | 136 | + const struct phy_driver *phydrv) |
135 | { | 137 | { |
136 | return ksz8051_ksz8795_match_phy_device(phydev, false); | 138 | return ksz8051_ksz8795_match_phy_device(phydev, false); |
137 | } | 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); | ||
138 | diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c | 178 | diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c |
139 | index XXXXXXX..XXXXXXX 100644 | 179 | index XXXXXXX..XXXXXXX 100644 |
140 | --- a/drivers/net/phy/nxp-tja11xx.c | 180 | --- a/drivers/net/phy/nxp-tja11xx.c |
141 | +++ b/drivers/net/phy/nxp-tja11xx.c | 181 | +++ b/drivers/net/phy/nxp-tja11xx.c |
142 | @@ -XXX,XX +XXX,XX @@ static int tja1102_match_phy_device(struct phy_device *phydev, bool port0) | 182 | @@ -XXX,XX +XXX,XX @@ static int tja1102_match_phy_device(struct phy_device *phydev, bool port0) |
... | ... | diff view generated by jsdifflib |
1 | Simplify .match_phy_device OP by using a generic function and using the | 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. | 2 | new phy_id PHY driver info instead of hardcoding the matching PHY ID. |
3 | 3 | ||
4 | Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | ||
4 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | 5 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> |
5 | --- | 6 | --- |
6 | drivers/net/phy/bcm87xx.c | 14 ++++---------- | 7 | drivers/net/phy/bcm87xx.c | 14 ++++---------- |
7 | 1 file changed, 4 insertions(+), 10 deletions(-) | 8 | 1 file changed, 4 insertions(+), 10 deletions(-) |
8 | 9 | ||
... | ... | 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 |
New patch | |||
---|---|---|---|
1 | Introduce new API, genphy_match_phy_device(), to provide a way to check | ||
2 | to match a PHY driver for a PHY device based on the info stored in the | ||
3 | PHY device struct. | ||
1 | 4 | ||
5 | The function generalize the logic used in phy_bus_match() to check the | ||
6 | PHY ID whether if C45 or C22 ID should be used for matching. | ||
7 | |||
8 | This is useful for custom .match_phy_device function that wants to use | ||
9 | the generic logic under some condition. (example a PHY is already setup | ||
10 | and provide the correct PHY ID) | ||
11 | |||
12 | Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> | ||
13 | --- | ||
14 | drivers/net/phy/phy_device.c | 52 +++++++++++++++++++++++++----------- | ||
15 | include/linux/phy.h | 3 +++ | ||
16 | 2 files changed, 40 insertions(+), 15 deletions(-) | ||
17 | |||
18 | diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/drivers/net/phy/phy_device.c | ||
21 | +++ b/drivers/net/phy/phy_device.c | ||
22 | @@ -XXX,XX +XXX,XX @@ static int phy_scan_fixups(struct phy_device *phydev) | ||
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); | ||
70 | } | ||
71 | + | ||
72 | + return phy_id_compare(phydev->phy_id, phydrv->phy_id, | ||
73 | + phydrv->phy_id_mask); | ||
74 | +} | ||
75 | +EXPORT_SYMBOL_GPL(genphy_match_phy_device); | ||
76 | + | ||
77 | +static int phy_bus_match(struct device *dev, const struct device_driver *drv) | ||
78 | +{ | ||
79 | + struct phy_device *phydev = to_phy_device(dev); | ||
80 | + const struct phy_driver *phydrv = to_phy_driver(drv); | ||
81 | + | ||
82 | + if (!(phydrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)) | ||
83 | + return 0; | ||
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 | ||
92 | diff --git a/include/linux/phy.h b/include/linux/phy.h | ||
93 | index XXXXXXX..XXXXXXX 100644 | ||
94 | --- a/include/linux/phy.h | ||
95 | +++ b/include/linux/phy.h | ||
96 | @@ -XXX,XX +XXX,XX @@ char *phy_attached_info_irq(struct phy_device *phydev) | ||
97 | __malloc; | ||
98 | void phy_attached_info(struct phy_device *phydev); | ||
99 | |||
100 | +int genphy_match_phy_device(struct phy_device *phydev, | ||
101 | + const struct phy_driver *phydrv); | ||
102 | + | ||
103 | /* Clause 22 PHY */ | ||
104 | int genphy_read_abilities(struct phy_device *phydev); | ||
105 | int genphy_setup_forced(struct phy_device *phydev); | ||
106 | -- | ||
107 | 2.48.1 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
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 | 1048 +++++++++++++++++++++++++++++++++++++ | 33 | drivers/net/phy/as21xxx.c | 1067 +++++++++++++++++++++++++++++++++++++ |
34 | 4 files changed, 1067 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 |
... | ... | ||
484 | + AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false); | 484 | + AEON_IPC_DELAY, AEON_IPC_TIMEOUT, false); |
485 | +} | 485 | +} |
486 | + | 486 | + |
487 | +static int aeon_ipc_send_cmd(struct phy_device *phydev, | 487 | +static int aeon_ipc_send_cmd(struct phy_device *phydev, |
488 | + struct as21xxx_priv *priv, | 488 | + struct as21xxx_priv *priv, |
489 | + u32 cmd, u16 *ret_sts) | 489 | + u16 cmd, u16 *ret_sts) |
490 | +{ | 490 | +{ |
491 | + bool curr_parity; | 491 | + bool curr_parity; |
492 | + int ret; | 492 | + int ret; |
493 | + | 493 | + |
494 | + /* The IPC sync by using a single parity bit. | 494 | + /* The IPC sync by using a single parity bit. |
... | ... | ||
529 | + | 529 | + |
530 | + return 0; | 530 | + return 0; |
531 | +} | 531 | +} |
532 | + | 532 | + |
533 | +static int aeon_ipc_send_msg(struct phy_device *phydev, | 533 | +static int aeon_ipc_send_msg(struct phy_device *phydev, |
534 | + struct as21xxx_priv *priv, | ||
535 | + u16 opcode, u16 *data, unsigned int data_len, | 534 | + u16 opcode, u16 *data, unsigned int data_len, |
536 | + u16 *ret_sts) | 535 | + u16 *ret_sts) |
537 | +{ | 536 | +{ |
538 | + u32 cmd; | 537 | + struct as21xxx_priv *priv = phydev->priv; |
538 | + u16 cmd; | ||
539 | + int ret; | 539 | + int ret; |
540 | + int i; | 540 | + int i; |
541 | + | 541 | + |
542 | + /* IPC have a max of 8 register to transfer data, | 542 | + /* IPC have a max of 8 register to transfer data, |
543 | + * make sure we never exceed this. | 543 | + * make sure we never exceed this. |
... | ... | ||
562 | + | 562 | + |
563 | + return ret; | 563 | + return ret; |
564 | +} | 564 | +} |
565 | + | 565 | + |
566 | +static int aeon_ipc_rcv_msg(struct phy_device *phydev, | 566 | +static int aeon_ipc_rcv_msg(struct phy_device *phydev, |
567 | + struct as21xxx_priv *priv, | ||
568 | + u16 ret_sts, u16 *data) | 567 | + u16 ret_sts, u16 *data) |
569 | +{ | 568 | +{ |
570 | + unsigned int size = FIELD_GET(AEON_IPC_STS_SIZE, ret_sts); | 569 | + struct as21xxx_priv *priv = phydev->priv; |
570 | + unsigned int size; | ||
571 | + int ret; | 571 | + int ret; |
572 | + int i; | 572 | + int i; |
573 | + | 573 | + |
574 | + 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) |
575 | + return -EINVAL; | 575 | + return -EINVAL; |
576 | + | 576 | + |
577 | + /* 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); | ||
578 | + if (size > AEON_IPC_DATA_MAX) | 579 | + if (size > AEON_IPC_DATA_MAX) |
579 | + return -EINVAL; | 580 | + return -EINVAL; |
580 | + | 581 | + |
581 | + mutex_lock(&priv->ipc_lock); | 582 | + mutex_lock(&priv->ipc_lock); |
582 | + | 583 | + |
... | ... | ||
592 | + | 593 | + |
593 | +out: | 594 | +out: |
594 | + mutex_unlock(&priv->ipc_lock); | 595 | + mutex_unlock(&priv->ipc_lock); |
595 | + | 596 | + |
596 | + return size; | 597 | + return size; |
598 | +} | ||
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); | ||
597 | +} | 609 | +} |
598 | + | 610 | + |
599 | +/* Logic to sync parity bit with IPC. | 611 | +/* Logic to sync parity bit with IPC. |
600 | + * 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 |
601 | + * to handle the packet only for the second one. This way | 613 | + * to handle the packet only for the second one. This way |
602 | + * we make sure we are sync for every next cmd. | 614 | + * we make sure we are sync for every next cmd. |
603 | + */ | 615 | + */ |
604 | +static int aeon_ipc_sync_parity(struct phy_device *phydev, | 616 | +static int aeon_ipc_sync_parity(struct phy_device *phydev, |
605 | + struct as21xxx_priv *priv) | 617 | + struct as21xxx_priv *priv) |
606 | +{ | 618 | +{ |
607 | + u16 ret_sts; | 619 | + u16 ret_sts; |
608 | + u32 cmd; | ||
609 | + int ret; | 620 | + int ret; |
610 | + | 621 | + |
611 | + mutex_lock(&priv->ipc_lock); | 622 | + mutex_lock(&priv->ipc_lock); |
612 | + | 623 | + |
613 | + /* Send NOP with no parity */ | 624 | + /* Send NOP with no parity */ |
614 | + cmd = FIELD_PREP(AEON_IPC_CMD_SIZE, 0) | | 625 | + aeon_ipc_noop(phydev, priv, NULL); |
615 | + FIELD_PREP(AEON_IPC_CMD_OPCODE, IPC_CMD_NOOP); | ||
616 | + aeon_ipc_send_cmd(phydev, priv, cmd, NULL); | ||
617 | + | 626 | + |
618 | + /* Reset packet parity */ | 627 | + /* Reset packet parity */ |
619 | + priv->parity_status = false; | 628 | + priv->parity_status = false; |
620 | + | 629 | + |
621 | + /* Send second NOP with no parity */ | 630 | + /* Send second NOP with no parity */ |
622 | + ret = aeon_ipc_send_cmd(phydev, priv, cmd, &ret_sts); | 631 | + ret = aeon_ipc_noop(phydev, priv, &ret_sts); |
623 | + | 632 | + |
624 | + mutex_unlock(&priv->ipc_lock); | 633 | + mutex_unlock(&priv->ipc_lock); |
625 | + | 634 | + |
626 | + /* We expect to return -EINVAL */ | 635 | + /* We expect to return -EINVAL */ |
627 | + if (ret != -EINVAL) | 636 | + if (ret != -EINVAL) |
... | ... | ||
634 | + } | 643 | + } |
635 | + | 644 | + |
636 | + return 0; | 645 | + return 0; |
637 | +} | 646 | +} |
638 | + | 647 | + |
639 | +static int aeon_ipc_get_fw_version(struct phy_device *phydev, | 648 | +static int aeon_ipc_get_fw_version(struct phy_device *phydev) |
640 | + struct as21xxx_priv *priv) | ||
641 | +{ | 649 | +{ |
642 | + u16 ret_data[8], data[1]; | 650 | + u16 ret_data[8], data[1]; |
643 | + u16 ret_sts; | 651 | + u16 ret_sts; |
644 | + int ret; | 652 | + int ret; |
645 | + | 653 | + |
646 | + data[0] = IPC_INFO_VERSION; | 654 | + data[0] = IPC_INFO_VERSION; |
647 | + ret = aeon_ipc_send_msg(phydev, priv, IPC_CMD_INFO, data, | 655 | + ret = aeon_ipc_send_msg(phydev, IPC_CMD_INFO, data, |
648 | + sizeof(data), &ret_sts); | 656 | + sizeof(data), &ret_sts); |
649 | + if (ret) | 657 | + if (ret) |
650 | + return ret; | 658 | + return ret; |
651 | + | 659 | + |
652 | + ret = aeon_ipc_rcv_msg(phydev, priv, ret_sts, ret_data); | 660 | + ret = aeon_ipc_rcv_msg(phydev, ret_sts, ret_data); |
653 | + if (ret < 0) | 661 | + if (ret < 0) |
654 | + return ret; | 662 | + return ret; |
655 | + | 663 | + |
656 | + phydev_info(phydev, "Firmware Version: %s\n", (char *)ret_data); | 664 | + phydev_info(phydev, "Firmware Version: %s\n", (char *)ret_data); |
657 | + | 665 | + |
658 | + return 0; | 666 | + return 0; |
659 | +} | 667 | +} |
660 | + | 668 | + |
661 | +static int aeon_dpc_ra_enable(struct phy_device *phydev, | 669 | +static int aeon_dpc_ra_enable(struct phy_device *phydev) |
662 | + struct as21xxx_priv *priv) | ||
663 | +{ | 670 | +{ |
664 | + u16 data[2]; | 671 | + u16 data[2]; |
665 | + u16 ret_sts; | 672 | + u16 ret_sts; |
666 | + | 673 | + |
667 | + data[0] = IPC_CFG_PARAM_DIRECT; | 674 | + data[0] = IPC_CFG_PARAM_DIRECT; |
668 | + data[1] = IPC_CFG_PARAM_DIRECT_DPC_RA; | 675 | + data[1] = IPC_CFG_PARAM_DIRECT_DPC_RA; |
669 | + | 676 | + |
670 | + return aeon_ipc_send_msg(phydev, priv, IPC_CMD_CFG_PARAM, data, | 677 | + return aeon_ipc_send_msg(phydev, IPC_CMD_CFG_PARAM, data, |
671 | + sizeof(data), &ret_sts); | 678 | + sizeof(data), &ret_sts); |
672 | +} | 679 | +} |
673 | + | 680 | + |
674 | +static int as21xxx_probe(struct phy_device *phydev) | 681 | +static int as21xxx_probe(struct phy_device *phydev) |
675 | +{ | 682 | +{ |
... | ... | ||
689 | + | 696 | + |
690 | + ret = aeon_ipc_sync_parity(phydev, priv); | 697 | + ret = aeon_ipc_sync_parity(phydev, priv); |
691 | + if (ret) | 698 | + if (ret) |
692 | + return ret; | 699 | + return ret; |
693 | + | 700 | + |
694 | + return aeon_ipc_get_fw_version(phydev, priv); | 701 | + ret = aeon_ipc_get_fw_version(phydev); |
702 | + if (ret) | ||
703 | + return ret; | ||
704 | + | ||
705 | + /* Enable PTP clk if not already Enabled */ | ||
706 | + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK, | ||
707 | + VEND1_PTP_CLK_EN); | ||
708 | + if (ret) | ||
709 | + return ret; | ||
710 | + | ||
711 | + return aeon_dpc_ra_enable(phydev); | ||
695 | +} | 712 | +} |
696 | + | 713 | + |
697 | +static int as21xxx_read_link(struct phy_device *phydev, int *bmcr) | 714 | +static int as21xxx_read_link(struct phy_device *phydev, int *bmcr) |
698 | +{ | 715 | +{ |
699 | + int status; | 716 | + int status; |
... | ... | ||
939 | + | 956 | + |
940 | +static int as21xxx_match_phy_device(struct phy_device *phydev, | 957 | +static int as21xxx_match_phy_device(struct phy_device *phydev, |
941 | + const struct phy_driver *phydrv) | 958 | + const struct phy_driver *phydrv) |
942 | +{ | 959 | +{ |
943 | + struct as21xxx_priv *priv; | 960 | + struct as21xxx_priv *priv; |
961 | + u16 ret_sts; | ||
944 | + u32 phy_id; | 962 | + u32 phy_id; |
945 | + int ret; | 963 | + int ret; |
946 | + | 964 | + |
947 | + /* Skip PHY that are not AS21xxx or already have firmware loaded */ | 965 | + /* Skip PHY that are not AS21xxx or already have firmware loaded */ |
948 | + if (phydev->c45_ids.device_ids[MDIO_MMD_PCS] != PHY_ID_AS21XXX) | 966 | + if (phydev->c45_ids.device_ids[MDIO_MMD_PCS] != PHY_ID_AS21XXX) |
949 | + return phydev->phy_id == phydrv->phy_id; | 967 | + return genphy_match_phy_device(phydev, phydrv); |
950 | + | 968 | + |
951 | + /* Read PHY ID to handle firmware just loaded */ | 969 | + /* Read PHY ID to handle firmware just loaded */ |
952 | + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1); | 970 | + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_PHYSID1); |
953 | + if (ret < 0) | 971 | + if (ret < 0) |
954 | + return ret; | 972 | + return ret; |
... | ... | ||
972 | + | 990 | + |
973 | + mutex_init(&priv->ipc_lock); | 991 | + mutex_init(&priv->ipc_lock); |
974 | + | 992 | + |
975 | + ret = aeon_firmware_load(phydev); | 993 | + ret = aeon_firmware_load(phydev); |
976 | + if (ret) | 994 | + if (ret) |
977 | + return ret; | 995 | + goto out; |
978 | + | 996 | + |
997 | + /* Sync parity... */ | ||
979 | + ret = aeon_ipc_sync_parity(phydev, priv); | 998 | + ret = aeon_ipc_sync_parity(phydev, priv); |
980 | + if (ret) | 999 | + if (ret) |
981 | + return ret; | 1000 | + goto out; |
982 | + | 1001 | + |
983 | + /* Enable PTP clk if not already Enabled */ | 1002 | + /* ...and send a third NOOP cmd to wait for firmware finish loading */ |
984 | + ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK, | 1003 | + ret = aeon_ipc_noop(phydev, priv, &ret_sts); |
985 | + VEND1_PTP_CLK_EN); | 1004 | + if (ret) |
986 | + if (ret) | 1005 | + goto out; |
987 | + return ret; | 1006 | + |
988 | + | 1007 | +out: |
989 | + ret = aeon_dpc_ra_enable(phydev, priv); | ||
990 | + if (ret) | ||
991 | + return ret; | ||
992 | + | ||
993 | + mutex_destroy(&priv->ipc_lock); | 1008 | + mutex_destroy(&priv->ipc_lock); |
994 | + kfree(priv); | 1009 | + kfree(priv); |
995 | + | 1010 | + |
996 | + /* Return not maching anyway as PHY ID will change after | 1011 | + /* Return not maching anyway as PHY ID will change after |
997 | + * firmware is loaded. | 1012 | + * firmware is loaded. This relies on the driver probe |
1013 | + * order where the first PHY driver probed is the | ||
1014 | + * generic one. | ||
998 | + */ | 1015 | + */ |
999 | + return 0; | 1016 | + return ret; |
1000 | +} | 1017 | +} |
1001 | + | 1018 | + |
1002 | +static struct phy_driver as21xxx_drivers[] = { | 1019 | +static struct phy_driver as21xxx_drivers[] = { |
1003 | + { | 1020 | + { |
1004 | + /* PHY expose in C45 as 0x7500 0x9410 | 1021 | + /* PHY expose in C45 as 0x7500 0x9410 |
1005 | + * 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. | ||
1006 | + */ | 1025 | + */ |
1007 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX), | 1026 | + PHY_ID_MATCH_EXACT(PHY_ID_AS21XXX), |
1008 | + .name = "Aeonsemi AS21xxx", | 1027 | + .name = "Aeonsemi AS21xxx", |
1009 | + .match_phy_device = as21xxx_match_phy_device, | 1028 | + .match_phy_device = as21xxx_match_phy_device, |
1010 | + }, | 1029 | + }, |
... | ... | 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 |