xref: /f-stack/freebsd/mips/nlm/dev/net/mdio.c (revision 22ce4aff)
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