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