xref: /onnv-gate/usr/src/uts/common/io/chxge/com/mc4.c (revision 3833:45d8d0ee8613)
1*3833Sxw161283 /*
2*3833Sxw161283  * CDDL HEADER START
3*3833Sxw161283  *
4*3833Sxw161283  * The contents of this file are subject to the terms of the
5*3833Sxw161283  * Common Development and Distribution License (the "License").
6*3833Sxw161283  * You may not use this file except in compliance with the License.
7*3833Sxw161283  *
8*3833Sxw161283  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3833Sxw161283  * or http://www.opensolaris.org/os/licensing.
10*3833Sxw161283  * See the License for the specific language governing permissions
11*3833Sxw161283  * and limitations under the License.
12*3833Sxw161283  *
13*3833Sxw161283  * When distributing Covered Code, include this CDDL HEADER in each
14*3833Sxw161283  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3833Sxw161283  * If applicable, add the following below this CDDL HEADER, with the
16*3833Sxw161283  * fields enclosed by brackets "[]" replaced with your own identifying
17*3833Sxw161283  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3833Sxw161283  *
19*3833Sxw161283  * CDDL HEADER END
20*3833Sxw161283  */
21*3833Sxw161283 
22*3833Sxw161283 /*
23*3833Sxw161283  * This file is part of the Chelsio T1 Ethernet driver.
24*3833Sxw161283  *
25*3833Sxw161283  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
26*3833Sxw161283  */
27*3833Sxw161283 
28*3833Sxw161283 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* mc4.c */
29*3833Sxw161283 
30*3833Sxw161283 #include "common.h"
31*3833Sxw161283 #include "regs.h"
32*3833Sxw161283 #include "mc4.h"
33*3833Sxw161283 
34*3833Sxw161283 struct pemc4 {
35*3833Sxw161283 	adapter_t *adapter;
36*3833Sxw161283 	unsigned int size;
37*3833Sxw161283 	unsigned int nwords;           /* MC4 width in terms of 32-bit words */
38*3833Sxw161283 	struct pemc4_intr_counts intr_cnt;
39*3833Sxw161283 };
40*3833Sxw161283 
t1_mc4_destroy(struct pemc4 * mc4)41*3833Sxw161283 void t1_mc4_destroy(struct pemc4 *mc4)
42*3833Sxw161283 {
43*3833Sxw161283 	t1_os_free((void *)mc4, sizeof(*mc4));
44*3833Sxw161283 }
45*3833Sxw161283 
46*3833Sxw161283 #define is_MC4A(adapter) (!t1_is_T1B(adapter))
47*3833Sxw161283 
48*3833Sxw161283 /* Calculate amount of MC4 memory. */
mc4_calc_size(adapter_t * adapter)49*3833Sxw161283 static unsigned int __devinit mc4_calc_size(adapter_t *adapter)
50*3833Sxw161283 {
51*3833Sxw161283 	u32 mc4_cfg = t1_read_reg_4(adapter, A_MC4_CFG);
52*3833Sxw161283 	unsigned int width = is_MC4A(adapter) ? G_MC4A_WIDTH(mc4_cfg) :
53*3833Sxw161283 		                                !!(mc4_cfg & F_MC4_NARROW);
54*3833Sxw161283 
55*3833Sxw161283 	return (256 * 1024 * 1024) >> width;
56*3833Sxw161283 }
57*3833Sxw161283 
58*3833Sxw161283 /*
59*3833Sxw161283  * Write a value to a register and check that the write completed.  These
60*3833Sxw161283  * writes normally complete in a cycle or two, so one read should suffice but
61*3833Sxw161283  * just in case we give them a bit of grace period.  Note that the very first
62*3833Sxw161283  * read exists to flush the posted write to the device.
63*3833Sxw161283  */
wrreg_wait(adapter_t * adapter,unsigned int addr,u32 val)64*3833Sxw161283 static int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val)
65*3833Sxw161283 {
66*3833Sxw161283 	int attempts = 2;
67*3833Sxw161283 
68*3833Sxw161283 	t1_write_reg_4(adapter,	addr, val);
69*3833Sxw161283 	val = t1_read_reg_4(adapter, addr);                   /* flush */
70*3833Sxw161283 	while (attempts--) {
71*3833Sxw161283 		if (!(t1_read_reg_4(adapter, addr) & F_BUSY))
72*3833Sxw161283 			return 0;
73*3833Sxw161283 		if (attempts)
74*3833Sxw161283 			DELAY_US(1);
75*3833Sxw161283 	}
76*3833Sxw161283 	CH_ERR("%s: write to MC4 register 0x%x timed out\n",
77*3833Sxw161283 	       adapter_name(adapter), addr);
78*3833Sxw161283 	return -EIO;
79*3833Sxw161283 }
80*3833Sxw161283 
81*3833Sxw161283 #define MC4_DLL_DONE (F_MASTER_DLL_LOCKED | F_MASTER_DLL_MAX_TAP_COUNT)
82*3833Sxw161283 
t1_mc4_init(struct pemc4 * mc4,unsigned int mc4_clock)83*3833Sxw161283 int t1_mc4_init(struct pemc4 *mc4, unsigned int mc4_clock)
84*3833Sxw161283 {
85*3833Sxw161283 	int attempts;
86*3833Sxw161283 	u32 val;
87*3833Sxw161283 	unsigned int width, ext_mode, slow_mode;
88*3833Sxw161283 	adapter_t *adapter = mc4->adapter;
89*3833Sxw161283 
90*3833Sxw161283 	/* Power up the FCRAMs. */
91*3833Sxw161283 	val = t1_read_reg_4(adapter, A_MC4_CFG);
92*3833Sxw161283 	t1_write_reg_4(adapter, A_MC4_CFG, val | F_POWER_UP);
93*3833Sxw161283 	val = t1_read_reg_4(adapter, A_MC4_CFG);               /* flush */
94*3833Sxw161283 
95*3833Sxw161283 	if (is_MC4A(adapter)) {
96*3833Sxw161283 		slow_mode = val & F_MC4A_SLOW;
97*3833Sxw161283 		width = G_MC4A_WIDTH(val);
98*3833Sxw161283 
99*3833Sxw161283 		/* If we're not in slow mode, we are using the DLLs */
100*3833Sxw161283 		if (!slow_mode) {
101*3833Sxw161283 			/* Clear Reset */
102*3833Sxw161283 			val = t1_read_reg_4(adapter, A_MC4_STROBE);
103*3833Sxw161283 			t1_write_reg_4(adapter, A_MC4_STROBE,
104*3833Sxw161283 				       val & ~F_SLAVE_DLL_RESET);
105*3833Sxw161283 
106*3833Sxw161283 			/* Wait for slave DLLs to lock */
107*3833Sxw161283 			DELAY_US(2 * 512 / (mc4_clock / 1000000) + 1);
108*3833Sxw161283 		}
109*3833Sxw161283 	} else {
110*3833Sxw161283 		slow_mode = val & F_MC4_SLOW;
111*3833Sxw161283 		width = !!(val & F_MC4_NARROW);
112*3833Sxw161283 
113*3833Sxw161283 		/* Initializes the master DLL and slave delay lines. */
114*3833Sxw161283 		if (t1_is_asic(adapter) && !slow_mode) {
115*3833Sxw161283 			val = t1_read_reg_4(adapter, A_MC4_STROBE);
116*3833Sxw161283 			t1_write_reg_4(adapter, A_MC4_STROBE,
117*3833Sxw161283 				       val & ~F_MASTER_DLL_RESET);
118*3833Sxw161283 
119*3833Sxw161283 			/* Wait for the master DLL to lock. */
120*3833Sxw161283 			attempts = 100;
121*3833Sxw161283 			do {
122*3833Sxw161283 				DELAY_US(1);
123*3833Sxw161283 				val = t1_read_reg_4(adapter, A_MC4_STROBE);
124*3833Sxw161283 			} while (!(val & MC4_DLL_DONE) && --attempts);
125*3833Sxw161283 			if (!(val & MC4_DLL_DONE)) {
126*3833Sxw161283 				CH_ERR("%s: MC4 DLL lock failed\n",
127*3833Sxw161283 				       adapter_name(adapter));
128*3833Sxw161283 				goto out_fail;
129*3833Sxw161283 			}
130*3833Sxw161283 		}
131*3833Sxw161283 	}
132*3833Sxw161283 
133*3833Sxw161283 	mc4->nwords = 4 >> width;
134*3833Sxw161283 
135*3833Sxw161283 	/* Set the FCRAM output drive strength and enable DLLs if needed */
136*3833Sxw161283 	ext_mode = t1_is_asic(adapter) && !slow_mode ? 0 : 1;
137*3833Sxw161283 	if (wrreg_wait(adapter, A_MC4_EXT_MODE, ext_mode))
138*3833Sxw161283 		goto out_fail;
139*3833Sxw161283 
140*3833Sxw161283 	/* Specify the FCRAM operating parameters */
141*3833Sxw161283 	if (wrreg_wait(adapter, A_MC4_MODE, 0x32))
142*3833Sxw161283 		goto out_fail;
143*3833Sxw161283 
144*3833Sxw161283 	/* Initiate an immediate refresh and wait for the write to complete. */
145*3833Sxw161283 	val = t1_read_reg_4(adapter, A_MC4_REFRESH);
146*3833Sxw161283 	if (wrreg_wait(adapter, A_MC4_REFRESH, val & ~F_REFRESH_ENABLE))
147*3833Sxw161283 		goto out_fail;
148*3833Sxw161283 
149*3833Sxw161283 	/* 2nd immediate refresh as before */
150*3833Sxw161283 	if (wrreg_wait(adapter, A_MC4_REFRESH, val & ~F_REFRESH_ENABLE))
151*3833Sxw161283 		goto out_fail;
152*3833Sxw161283 
153*3833Sxw161283 	/* Convert to KHz first to avoid 64-bit division. */
154*3833Sxw161283 	mc4_clock /= 1000;                            /* Hz->KHz */
155*3833Sxw161283 	mc4_clock = mc4_clock * 7812 + mc4_clock / 2; /* ns */
156*3833Sxw161283 	mc4_clock /= 1000000;                         /* KHz->MHz, ns->us */
157*3833Sxw161283 
158*3833Sxw161283 	/* Enable periodic refresh. */
159*3833Sxw161283 	t1_write_reg_4(adapter, A_MC4_REFRESH,
160*3833Sxw161283 		       F_REFRESH_ENABLE | V_REFRESH_DIVISOR(mc4_clock));
161*3833Sxw161283 	(void) t1_read_reg_4(adapter, A_MC4_REFRESH);    /* flush */
162*3833Sxw161283 
163*3833Sxw161283 	t1_write_reg_4(adapter, A_MC4_ECC_CNTL,
164*3833Sxw161283 		       F_ECC_GENERATION_ENABLE | F_ECC_CHECK_ENABLE);
165*3833Sxw161283 
166*3833Sxw161283 	/* Use the BIST engine to clear all of the MC4 memory. */
167*3833Sxw161283 	t1_write_reg_4(adapter, A_MC4_BIST_ADDR_BEG, 0);
168*3833Sxw161283 	t1_write_reg_4(adapter, A_MC4_BIST_ADDR_END, (mc4->size << width) - 1);
169*3833Sxw161283 	t1_write_reg_4(adapter, A_MC4_BIST_DATA, 0);
170*3833Sxw161283 	t1_write_reg_4(adapter, A_MC4_BIST_OP, V_OP(1) | 0x1f0);
171*3833Sxw161283 	(void) t1_read_reg_4(adapter, A_MC4_BIST_OP);              /* flush */
172*3833Sxw161283 
173*3833Sxw161283 	attempts = 100;
174*3833Sxw161283 	do {
175*3833Sxw161283 		DELAY_MS(100);
176*3833Sxw161283 		val = t1_read_reg_4(adapter, A_MC4_BIST_OP);
177*3833Sxw161283 	} while ((val & F_BUSY) && --attempts);
178*3833Sxw161283 	if (val & F_BUSY) {
179*3833Sxw161283 		CH_ERR("%s: MC4 BIST timed out\n", adapter_name(adapter));
180*3833Sxw161283 		goto out_fail;
181*3833Sxw161283 	}
182*3833Sxw161283 
183*3833Sxw161283 	/* Enable normal memory accesses. */
184*3833Sxw161283 	val = t1_read_reg_4(adapter, A_MC4_CFG);
185*3833Sxw161283 	t1_write_reg_4(adapter, A_MC4_CFG, val | F_READY);
186*3833Sxw161283 	val = t1_read_reg_4(adapter, A_MC4_CFG);               /* flush */
187*3833Sxw161283 	return 0;
188*3833Sxw161283 
189*3833Sxw161283  out_fail:
190*3833Sxw161283 	return -1;
191*3833Sxw161283 }
192*3833Sxw161283 
t1_mc4_create(adapter_t * adapter)193*3833Sxw161283 struct pemc4 * __devinit t1_mc4_create(adapter_t *adapter)
194*3833Sxw161283 {
195*3833Sxw161283 	struct pemc4 *mc4 = t1_os_malloc_wait_zero(sizeof(*mc4));
196*3833Sxw161283 
197*3833Sxw161283 	if (mc4) {
198*3833Sxw161283 		mc4->adapter = adapter;
199*3833Sxw161283 		mc4->size = mc4_calc_size(adapter);
200*3833Sxw161283 	}
201*3833Sxw161283 	return mc4;
202*3833Sxw161283 }
203*3833Sxw161283 
t1_mc4_get_size(struct pemc4 * mc4)204*3833Sxw161283 unsigned int t1_mc4_get_size(struct pemc4 *mc4)
205*3833Sxw161283 {
206*3833Sxw161283 	return mc4->size;
207*3833Sxw161283 }
208*3833Sxw161283 
209*3833Sxw161283 #define MC4_INT_MASK (F_MC4_CORR_ERR | F_MC4_UNCORR_ERR | F_MC4_ADDR_ERR)
210*3833Sxw161283 #define MC4_INT_FATAL (F_MC4_UNCORR_ERR | F_MC4_ADDR_ERR)
211*3833Sxw161283 
t1_mc4_intr_enable(struct pemc4 * mc4)212*3833Sxw161283 void t1_mc4_intr_enable(struct pemc4 *mc4)
213*3833Sxw161283 {
214*3833Sxw161283 	u32 pl_intr;
215*3833Sxw161283 
216*3833Sxw161283 	if (t1_is_asic(mc4->adapter)) {
217*3833Sxw161283 		t1_write_reg_4(mc4->adapter, A_MC4_INT_ENABLE, MC4_INT_MASK);
218*3833Sxw161283 
219*3833Sxw161283 		pl_intr = t1_read_reg_4(mc4->adapter, A_PL_ENABLE);
220*3833Sxw161283 		t1_write_reg_4(mc4->adapter, A_PL_ENABLE,
221*3833Sxw161283 			       pl_intr | F_PL_INTR_MC4);
222*3833Sxw161283 	}
223*3833Sxw161283 }
224*3833Sxw161283 
t1_mc4_intr_disable(struct pemc4 * mc4)225*3833Sxw161283 void t1_mc4_intr_disable(struct pemc4 *mc4)
226*3833Sxw161283 {
227*3833Sxw161283 	u32 pl_intr;
228*3833Sxw161283 
229*3833Sxw161283 	if (t1_is_asic(mc4->adapter)) {
230*3833Sxw161283 		t1_write_reg_4(mc4->adapter, A_MC4_INT_ENABLE, 0);
231*3833Sxw161283 
232*3833Sxw161283 		pl_intr = t1_read_reg_4(mc4->adapter, A_PL_ENABLE);
233*3833Sxw161283 		t1_write_reg_4(mc4->adapter, A_PL_ENABLE,
234*3833Sxw161283 			       pl_intr & ~F_PL_INTR_MC4);
235*3833Sxw161283 	}
236*3833Sxw161283 }
237*3833Sxw161283 
t1_mc4_intr_clear(struct pemc4 * mc4)238*3833Sxw161283 void t1_mc4_intr_clear(struct pemc4 *mc4)
239*3833Sxw161283 {
240*3833Sxw161283 	if (t1_is_asic(mc4->adapter)) {
241*3833Sxw161283 		t1_write_reg_4(mc4->adapter, A_MC4_INT_CAUSE, 0xffffffff);
242*3833Sxw161283 		t1_write_reg_4(mc4->adapter, A_PL_CAUSE, F_PL_INTR_MC4);
243*3833Sxw161283 	}
244*3833Sxw161283 }
245*3833Sxw161283 
t1_mc4_intr_handler(struct pemc4 * mc4)246*3833Sxw161283 int t1_mc4_intr_handler(struct pemc4 *mc4)
247*3833Sxw161283 {
248*3833Sxw161283 	adapter_t *adapter = mc4->adapter;
249*3833Sxw161283 	u32 cause = t1_read_reg_4(adapter, A_MC4_INT_CAUSE);
250*3833Sxw161283 
251*3833Sxw161283 	if (cause & F_MC4_CORR_ERR) {
252*3833Sxw161283 		mc4->intr_cnt.corr_err++;
253*3833Sxw161283 		CH_WARN("%s: MC4 correctable error at addr 0x%x, "
254*3833Sxw161283 			"data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
255*3833Sxw161283 			adapter_name(adapter),
256*3833Sxw161283 			G_MC4_CE_ADDR(t1_read_reg_4(adapter, A_MC4_CE_ADDR)),
257*3833Sxw161283 			t1_read_reg_4(adapter, A_MC4_CE_DATA0),
258*3833Sxw161283 			t1_read_reg_4(adapter, A_MC4_CE_DATA1),
259*3833Sxw161283 			t1_read_reg_4(adapter, A_MC4_CE_DATA2),
260*3833Sxw161283 			t1_read_reg_4(adapter, A_MC4_CE_DATA3),
261*3833Sxw161283 			t1_read_reg_4(adapter, A_MC4_CE_DATA4));
262*3833Sxw161283 	}
263*3833Sxw161283 
264*3833Sxw161283 	if (cause & F_MC4_UNCORR_ERR) {
265*3833Sxw161283 		mc4->intr_cnt.uncorr_err++;
266*3833Sxw161283 		CH_ALERT("%s: MC4 uncorrectable error at addr 0x%x, "
267*3833Sxw161283 			 "data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
268*3833Sxw161283 			 adapter_name(adapter),
269*3833Sxw161283 			 G_MC4_UE_ADDR(t1_read_reg_4(adapter, A_MC4_UE_ADDR)),
270*3833Sxw161283 			 t1_read_reg_4(adapter, A_MC4_UE_DATA0),
271*3833Sxw161283 			 t1_read_reg_4(adapter, A_MC4_UE_DATA1),
272*3833Sxw161283 			 t1_read_reg_4(adapter, A_MC4_UE_DATA2),
273*3833Sxw161283 			 t1_read_reg_4(adapter, A_MC4_UE_DATA3),
274*3833Sxw161283 			 t1_read_reg_4(adapter, A_MC4_UE_DATA4));
275*3833Sxw161283 	}
276*3833Sxw161283 
277*3833Sxw161283 	if (cause & F_MC4_ADDR_ERR) {
278*3833Sxw161283 		mc4->intr_cnt.addr_err++;
279*3833Sxw161283 		CH_ALERT("%s: MC4 address error\n", adapter_name(adapter));
280*3833Sxw161283 	}
281*3833Sxw161283 
282*3833Sxw161283 	if (cause & MC4_INT_FATAL)
283*3833Sxw161283 		t1_fatal_err(adapter);
284*3833Sxw161283 
285*3833Sxw161283 	t1_write_reg_4(mc4->adapter, A_MC4_INT_CAUSE, cause);
286*3833Sxw161283 	return 0;
287*3833Sxw161283 }
288*3833Sxw161283 
t1_mc4_get_intr_counts(struct pemc4 * mc4)289*3833Sxw161283 const struct pemc4_intr_counts *t1_mc4_get_intr_counts(struct pemc4 *mc4)
290*3833Sxw161283 {
291*3833Sxw161283 	return &mc4->intr_cnt;
292*3833Sxw161283 }
293*3833Sxw161283 
294*3833Sxw161283 /*
295*3833Sxw161283  * Read n 256-bit words from MC4 starting at word start, using backdoor
296*3833Sxw161283  * accesses.
297*3833Sxw161283  */
t1_mc4_bd_read(struct pemc4 * mc4,unsigned int start,unsigned int n,u32 * buf)298*3833Sxw161283 int t1_mc4_bd_read(struct pemc4 *mc4, unsigned int start, unsigned int n,
299*3833Sxw161283 		   u32 *buf)
300*3833Sxw161283 {
301*3833Sxw161283 	adapter_t *adap = mc4->adapter;
302*3833Sxw161283 	unsigned int size256 = mc4->size / 32, c = 8 / mc4->nwords, i;
303*3833Sxw161283 
304*3833Sxw161283 	if (start >= size256 || start + n > size256)
305*3833Sxw161283 		return -EINVAL;
306*3833Sxw161283 
307*3833Sxw161283 	for (i = 8, start *= 16 * c, n *= c; n; --n, start += 16) {
308*3833Sxw161283 		int attempts = 10;
309*3833Sxw161283 		u32 val;
310*3833Sxw161283 
311*3833Sxw161283 		t1_write_reg_4(adap, A_MC4_BD_ADDR, start);
312*3833Sxw161283 		t1_write_reg_4(adap, A_MC4_BD_OP, 0);
313*3833Sxw161283 		val = t1_read_reg_4(adap, A_MC4_BD_OP);
314*3833Sxw161283 		while ((val & F_BUSY) && attempts--)
315*3833Sxw161283 			val = t1_read_reg_4(adap, A_MC4_BD_OP);
316*3833Sxw161283 
317*3833Sxw161283 		if (val & F_BUSY)
318*3833Sxw161283 			return -EIO;
319*3833Sxw161283 
320*3833Sxw161283 		buf[--i] = t1_read_reg_4(adap, A_MC4_BD_DATA3);
321*3833Sxw161283 		if (mc4->nwords >= 2)
322*3833Sxw161283 			buf[--i] = t1_read_reg_4(adap, A_MC4_BD_DATA2);
323*3833Sxw161283 		if (mc4->nwords == 4) {
324*3833Sxw161283 			buf[--i] = t1_read_reg_4(adap, A_MC4_BD_DATA1);
325*3833Sxw161283 			buf[--i] = t1_read_reg_4(adap, A_MC4_BD_DATA0);
326*3833Sxw161283 		}
327*3833Sxw161283 		if (i == 0) {
328*3833Sxw161283 			i = 8;
329*3833Sxw161283 			buf += 8;
330*3833Sxw161283 		}
331*3833Sxw161283 	}
332*3833Sxw161283 	return 0;
333*3833Sxw161283 }
334