1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Bitbanged MDIO support. |
4 | * |
5 | * Author: Scott Wood <scottwood@freescale.com> |
6 | * Copyright (c) 2007 Freescale Semiconductor |
7 | * |
8 | * Based on CPM2 MDIO code which is: |
9 | * |
10 | * Copyright (c) 2003 Intracom S.A. |
11 | * by Pantelis Antoniou <panto@intracom.gr> |
12 | * |
13 | * 2005 (c) MontaVista Software, Inc. |
14 | * Vitaly Bordug <vbordug@ru.mvista.com> |
15 | */ |
16 | |
17 | #include <linux/delay.h> |
18 | #include <linux/mdio-bitbang.h> |
19 | #include <linux/module.h> |
20 | #include <linux/types.h> |
21 | |
22 | #define MDIO_READ 2 |
23 | #define MDIO_WRITE 1 |
24 | |
25 | #define MDIO_C45 (1<<15) |
26 | #define MDIO_C45_ADDR (MDIO_C45 | 0) |
27 | #define MDIO_C45_READ (MDIO_C45 | 3) |
28 | #define MDIO_C45_WRITE (MDIO_C45 | 1) |
29 | |
30 | #define MDIO_SETUP_TIME 10 |
31 | #define MDIO_HOLD_TIME 10 |
32 | |
33 | /* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY |
34 | * is done twice per period. |
35 | */ |
36 | #define MDIO_DELAY 250 |
37 | |
38 | /* The PHY may take up to 300 ns to produce data, plus some margin |
39 | * for error. |
40 | */ |
41 | #define MDIO_READ_DELAY 350 |
42 | |
43 | /* MDIO must already be configured as output. */ |
44 | static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val) |
45 | { |
46 | const struct mdiobb_ops *ops = ctrl->ops; |
47 | |
48 | ops->set_mdio_data(ctrl, val); |
49 | ndelay(MDIO_DELAY); |
50 | ops->set_mdc(ctrl, 1); |
51 | ndelay(MDIO_DELAY); |
52 | ops->set_mdc(ctrl, 0); |
53 | } |
54 | |
55 | /* MDIO must already be configured as input. */ |
56 | static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl) |
57 | { |
58 | const struct mdiobb_ops *ops = ctrl->ops; |
59 | |
60 | ndelay(MDIO_DELAY); |
61 | ops->set_mdc(ctrl, 1); |
62 | ndelay(MDIO_READ_DELAY); |
63 | ops->set_mdc(ctrl, 0); |
64 | |
65 | return ops->get_mdio_data(ctrl); |
66 | } |
67 | |
68 | /* MDIO must already be configured as output. */ |
69 | static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits) |
70 | { |
71 | int i; |
72 | |
73 | for (i = bits - 1; i >= 0; i--) |
74 | mdiobb_send_bit(ctrl, val: (val >> i) & 1); |
75 | } |
76 | |
77 | /* MDIO must already be configured as input. */ |
78 | static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits) |
79 | { |
80 | int i; |
81 | u16 ret = 0; |
82 | |
83 | for (i = bits - 1; i >= 0; i--) { |
84 | ret <<= 1; |
85 | ret |= mdiobb_get_bit(ctrl); |
86 | } |
87 | |
88 | return ret; |
89 | } |
90 | |
91 | /* Utility to send the preamble, address, and |
92 | * register (common to read and write). |
93 | */ |
94 | static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg) |
95 | { |
96 | const struct mdiobb_ops *ops = ctrl->ops; |
97 | int i; |
98 | |
99 | ops->set_mdio_dir(ctrl, 1); |
100 | |
101 | /* |
102 | * Send a 32 bit preamble ('1's) with an extra '1' bit for good |
103 | * measure. The IEEE spec says this is a PHY optional |
104 | * requirement. The AMD 79C874 requires one after power up and |
105 | * one after a MII communications error. This means that we are |
106 | * doing more preambles than we need, but it is safer and will be |
107 | * much more robust. |
108 | */ |
109 | |
110 | for (i = 0; i < 32; i++) |
111 | mdiobb_send_bit(ctrl, val: 1); |
112 | |
113 | /* send the start bit (01) and the read opcode (10) or write (01). |
114 | Clause 45 operation uses 00 for the start and 11, 10 for |
115 | read/write */ |
116 | mdiobb_send_bit(ctrl, val: 0); |
117 | if (op & MDIO_C45) |
118 | mdiobb_send_bit(ctrl, val: 0); |
119 | else |
120 | mdiobb_send_bit(ctrl, val: 1); |
121 | mdiobb_send_bit(ctrl, val: (op >> 1) & 1); |
122 | mdiobb_send_bit(ctrl, val: (op >> 0) & 1); |
123 | |
124 | mdiobb_send_num(ctrl, val: phy, bits: 5); |
125 | mdiobb_send_num(ctrl, val: reg, bits: 5); |
126 | } |
127 | |
128 | /* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the |
129 | lower 16 bits of the 21 bit address. This transfer is done identically to a |
130 | MDIO_WRITE except for a different code. Theoretically clause 45 and normal |
131 | devices can exist on the same bus. Normal devices should ignore the MDIO_ADDR |
132 | phase. */ |
133 | static void mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, int dev_addr, |
134 | int reg) |
135 | { |
136 | mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, reg: dev_addr); |
137 | |
138 | /* send the turnaround (10) */ |
139 | mdiobb_send_bit(ctrl, val: 1); |
140 | mdiobb_send_bit(ctrl, val: 0); |
141 | |
142 | mdiobb_send_num(ctrl, val: reg, bits: 16); |
143 | |
144 | ctrl->ops->set_mdio_dir(ctrl, 0); |
145 | mdiobb_get_bit(ctrl); |
146 | } |
147 | |
148 | static int mdiobb_read_common(struct mii_bus *bus, int phy) |
149 | { |
150 | struct mdiobb_ctrl *ctrl = bus->priv; |
151 | int ret, i; |
152 | |
153 | ctrl->ops->set_mdio_dir(ctrl, 0); |
154 | |
155 | /* check the turnaround bit: the PHY should be driving it to zero, if this |
156 | * PHY is listed in phy_ignore_ta_mask as having broken TA, skip that |
157 | */ |
158 | if (mdiobb_get_bit(ctrl) != 0 && |
159 | !(bus->phy_ignore_ta_mask & (1 << phy))) { |
160 | /* PHY didn't drive TA low -- flush any bits it |
161 | * may be trying to send. |
162 | */ |
163 | for (i = 0; i < 32; i++) |
164 | mdiobb_get_bit(ctrl); |
165 | |
166 | return 0xffff; |
167 | } |
168 | |
169 | ret = mdiobb_get_num(ctrl, bits: 16); |
170 | mdiobb_get_bit(ctrl); |
171 | return ret; |
172 | } |
173 | |
174 | int mdiobb_read_c22(struct mii_bus *bus, int phy, int reg) |
175 | { |
176 | struct mdiobb_ctrl *ctrl = bus->priv; |
177 | |
178 | mdiobb_cmd(ctrl, op: ctrl->op_c22_read, phy, reg); |
179 | |
180 | return mdiobb_read_common(bus, phy); |
181 | } |
182 | EXPORT_SYMBOL(mdiobb_read_c22); |
183 | |
184 | int mdiobb_read_c45(struct mii_bus *bus, int phy, int devad, int reg) |
185 | { |
186 | struct mdiobb_ctrl *ctrl = bus->priv; |
187 | |
188 | mdiobb_cmd_addr(ctrl, phy, dev_addr: devad, reg); |
189 | mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg: devad); |
190 | |
191 | return mdiobb_read_common(bus, phy); |
192 | } |
193 | EXPORT_SYMBOL(mdiobb_read_c45); |
194 | |
195 | static int mdiobb_write_common(struct mii_bus *bus, u16 val) |
196 | { |
197 | struct mdiobb_ctrl *ctrl = bus->priv; |
198 | |
199 | /* send the turnaround (10) */ |
200 | mdiobb_send_bit(ctrl, val: 1); |
201 | mdiobb_send_bit(ctrl, val: 0); |
202 | |
203 | mdiobb_send_num(ctrl, val, bits: 16); |
204 | |
205 | ctrl->ops->set_mdio_dir(ctrl, 0); |
206 | mdiobb_get_bit(ctrl); |
207 | return 0; |
208 | } |
209 | |
210 | int mdiobb_write_c22(struct mii_bus *bus, int phy, int reg, u16 val) |
211 | { |
212 | struct mdiobb_ctrl *ctrl = bus->priv; |
213 | |
214 | mdiobb_cmd(ctrl, op: ctrl->op_c22_write, phy, reg); |
215 | |
216 | return mdiobb_write_common(bus, val); |
217 | } |
218 | EXPORT_SYMBOL(mdiobb_write_c22); |
219 | |
220 | int mdiobb_write_c45(struct mii_bus *bus, int phy, int devad, int reg, u16 val) |
221 | { |
222 | struct mdiobb_ctrl *ctrl = bus->priv; |
223 | |
224 | mdiobb_cmd_addr(ctrl, phy, dev_addr: devad, reg); |
225 | mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg: devad); |
226 | |
227 | return mdiobb_write_common(bus, val); |
228 | } |
229 | EXPORT_SYMBOL(mdiobb_write_c45); |
230 | |
231 | struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl) |
232 | { |
233 | struct mii_bus *bus; |
234 | |
235 | bus = mdiobus_alloc(); |
236 | if (!bus) |
237 | return NULL; |
238 | |
239 | __module_get(module: ctrl->ops->owner); |
240 | |
241 | bus->read = mdiobb_read_c22; |
242 | bus->write = mdiobb_write_c22; |
243 | bus->read_c45 = mdiobb_read_c45; |
244 | bus->write_c45 = mdiobb_write_c45; |
245 | |
246 | bus->priv = ctrl; |
247 | if (!ctrl->override_op_c22) { |
248 | ctrl->op_c22_read = MDIO_READ; |
249 | ctrl->op_c22_write = MDIO_WRITE; |
250 | } |
251 | |
252 | return bus; |
253 | } |
254 | EXPORT_SYMBOL(alloc_mdio_bitbang); |
255 | |
256 | void free_mdio_bitbang(struct mii_bus *bus) |
257 | { |
258 | struct mdiobb_ctrl *ctrl = bus->priv; |
259 | |
260 | module_put(module: ctrl->ops->owner); |
261 | mdiobus_free(bus); |
262 | } |
263 | EXPORT_SYMBOL(free_mdio_bitbang); |
264 | |
265 | MODULE_LICENSE("GPL v2" ); |
266 | MODULE_DESCRIPTION("Bitbanged MDIO buses" ); |
267 | |