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#include <mips/nlm/hal/sgmii.h>
41#include <mips/nlm/hal/xaui.h>
42
43#include <mips/nlm/xlp.h>
44void
45nlm_xaui_pcs_init(uint64_t nae_base, int xaui_cplx_mask)
46{
47	int block, lane_ctrl, reg;
48	int cplx_lane_enable;
49	int lane_enable = 0;
50	uint32_t regval;
51
52	cplx_lane_enable = LM_XAUI |
53	    (LM_XAUI << 4) |
54	    (LM_XAUI << 8) |
55	    (LM_XAUI << 12);
56
57	if (xaui_cplx_mask == 0)
58		return;
59
60	/* write 0x2 to enable SGMII for all lane */
61	block = 7;
62
63	if (xaui_cplx_mask & 0x3) { /* Complexes 0, 1 */
64		lane_enable = nlm_read_nae_reg(nae_base,
65		    NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_0_1));
66		if (xaui_cplx_mask & 0x1) { /* Complex 0 */
67			lane_enable &= ~(0xFFFF);
68			lane_enable |= cplx_lane_enable;
69		}
70		if (xaui_cplx_mask & 0x2) { /* Complex 1 */
71			lane_enable &= ~(0xFFFF<<16);
72			lane_enable |= (cplx_lane_enable << 16);
73		}
74		nlm_write_nae_reg(nae_base,
75		    NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_0_1),
76		    lane_enable);
77	}
78	lane_enable = 0;
79	if (xaui_cplx_mask & 0xc) { /* Complexes 2, 3 */
80		lane_enable = nlm_read_nae_reg(nae_base,
81		    NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_2_3));
82		if (xaui_cplx_mask & 0x4) { /* Complex 2 */
83			lane_enable &= ~(0xFFFF);
84			lane_enable |= cplx_lane_enable;
85		}
86		if (xaui_cplx_mask & 0x8) { /* Complex 3 */
87			lane_enable &= ~(0xFFFF<<16);
88			lane_enable |= (cplx_lane_enable << 16);
89		}
90		nlm_write_nae_reg(nae_base,
91		    NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_2_3),
92		    lane_enable);
93	}
94
95	/* Bring txpll out of reset */
96	for (block = 0; block < 4; block++) {
97		if ((xaui_cplx_mask & (1 << block)) == 0)
98			continue;
99
100		for (lane_ctrl = PHY_LANE_0_CTRL;
101		    lane_ctrl <= PHY_LANE_3_CTRL; lane_ctrl++) {
102			if (!nlm_is_xlp8xx_ax())
103				xlp_nae_lane_reset_txpll(nae_base,
104				    block, lane_ctrl, PHYMODE_XAUI);
105			else
106				xlp_ax_nae_lane_reset_txpll(nae_base, block,
107				    lane_ctrl, PHYMODE_XAUI);
108		}
109	}
110
111	/* Wait for Rx & TX clock stable */
112	for (block = 0; block < 4; block++) {
113		if ((xaui_cplx_mask & (1 << block)) == 0)
114			continue;
115
116		for (lane_ctrl = PHY_LANE_0_CTRL;
117		    lane_ctrl <= PHY_LANE_3_CTRL; lane_ctrl++) {
118
119			reg = NAE_REG(block, PHY, lane_ctrl - 4);
120			/* Wait for TX clock to be set */
121			do {
122				regval = nlm_read_nae_reg(nae_base, reg);
123			} while ((regval & LANE_TX_CLK) == 0);
124
125			/* Wait for RX clock to be set */
126			do {
127				regval = nlm_read_nae_reg(nae_base, reg);
128			} while ((regval & LANE_RX_CLK) == 0);
129
130			/* Wait for XAUI Lane fault to be cleared */
131			do {
132				regval = nlm_read_nae_reg(nae_base, reg);
133			} while ((regval & XAUI_LANE_FAULT) != 0);
134		}
135	}
136}
137
138void
139nlm_nae_setup_rx_mode_xaui(uint64_t base, int nblock, int iface, int port_type,
140    int broadcast_en, int multicast_en, int pause_en, int promisc_en)
141{
142	uint32_t val;
143
144	val = ((broadcast_en & 0x1) << 10)  |
145	    ((pause_en & 0x1) << 9)     |
146	    ((multicast_en & 0x1) << 8) |
147	    ((promisc_en & 0x1) << 7)   | /* unicast_enable - enables promisc mode */
148	    1; /* MAC address is always valid */
149
150	nlm_write_nae_reg(base, XAUI_MAC_FILTER_CFG(nblock), val);
151}
152
153void
154nlm_nae_setup_mac_addr_xaui(uint64_t base, int nblock, int iface,
155    int port_type, unsigned char *mac_addr)
156{
157	nlm_write_nae_reg(base,
158	    XAUI_MAC_ADDR0_LO(nblock),
159	    (mac_addr[5] << 24) |
160	    (mac_addr[4] << 16) |
161	    (mac_addr[3] << 8)  |
162	    mac_addr[2]);
163
164	nlm_write_nae_reg(base,
165	    XAUI_MAC_ADDR0_HI(nblock),
166	    (mac_addr[1] << 24) |
167	    (mac_addr[0] << 16));
168
169	nlm_write_nae_reg(base,
170	    XAUI_MAC_ADDR_MASK0_LO(nblock),
171	    0xffffffff);
172	nlm_write_nae_reg(base,
173	    XAUI_MAC_ADDR_MASK0_HI(nblock),
174	    0xffffffff);
175
176	nlm_nae_setup_rx_mode_xaui(base, nblock, iface,
177	    XAUIC,
178	    1, /* broadcast enabled */
179	    1, /* multicast enabled */
180	    0, /* do not accept pause frames */
181	    0 /* promisc mode disabled */
182	    );
183}
184
185void
186nlm_config_xaui_mtu(uint64_t nae_base, int nblock,
187    int max_tx_frame_sz, int max_rx_frame_sz)
188{
189	uint32_t tx_words = max_tx_frame_sz >> 2; /* max_tx_frame_sz / 4 */
190
191	/* write max frame length */
192	nlm_write_nae_reg(nae_base,
193	    XAUI_MAX_FRAME_LEN(nblock),
194	    ((tx_words & 0x3ff) << 16) | (max_rx_frame_sz & 0xffff));
195}
196
197void
198nlm_config_xaui(uint64_t nae_base, int nblock,
199    int max_tx_frame_sz, int max_rx_frame_sz, int vlan_pri_en)
200{
201	uint32_t val;
202
203	val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock));
204	val &= ~(0x1 << 11);	/* clear soft reset */
205	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val);
206
207	val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock));
208	val &= ~(0x3 << 11);	/* clear soft reset and hard reset */
209	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val);
210	nlm_write_nae_reg(nae_base, XAUI_CONFIG0(nblock), 0xffffffff);
211	nlm_write_nae_reg(nae_base, XAUI_CONFIG0(nblock), 0);
212
213	/* Enable tx/rx frame */
214	val = 0x000010A8;
215	val |= XAUI_CONFIG_LENCHK;
216	val |= XAUI_CONFIG_GENFCS;
217	val |= XAUI_CONFIG_PAD_64;
218	nlm_write_nae_reg(nae_base, XAUI_CONFIG1(nblock), val);
219
220	/* write max frame length */
221	nlm_config_xaui_mtu(nae_base, nblock, max_tx_frame_sz,
222	    max_rx_frame_sz);
223
224	/* set stats counter */
225	val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock));
226	val |= (0x1 << NETIOR_XGMAC_VLAN_DC_POS);
227	val |= (0x1 << NETIOR_XGMAC_STATS_EN_POS);
228	if (vlan_pri_en) {
229		val |= (0x1 << NETIOR_XGMAC_TX_PFC_EN_POS);
230		val |= (0x1 << NETIOR_XGMAC_RX_PFC_EN_POS);
231		val |= (0x1 << NETIOR_XGMAC_TX_PAUSE_POS);
232	} else {
233		val &= ~(0x1 << NETIOR_XGMAC_TX_PFC_EN_POS);
234		val |= (0x1 << NETIOR_XGMAC_TX_PAUSE_POS);
235	}
236	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val);
237	/* configure on / off timer */
238	if (vlan_pri_en)
239		val = 0xF1230000; /* PFC mode, offtimer = 0xf123, ontimer = 0 */
240	else
241		val = 0x0000F123; /* link level FC mode, offtimer = 0xf123 */
242	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL2(nblock), val);
243
244	/* set xaui tx threshold */
245	val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL3(nblock));
246	val &= ~(0x1f << 10);
247	val |= ~(15 << 10);
248	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL3(nblock), val);
249}
250