1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2003-2012 Broadcom Corporation
5 * All Rights Reserved
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
28 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
34 #include <sys/systm.h>
35
36 #include <mips/nlm/hal/mips-extns.h>
37 #include <mips/nlm/hal/haldefs.h>
38 #include <mips/nlm/hal/iomap.h>
39 #include <mips/nlm/hal/sys.h>
40 #include <mips/nlm/hal/nae.h>
41 #include <mips/nlm/hal/mdio.h>
42
43 #include <mips/nlm/xlp.h>
44
45 /* Internal MDIO READ/WRITE Routines */
46 int
nlm_int_gmac_mdio_read(uint64_t nae_base,int bus,int block,int intf_type,int phyaddr,int regidx)47 nlm_int_gmac_mdio_read(uint64_t nae_base, int bus, int block,
48 int intf_type, int phyaddr, int regidx)
49 {
50 uint32_t mdio_ld_cmd;
51 uint32_t ctrlval;
52
53 ctrlval = INT_MDIO_CTRL_SMP |
54 (phyaddr << INT_MDIO_CTRL_PHYADDR_POS) |
55 (regidx << INT_MDIO_CTRL_DEVTYPE_POS) |
56 (2 << INT_MDIO_CTRL_OP_POS) |
57 (1 << INT_MDIO_CTRL_ST_POS) |
58 (7 << INT_MDIO_CTRL_XDIV_POS) |
59 (2 << INT_MDIO_CTRL_TA_POS) |
60 (2 << INT_MDIO_CTRL_MIIM_POS) |
61 (1 << INT_MDIO_CTRL_MCDIV_POS);
62
63 mdio_ld_cmd = nlm_read_nae_reg(nae_base,
64 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)));
65 if (mdio_ld_cmd & INT_MDIO_CTRL_CMD_LOAD) {
66 nlm_write_nae_reg(nae_base,
67 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus*4)),
68 (mdio_ld_cmd & ~INT_MDIO_CTRL_CMD_LOAD));
69 }
70
71 nlm_write_nae_reg(nae_base,
72 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)),
73 ctrlval);
74
75 /* Toggle Load Cmd Bit */
76 nlm_write_nae_reg(nae_base,
77 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)),
78 ctrlval | (1 << INT_MDIO_CTRL_LOAD_POS));
79
80 /* poll master busy bit until it is not busy */
81 while(nlm_read_nae_reg(nae_base,
82 NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4))) &
83 INT_MDIO_STAT_MBSY) {
84 }
85
86 nlm_write_nae_reg(nae_base,
87 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)),
88 ctrlval);
89
90 /* Read the data back */
91 return nlm_read_nae_reg(nae_base,
92 NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4)));
93 }
94
95 /* Internal MDIO WRITE Routines */
96 int
nlm_int_gmac_mdio_write(uint64_t nae_base,int bus,int block,int intf_type,int phyaddr,int regidx,uint16_t val)97 nlm_int_gmac_mdio_write(uint64_t nae_base, int bus, int block,
98 int intf_type, int phyaddr, int regidx, uint16_t val)
99 {
100 uint32_t mdio_ld_cmd;
101 uint32_t ctrlval;
102
103 ctrlval = INT_MDIO_CTRL_SMP |
104 (phyaddr << INT_MDIO_CTRL_PHYADDR_POS) |
105 (regidx << INT_MDIO_CTRL_DEVTYPE_POS) |
106 (1 << INT_MDIO_CTRL_OP_POS) |
107 (1 << INT_MDIO_CTRL_ST_POS) |
108 (7 << INT_MDIO_CTRL_XDIV_POS) |
109 (2 << INT_MDIO_CTRL_TA_POS) |
110 (1 << INT_MDIO_CTRL_MIIM_POS) |
111 (1 << INT_MDIO_CTRL_MCDIV_POS);
112
113 mdio_ld_cmd = nlm_read_nae_reg(nae_base,
114 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)));
115 if (mdio_ld_cmd & INT_MDIO_CTRL_CMD_LOAD) {
116 nlm_write_nae_reg(nae_base,
117 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus*4)),
118 (mdio_ld_cmd & ~INT_MDIO_CTRL_CMD_LOAD));
119 }
120
121 /* load data into ctrl data reg */
122 nlm_write_nae_reg(nae_base,
123 NAE_REG(block, intf_type, (INT_MDIO_CTRL_DATA + bus * 4)),
124 val);
125
126 nlm_write_nae_reg(nae_base,
127 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)),
128 ctrlval);
129
130 nlm_write_nae_reg(nae_base,
131 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)),
132 ctrlval | (1 << INT_MDIO_CTRL_LOAD_POS));
133
134 /* poll master busy bit until it is not busy */
135 while(nlm_read_nae_reg(nae_base,
136 NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4))) &
137 INT_MDIO_STAT_MBSY) {
138 }
139
140 nlm_write_nae_reg(nae_base,
141 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)),
142 ctrlval);
143
144 return (0);
145 }
146
147 int
nlm_int_gmac_mdio_reset(uint64_t nae_base,int bus,int block,int intf_type)148 nlm_int_gmac_mdio_reset(uint64_t nae_base, int bus, int block,
149 int intf_type)
150 {
151 uint32_t val;
152
153 val = (7 << INT_MDIO_CTRL_XDIV_POS) |
154 (1 << INT_MDIO_CTRL_MCDIV_POS) |
155 (INT_MDIO_CTRL_SMP);
156
157 nlm_write_nae_reg(nae_base,
158 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)),
159 val | INT_MDIO_CTRL_RST);
160
161 nlm_write_nae_reg(nae_base,
162 NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)),
163 val);
164
165 return (0);
166 }
167
168 /*
169 * nae_gmac_mdio_read - Read sgmii phy register
170 *
171 * Input parameters:
172 * bus - bus number, nae has two external gmac bus: 0 and 1
173 * phyaddr - PHY's address
174 * regidx - index of register to read
175 *
176 * Return value:
177 * value read (16 bits), or 0xffffffff if an error occurred.
178 */
179 int
nlm_gmac_mdio_read(uint64_t nae_base,int bus,int block,int intf_type,int phyaddr,int regidx)180 nlm_gmac_mdio_read(uint64_t nae_base, int bus, int block,
181 int intf_type, int phyaddr, int regidx)
182 {
183 uint32_t mdio_ld_cmd;
184 uint32_t ctrlval;
185
186 mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type,
187 (EXT_G0_MDIO_CTRL + bus * 4)));
188 if (mdio_ld_cmd & EXT_G_MDIO_CMD_LCD) {
189 nlm_write_nae_reg(nae_base,
190 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)),
191 (mdio_ld_cmd & ~EXT_G_MDIO_CMD_LCD));
192 while(nlm_read_nae_reg(nae_base,
193 NAE_REG(block, intf_type,
194 (EXT_G0_MDIO_RD_STAT + bus * 4))) &
195 EXT_G_MDIO_STAT_MBSY);
196 }
197
198 ctrlval = EXT_G_MDIO_CMD_SP |
199 (phyaddr << EXT_G_MDIO_PHYADDR_POS) |
200 (regidx << EXT_G_MDIO_REGADDR_POS);
201 if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax())
202 ctrlval |= EXT_G_MDIO_DIV;
203 else
204 ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64;
205
206 nlm_write_nae_reg(nae_base,
207 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)),
208 ctrlval);
209
210 nlm_write_nae_reg(nae_base,
211 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)),
212 ctrlval | (1<<18));
213 DELAY(1000);
214 /* poll master busy bit until it is not busy */
215 while(nlm_read_nae_reg(nae_base,
216 NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) &
217 EXT_G_MDIO_STAT_MBSY);
218
219 nlm_write_nae_reg(nae_base,
220 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)),
221 ctrlval);
222
223 /* Read the data back */
224 return nlm_read_nae_reg(nae_base,
225 NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4)));
226 }
227
228 /*
229 * nae_gmac_mdio_write -Write sgmac mii PHY register.
230 *
231 * Input parameters:
232 * bus - bus number, nae has two external gmac bus: 0 and 1
233 * phyaddr - PHY to use
234 * regidx - register within the PHY
235 * val - data to write to register
236 *
237 * Return value:
238 * 0 - success
239 */
240 int
nlm_gmac_mdio_write(uint64_t nae_base,int bus,int block,int intf_type,int phyaddr,int regidx,uint16_t val)241 nlm_gmac_mdio_write(uint64_t nae_base, int bus, int block,
242 int intf_type, int phyaddr, int regidx, uint16_t val)
243 {
244 uint32_t mdio_ld_cmd;
245 uint32_t ctrlval;
246
247 mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type,
248 (EXT_G0_MDIO_CTRL + bus * 4)));
249 if (mdio_ld_cmd & EXT_G_MDIO_CMD_LCD) {
250 nlm_write_nae_reg(nae_base,
251 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)),
252 (mdio_ld_cmd & ~EXT_G_MDIO_CMD_LCD));
253 while(nlm_read_nae_reg(nae_base,
254 NAE_REG(block, intf_type,
255 (EXT_G0_MDIO_RD_STAT + bus * 4))) &
256 EXT_G_MDIO_STAT_MBSY);
257 }
258
259 /* load data into ctrl data reg */
260 nlm_write_nae_reg(nae_base,
261 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL_DATA+bus*4)),
262 val);
263
264 ctrlval = EXT_G_MDIO_CMD_SP |
265 (phyaddr << EXT_G_MDIO_PHYADDR_POS) |
266 (regidx << EXT_G_MDIO_REGADDR_POS);
267 if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax())
268 ctrlval |= EXT_G_MDIO_DIV;
269 else
270 ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64;
271
272 nlm_write_nae_reg(nae_base,
273 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)),
274 ctrlval);
275
276 nlm_write_nae_reg(nae_base,
277 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)),
278 ctrlval | EXT_G_MDIO_CMD_LCD);
279 DELAY(1000);
280
281 /* poll master busy bit until it is not busy */
282 while(nlm_read_nae_reg(nae_base,
283 NAE_REG(block, intf_type,
284 (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY);
285
286 nlm_write_nae_reg(nae_base,
287 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)),
288 ctrlval);
289
290 return (0);
291 }
292
293 /*
294 * nae_gmac_mdio_reset -Reset sgmii mdio module.
295 *
296 * Input parameters:
297 * bus - bus number, nae has two external gmac bus: 0 and 1
298 *
299 * Return value:
300 * 0 - success
301 */
302 int
nlm_gmac_mdio_reset(uint64_t nae_base,int bus,int block,int intf_type)303 nlm_gmac_mdio_reset(uint64_t nae_base, int bus, int block,
304 int intf_type)
305 {
306 uint32_t ctrlval;
307
308 ctrlval = nlm_read_nae_reg(nae_base,
309 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)));
310
311 if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax())
312 ctrlval |= EXT_G_MDIO_DIV;
313 else
314 ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64;
315
316 nlm_write_nae_reg(nae_base,
317 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4)),
318 EXT_G_MDIO_MMRST | ctrlval);
319 nlm_write_nae_reg(nae_base,
320 NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4)), ctrlval);
321 return (0);
322 }
323
324 /*
325 * nlm_mdio_reset_all : reset all internal and external MDIO
326 */
327 void
nlm_mdio_reset_all(uint64_t nae_base)328 nlm_mdio_reset_all(uint64_t nae_base)
329 {
330 /* reset internal MDIO */
331 nlm_int_gmac_mdio_reset(nae_base, 0, BLOCK_7, LANE_CFG);
332 /* reset external MDIO */
333 nlm_gmac_mdio_reset(nae_base, 0, BLOCK_7, LANE_CFG);
334 nlm_gmac_mdio_reset(nae_base, 1, BLOCK_7, LANE_CFG);
335 }
336