Loading...
1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2/* Copyright 2019 NXP */
3
4#include <linux/fsl/enetc_mdio.h>
5#include <linux/mdio.h>
6#include <linux/of_mdio.h>
7#include <linux/iopoll.h>
8#include <linux/of.h>
9
10#include "enetc_pf.h"
11
12#define ENETC_MDIO_CFG 0x0 /* MDIO configuration and status */
13#define ENETC_MDIO_CTL 0x4 /* MDIO control */
14#define ENETC_MDIO_DATA 0x8 /* MDIO data */
15#define ENETC_MDIO_ADDR 0xc /* MDIO address */
16
17#define MDIO_CFG_CLKDIV(x) ((((x) >> 1) & 0xff) << 8)
18#define MDIO_CFG_BSY BIT(0)
19#define MDIO_CFG_RD_ER BIT(1)
20#define MDIO_CFG_HOLD(x) (((x) << 2) & GENMASK(4, 2))
21#define MDIO_CFG_ENC45 BIT(6)
22 /* external MDIO only - driven on neg MDC edge */
23#define MDIO_CFG_NEG BIT(23)
24
25#define ENETC_EMDIO_CFG \
26 (MDIO_CFG_HOLD(2) | \
27 MDIO_CFG_CLKDIV(258) | \
28 MDIO_CFG_NEG)
29
30#define MDIO_CTL_DEV_ADDR(x) ((x) & 0x1f)
31#define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5)
32#define MDIO_CTL_READ BIT(15)
33
34static inline u32 enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off)
35{
36 return enetc_port_rd_mdio(mdio_priv->hw, mdio_priv->mdio_base + off);
37}
38
39static inline void enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off,
40 u32 val)
41{
42 enetc_port_wr_mdio(mdio_priv->hw, mdio_priv->mdio_base + off, val);
43}
44
45static bool enetc_mdio_is_busy(struct enetc_mdio_priv *mdio_priv)
46{
47 return enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_BSY;
48}
49
50static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv)
51{
52 bool is_busy;
53
54 return readx_poll_timeout(enetc_mdio_is_busy, mdio_priv,
55 is_busy, !is_busy, 10, 10 * 1000);
56}
57
58int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum,
59 u16 value)
60{
61 struct enetc_mdio_priv *mdio_priv = bus->priv;
62 u32 mdio_ctl, mdio_cfg;
63 u16 dev_addr;
64 int ret;
65
66 mdio_cfg = ENETC_EMDIO_CFG;
67 dev_addr = regnum & 0x1f;
68 mdio_cfg &= ~MDIO_CFG_ENC45;
69
70 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
71
72 ret = enetc_mdio_wait_complete(mdio_priv);
73 if (ret)
74 return ret;
75
76 /* set port and dev addr */
77 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
78 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
79
80 /* write the value */
81 enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value);
82
83 ret = enetc_mdio_wait_complete(mdio_priv);
84 if (ret)
85 return ret;
86
87 return 0;
88}
89EXPORT_SYMBOL_GPL(enetc_mdio_write_c22);
90
91int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
92 int regnum, u16 value)
93{
94 struct enetc_mdio_priv *mdio_priv = bus->priv;
95 u32 mdio_ctl, mdio_cfg;
96 int ret;
97
98 mdio_cfg = ENETC_EMDIO_CFG;
99 mdio_cfg |= MDIO_CFG_ENC45;
100
101 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
102
103 ret = enetc_mdio_wait_complete(mdio_priv);
104 if (ret)
105 return ret;
106
107 /* set port and dev addr */
108 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
109 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
110
111 /* set the register address */
112 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
113
114 ret = enetc_mdio_wait_complete(mdio_priv);
115 if (ret)
116 return ret;
117
118 /* write the value */
119 enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value);
120
121 ret = enetc_mdio_wait_complete(mdio_priv);
122 if (ret)
123 return ret;
124
125 return 0;
126}
127EXPORT_SYMBOL_GPL(enetc_mdio_write_c45);
128
129int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum)
130{
131 struct enetc_mdio_priv *mdio_priv = bus->priv;
132 u32 mdio_ctl, mdio_cfg;
133 u16 dev_addr, value;
134 int ret;
135
136 mdio_cfg = ENETC_EMDIO_CFG;
137 dev_addr = regnum & 0x1f;
138 mdio_cfg &= ~MDIO_CFG_ENC45;
139
140 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
141
142 ret = enetc_mdio_wait_complete(mdio_priv);
143 if (ret)
144 return ret;
145
146 /* set port and device addr */
147 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
148 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
149
150 /* initiate the read */
151 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
152
153 ret = enetc_mdio_wait_complete(mdio_priv);
154 if (ret)
155 return ret;
156
157 /* return all Fs if nothing was there */
158 if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) {
159 dev_dbg(&bus->dev,
160 "Error while reading PHY%d reg at %d.%d\n",
161 phy_id, dev_addr, regnum);
162 return 0xffff;
163 }
164
165 value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff;
166
167 return value;
168}
169EXPORT_SYMBOL_GPL(enetc_mdio_read_c22);
170
171int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr,
172 int regnum)
173{
174 struct enetc_mdio_priv *mdio_priv = bus->priv;
175 u32 mdio_ctl, mdio_cfg;
176 u16 value;
177 int ret;
178
179 mdio_cfg = ENETC_EMDIO_CFG;
180 mdio_cfg |= MDIO_CFG_ENC45;
181
182 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg);
183
184 ret = enetc_mdio_wait_complete(mdio_priv);
185 if (ret)
186 return ret;
187
188 /* set port and device addr */
189 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
190 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl);
191
192 /* set the register address */
193 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff);
194
195 ret = enetc_mdio_wait_complete(mdio_priv);
196 if (ret)
197 return ret;
198
199 /* initiate the read */
200 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
201
202 ret = enetc_mdio_wait_complete(mdio_priv);
203 if (ret)
204 return ret;
205
206 /* return all Fs if nothing was there */
207 if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) {
208 dev_dbg(&bus->dev,
209 "Error while reading PHY%d reg at %d.%d\n",
210 phy_id, dev_addr, regnum);
211 return 0xffff;
212 }
213
214 value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff;
215
216 return value;
217}
218EXPORT_SYMBOL_GPL(enetc_mdio_read_c45);
219
220struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
221{
222 struct enetc_hw *hw;
223
224 hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
225 if (!hw)
226 return ERR_PTR(-ENOMEM);
227
228 hw->port = port_regs;
229
230 return hw;
231}
232EXPORT_SYMBOL_GPL(enetc_hw_alloc);
233
234/* Lock for MDIO access errata on LS1028A */
235DEFINE_RWLOCK(enetc_mdio_lock);
236EXPORT_SYMBOL_GPL(enetc_mdio_lock);
1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2/* Copyright 2019 NXP */
3
4#include <linux/fsl/enetc_mdio.h>
5#include <linux/mdio.h>
6#include <linux/of_mdio.h>
7#include <linux/iopoll.h>
8#include <linux/of.h>
9
10#include "enetc_pf.h"
11
12#define ENETC_MDIO_CFG 0x0 /* MDIO configuration and status */
13#define ENETC_MDIO_CTL 0x4 /* MDIO control */
14#define ENETC_MDIO_DATA 0x8 /* MDIO data */
15#define ENETC_MDIO_ADDR 0xc /* MDIO address */
16
17static inline u32 _enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off)
18{
19 return enetc_port_rd(mdio_priv->hw, mdio_priv->mdio_base + off);
20}
21
22static inline void _enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off,
23 u32 val)
24{
25 enetc_port_wr(mdio_priv->hw, mdio_priv->mdio_base + off, val);
26}
27
28#define enetc_mdio_rd(mdio_priv, off) \
29 _enetc_mdio_rd(mdio_priv, ENETC_##off)
30#define enetc_mdio_wr(mdio_priv, off, val) \
31 _enetc_mdio_wr(mdio_priv, ENETC_##off, val)
32#define enetc_mdio_rd_reg(off) enetc_mdio_rd(mdio_priv, off)
33
34#define MDIO_CFG_CLKDIV(x) ((((x) >> 1) & 0xff) << 8)
35#define MDIO_CFG_BSY BIT(0)
36#define MDIO_CFG_RD_ER BIT(1)
37#define MDIO_CFG_HOLD(x) (((x) << 2) & GENMASK(4, 2))
38#define MDIO_CFG_ENC45 BIT(6)
39 /* external MDIO only - driven on neg MDC edge */
40#define MDIO_CFG_NEG BIT(23)
41
42#define ENETC_EMDIO_CFG \
43 (MDIO_CFG_HOLD(2) | \
44 MDIO_CFG_CLKDIV(258) | \
45 MDIO_CFG_NEG)
46
47#define MDIO_CTL_DEV_ADDR(x) ((x) & 0x1f)
48#define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5)
49#define MDIO_CTL_READ BIT(15)
50#define MDIO_DATA(x) ((x) & 0xffff)
51
52#define TIMEOUT 1000
53static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv)
54{
55 u32 val;
56
57 return readx_poll_timeout(enetc_mdio_rd_reg, MDIO_CFG, val,
58 !(val & MDIO_CFG_BSY), 10, 10 * TIMEOUT);
59}
60
61int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
62{
63 struct enetc_mdio_priv *mdio_priv = bus->priv;
64 u32 mdio_ctl, mdio_cfg;
65 u16 dev_addr;
66 int ret;
67
68 mdio_cfg = ENETC_EMDIO_CFG;
69 if (regnum & MII_ADDR_C45) {
70 dev_addr = (regnum >> 16) & 0x1f;
71 mdio_cfg |= MDIO_CFG_ENC45;
72 } else {
73 /* clause 22 (ie 1G) */
74 dev_addr = regnum & 0x1f;
75 mdio_cfg &= ~MDIO_CFG_ENC45;
76 }
77
78 enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg);
79
80 ret = enetc_mdio_wait_complete(mdio_priv);
81 if (ret)
82 return ret;
83
84 /* set port and dev addr */
85 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
86 enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl);
87
88 /* set the register address */
89 if (regnum & MII_ADDR_C45) {
90 enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff);
91
92 ret = enetc_mdio_wait_complete(mdio_priv);
93 if (ret)
94 return ret;
95 }
96
97 /* write the value */
98 enetc_mdio_wr(mdio_priv, MDIO_DATA, MDIO_DATA(value));
99
100 ret = enetc_mdio_wait_complete(mdio_priv);
101 if (ret)
102 return ret;
103
104 return 0;
105}
106EXPORT_SYMBOL_GPL(enetc_mdio_write);
107
108int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
109{
110 struct enetc_mdio_priv *mdio_priv = bus->priv;
111 u32 mdio_ctl, mdio_cfg;
112 u16 dev_addr, value;
113 int ret;
114
115 mdio_cfg = ENETC_EMDIO_CFG;
116 if (regnum & MII_ADDR_C45) {
117 dev_addr = (regnum >> 16) & 0x1f;
118 mdio_cfg |= MDIO_CFG_ENC45;
119 } else {
120 dev_addr = regnum & 0x1f;
121 mdio_cfg &= ~MDIO_CFG_ENC45;
122 }
123
124 enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg);
125
126 ret = enetc_mdio_wait_complete(mdio_priv);
127 if (ret)
128 return ret;
129
130 /* set port and device addr */
131 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
132 enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl);
133
134 /* set the register address */
135 if (regnum & MII_ADDR_C45) {
136 enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff);
137
138 ret = enetc_mdio_wait_complete(mdio_priv);
139 if (ret)
140 return ret;
141 }
142
143 /* initiate the read */
144 enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl | MDIO_CTL_READ);
145
146 ret = enetc_mdio_wait_complete(mdio_priv);
147 if (ret)
148 return ret;
149
150 /* return all Fs if nothing was there */
151 if (enetc_mdio_rd(mdio_priv, MDIO_CFG) & MDIO_CFG_RD_ER) {
152 dev_dbg(&bus->dev,
153 "Error while reading PHY%d reg at %d.%hhu\n",
154 phy_id, dev_addr, regnum);
155 return 0xffff;
156 }
157
158 value = enetc_mdio_rd(mdio_priv, MDIO_DATA) & 0xffff;
159
160 return value;
161}
162EXPORT_SYMBOL_GPL(enetc_mdio_read);
163
164struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs)
165{
166 struct enetc_hw *hw;
167
168 hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
169 if (!hw)
170 return ERR_PTR(-ENOMEM);
171
172 hw->port = port_regs;
173
174 return hw;
175}
176EXPORT_SYMBOL_GPL(enetc_hw_alloc);