1233545Sjchandra/*-
2233545Sjchandra * Copyright (c) 2003-2012 Broadcom Corporation
3233545Sjchandra * All Rights Reserved
4233545Sjchandra *
5233545Sjchandra * Redistribution and use in source and binary forms, with or without
6233545Sjchandra * modification, are permitted provided that the following conditions
7233545Sjchandra * are met:
8233545Sjchandra *
9233545Sjchandra * 1. Redistributions of source code must retain the above copyright
10233545Sjchandra *    notice, this list of conditions and the following disclaimer.
11233545Sjchandra * 2. Redistributions in binary form must reproduce the above copyright
12233545Sjchandra *    notice, this list of conditions and the following disclaimer in
13233545Sjchandra *    the documentation and/or other materials provided with the
14233545Sjchandra *    distribution.
15279388Sjchandra *
16233545Sjchandra * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
17233545Sjchandra * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18233545Sjchandra * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19233545Sjchandra * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
20233545Sjchandra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21233545Sjchandra * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22233545Sjchandra * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23233545Sjchandra * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24233545Sjchandra * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25233545Sjchandra * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26233545Sjchandra * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27233545Sjchandra */
28233545Sjchandra
29233545Sjchandra#include <sys/cdefs.h>
30233545Sjchandra__FBSDID("$FreeBSD$");
31233545Sjchandra#include <sys/types.h>
32233545Sjchandra#include <sys/systm.h>
33233545Sjchandra
34233545Sjchandra#include <mips/nlm/hal/mips-extns.h>
35233545Sjchandra#include <mips/nlm/hal/haldefs.h>
36233545Sjchandra#include <mips/nlm/hal/iomap.h>
37233545Sjchandra#include <mips/nlm/hal/sys.h>
38233545Sjchandra#include <mips/nlm/hal/nae.h>
39233545Sjchandra#include <mips/nlm/hal/mdio.h>
40233545Sjchandra#include <mips/nlm/hal/sgmii.h>
41233545Sjchandra#include <mips/nlm/hal/xaui.h>
42233545Sjchandra
43233545Sjchandra#include <mips/nlm/xlp.h>
44233545Sjchandravoid
45233545Sjchandranlm_xaui_pcs_init(uint64_t nae_base, int xaui_cplx_mask)
46233545Sjchandra{
47233545Sjchandra	int block, lane_ctrl, reg;
48233545Sjchandra	int cplx_lane_enable;
49233545Sjchandra	int lane_enable = 0;
50233545Sjchandra	uint32_t regval;
51233545Sjchandra
52233545Sjchandra	cplx_lane_enable = LM_XAUI |
53233545Sjchandra	    (LM_XAUI << 4) |
54233545Sjchandra	    (LM_XAUI << 8) |
55233545Sjchandra	    (LM_XAUI << 12);
56233545Sjchandra
57233545Sjchandra	if (xaui_cplx_mask == 0)
58233545Sjchandra		return;
59233545Sjchandra
60233545Sjchandra	/* write 0x2 to enable SGMII for all lane */
61233545Sjchandra	block = 7;
62233545Sjchandra
63233545Sjchandra	if (xaui_cplx_mask & 0x3) { /* Complexes 0, 1 */
64233545Sjchandra		lane_enable = nlm_read_nae_reg(nae_base,
65233545Sjchandra		    NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_0_1));
66233545Sjchandra		if (xaui_cplx_mask & 0x1) { /* Complex 0 */
67233545Sjchandra			lane_enable &= ~(0xFFFF);
68233545Sjchandra			lane_enable |= cplx_lane_enable;
69233545Sjchandra		}
70233545Sjchandra		if (xaui_cplx_mask & 0x2) { /* Complex 1 */
71233545Sjchandra			lane_enable &= ~(0xFFFF<<16);
72233545Sjchandra			lane_enable |= (cplx_lane_enable << 16);
73233545Sjchandra		}
74233545Sjchandra		nlm_write_nae_reg(nae_base,
75233545Sjchandra		    NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_0_1),
76233545Sjchandra		    lane_enable);
77233545Sjchandra	}
78233545Sjchandra	lane_enable = 0;
79233545Sjchandra	if (xaui_cplx_mask & 0xc) { /* Complexes 2, 3 */
80233545Sjchandra		lane_enable = nlm_read_nae_reg(nae_base,
81233545Sjchandra		    NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_2_3));
82233545Sjchandra		if (xaui_cplx_mask & 0x4) { /* Complex 2 */
83233545Sjchandra			lane_enable &= ~(0xFFFF);
84233545Sjchandra			lane_enable |= cplx_lane_enable;
85233545Sjchandra		}
86233545Sjchandra		if (xaui_cplx_mask & 0x8) { /* Complex 3 */
87233545Sjchandra			lane_enable &= ~(0xFFFF<<16);
88233545Sjchandra			lane_enable |= (cplx_lane_enable << 16);
89233545Sjchandra		}
90233545Sjchandra		nlm_write_nae_reg(nae_base,
91233545Sjchandra		    NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_2_3),
92233545Sjchandra		    lane_enable);
93233545Sjchandra	}
94233545Sjchandra
95233545Sjchandra	/* Bring txpll out of reset */
96233545Sjchandra	for (block = 0; block < 4; block++) {
97233545Sjchandra		if ((xaui_cplx_mask & (1 << block)) == 0)
98233545Sjchandra			continue;
99233545Sjchandra
100233545Sjchandra		for (lane_ctrl = PHY_LANE_0_CTRL;
101233545Sjchandra		    lane_ctrl <= PHY_LANE_3_CTRL; lane_ctrl++) {
102233545Sjchandra			if (!nlm_is_xlp8xx_ax())
103233545Sjchandra				xlp_nae_lane_reset_txpll(nae_base,
104233545Sjchandra				    block, lane_ctrl, PHYMODE_XAUI);
105233545Sjchandra			else
106233545Sjchandra				xlp_ax_nae_lane_reset_txpll(nae_base, block,
107233545Sjchandra				    lane_ctrl, PHYMODE_XAUI);
108233545Sjchandra		}
109233545Sjchandra	}
110233545Sjchandra
111233545Sjchandra	/* Wait for Rx & TX clock stable */
112233545Sjchandra	for (block = 0; block < 4; block++) {
113233545Sjchandra		if ((xaui_cplx_mask & (1 << block)) == 0)
114233545Sjchandra			continue;
115233545Sjchandra
116233545Sjchandra		for (lane_ctrl = PHY_LANE_0_CTRL;
117233545Sjchandra		    lane_ctrl <= PHY_LANE_3_CTRL; lane_ctrl++) {
118233545Sjchandra
119233545Sjchandra			reg = NAE_REG(block, PHY, lane_ctrl - 4);
120233545Sjchandra			/* Wait for TX clock to be set */
121233545Sjchandra			do {
122233545Sjchandra				regval = nlm_read_nae_reg(nae_base, reg);
123233545Sjchandra			} while ((regval & LANE_TX_CLK) == 0);
124233545Sjchandra
125233545Sjchandra			/* Wait for RX clock to be set */
126233545Sjchandra			do {
127233545Sjchandra				regval = nlm_read_nae_reg(nae_base, reg);
128233545Sjchandra			} while ((regval & LANE_RX_CLK) == 0);
129233545Sjchandra
130233545Sjchandra			/* Wait for XAUI Lane fault to be cleared */
131233545Sjchandra			do {
132233545Sjchandra				regval = nlm_read_nae_reg(nae_base, reg);
133233545Sjchandra			} while ((regval & XAUI_LANE_FAULT) != 0);
134233545Sjchandra		}
135233545Sjchandra	}
136233545Sjchandra}
137233545Sjchandra
138233545Sjchandravoid
139233545Sjchandranlm_nae_setup_rx_mode_xaui(uint64_t base, int nblock, int iface, int port_type,
140233545Sjchandra    int broadcast_en, int multicast_en, int pause_en, int promisc_en)
141233545Sjchandra{
142233545Sjchandra	uint32_t val;
143233545Sjchandra
144233545Sjchandra	val = ((broadcast_en & 0x1) << 10)  |
145233545Sjchandra	    ((pause_en & 0x1) << 9)     |
146233545Sjchandra	    ((multicast_en & 0x1) << 8) |
147233545Sjchandra	    ((promisc_en & 0x1) << 7)   | /* unicast_enable - enables promisc mode */
148233545Sjchandra	    1; /* MAC address is always valid */
149233545Sjchandra
150233545Sjchandra	nlm_write_nae_reg(base, XAUI_MAC_FILTER_CFG(nblock), val);
151233545Sjchandra}
152233545Sjchandra
153233545Sjchandravoid
154233545Sjchandranlm_nae_setup_mac_addr_xaui(uint64_t base, int nblock, int iface,
155233545Sjchandra    int port_type, unsigned char *mac_addr)
156233545Sjchandra{
157233545Sjchandra	nlm_write_nae_reg(base,
158233545Sjchandra	    XAUI_MAC_ADDR0_LO(nblock),
159233545Sjchandra	    (mac_addr[5] << 24) |
160233545Sjchandra	    (mac_addr[4] << 16) |
161233545Sjchandra	    (mac_addr[3] << 8)  |
162233545Sjchandra	    mac_addr[2]);
163233545Sjchandra
164233545Sjchandra	nlm_write_nae_reg(base,
165233545Sjchandra	    XAUI_MAC_ADDR0_HI(nblock),
166233545Sjchandra	    (mac_addr[1] << 24) |
167233545Sjchandra	    (mac_addr[0] << 16));
168233545Sjchandra
169233545Sjchandra	nlm_write_nae_reg(base,
170233545Sjchandra	    XAUI_MAC_ADDR_MASK0_LO(nblock),
171233545Sjchandra	    0xffffffff);
172233545Sjchandra	nlm_write_nae_reg(base,
173233545Sjchandra	    XAUI_MAC_ADDR_MASK0_HI(nblock),
174233545Sjchandra	    0xffffffff);
175233545Sjchandra
176233545Sjchandra	nlm_nae_setup_rx_mode_xaui(base, nblock, iface,
177233545Sjchandra	    XAUIC,
178233545Sjchandra	    1, /* broadcast enabled */
179233545Sjchandra	    1, /* multicast enabled */
180233545Sjchandra	    0, /* do not accept pause frames */
181233545Sjchandra	    0 /* promisc mode disabled */
182233545Sjchandra	    );
183233545Sjchandra}
184233545Sjchandra
185233545Sjchandravoid
186233545Sjchandranlm_config_xaui_mtu(uint64_t nae_base, int nblock,
187233545Sjchandra    int max_tx_frame_sz, int max_rx_frame_sz)
188233545Sjchandra{
189233545Sjchandra	uint32_t tx_words = max_tx_frame_sz >> 2; /* max_tx_frame_sz / 4 */
190233545Sjchandra
191233545Sjchandra	/* write max frame length */
192233545Sjchandra	nlm_write_nae_reg(nae_base,
193233545Sjchandra	    XAUI_MAX_FRAME_LEN(nblock),
194233545Sjchandra	    ((tx_words & 0x3ff) << 16) | (max_rx_frame_sz & 0xffff));
195233545Sjchandra}
196233545Sjchandra
197233545Sjchandravoid
198233545Sjchandranlm_config_xaui(uint64_t nae_base, int nblock,
199233545Sjchandra    int max_tx_frame_sz, int max_rx_frame_sz, int vlan_pri_en)
200233545Sjchandra{
201233545Sjchandra	uint32_t val;
202233545Sjchandra
203233545Sjchandra	val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock));
204233545Sjchandra	val &= ~(0x1 << 11);	/* clear soft reset */
205233545Sjchandra	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val);
206233545Sjchandra
207233545Sjchandra	val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock));
208233545Sjchandra	val &= ~(0x3 << 11);	/* clear soft reset and hard reset */
209233545Sjchandra	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val);
210233545Sjchandra	nlm_write_nae_reg(nae_base, XAUI_CONFIG0(nblock), 0xffffffff);
211233545Sjchandra	nlm_write_nae_reg(nae_base, XAUI_CONFIG0(nblock), 0);
212233545Sjchandra
213233545Sjchandra	/* Enable tx/rx frame */
214255368Sjchandra	val = 0x000010A8;
215233545Sjchandra	val |= XAUI_CONFIG_LENCHK;
216233545Sjchandra	val |= XAUI_CONFIG_GENFCS;
217233545Sjchandra	val |= XAUI_CONFIG_PAD_64;
218233545Sjchandra	nlm_write_nae_reg(nae_base, XAUI_CONFIG1(nblock), val);
219233545Sjchandra
220233545Sjchandra	/* write max frame length */
221233545Sjchandra	nlm_config_xaui_mtu(nae_base, nblock, max_tx_frame_sz,
222233545Sjchandra	    max_rx_frame_sz);
223233545Sjchandra
224233545Sjchandra	/* set stats counter */
225233545Sjchandra	val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock));
226233545Sjchandra	val |= (0x1 << NETIOR_XGMAC_VLAN_DC_POS);
227233545Sjchandra	val |= (0x1 << NETIOR_XGMAC_STATS_EN_POS);
228233545Sjchandra	if (vlan_pri_en) {
229233545Sjchandra		val |= (0x1 << NETIOR_XGMAC_TX_PFC_EN_POS);
230233545Sjchandra		val |= (0x1 << NETIOR_XGMAC_RX_PFC_EN_POS);
231233545Sjchandra		val |= (0x1 << NETIOR_XGMAC_TX_PAUSE_POS);
232233545Sjchandra	} else {
233233545Sjchandra		val &= ~(0x1 << NETIOR_XGMAC_TX_PFC_EN_POS);
234233545Sjchandra		val |= (0x1 << NETIOR_XGMAC_TX_PAUSE_POS);
235233545Sjchandra	}
236233545Sjchandra	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val);
237233545Sjchandra	/* configure on / off timer */
238233545Sjchandra	if (vlan_pri_en)
239233545Sjchandra		val = 0xF1230000; /* PFC mode, offtimer = 0xf123, ontimer = 0 */
240233545Sjchandra	else
241233545Sjchandra		val = 0x0000F123; /* link level FC mode, offtimer = 0xf123 */
242233545Sjchandra	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL2(nblock), val);
243233545Sjchandra
244233545Sjchandra	/* set xaui tx threshold */
245233545Sjchandra	val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL3(nblock));
246233545Sjchandra	val &= ~(0x1f << 10);
247233545Sjchandra	val |= ~(15 << 10);
248233545Sjchandra	nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL3(nblock), val);
249233545Sjchandra}
250