mdio.c revision 331722
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: stable/11/sys/mips/nlm/dev/net/mdio.c 331722 2018-03-29 02:50:57Z eadler $");
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 */
44int
45nlm_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 */
94int
95nlm_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
145int
146nlm_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 */
177int
178nlm_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 */
238int
239nlm_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 */
300int
301nlm_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 */
325void
326nlm_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