xref: /illumos-gate/usr/src/uts/common/io/chxge/com/mc3.c (revision 2d6eb4a5e0a47d30189497241345dc5466bb68ab)
1*d39a76e7Sxw161283 /*
2*d39a76e7Sxw161283  * CDDL HEADER START
3*d39a76e7Sxw161283  *
4*d39a76e7Sxw161283  * The contents of this file are subject to the terms of the
5*d39a76e7Sxw161283  * Common Development and Distribution License (the "License").
6*d39a76e7Sxw161283  * You may not use this file except in compliance with the License.
7*d39a76e7Sxw161283  *
8*d39a76e7Sxw161283  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d39a76e7Sxw161283  * or http://www.opensolaris.org/os/licensing.
10*d39a76e7Sxw161283  * See the License for the specific language governing permissions
11*d39a76e7Sxw161283  * and limitations under the License.
12*d39a76e7Sxw161283  *
13*d39a76e7Sxw161283  * When distributing Covered Code, include this CDDL HEADER in each
14*d39a76e7Sxw161283  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d39a76e7Sxw161283  * If applicable, add the following below this CDDL HEADER, with the
16*d39a76e7Sxw161283  * fields enclosed by brackets "[]" replaced with your own identifying
17*d39a76e7Sxw161283  * information: Portions Copyright [yyyy] [name of copyright owner]
18*d39a76e7Sxw161283  *
19*d39a76e7Sxw161283  * CDDL HEADER END
20*d39a76e7Sxw161283  */
21*d39a76e7Sxw161283 
22*d39a76e7Sxw161283 /*
23*d39a76e7Sxw161283  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
24*d39a76e7Sxw161283  */
25*d39a76e7Sxw161283 
26*d39a76e7Sxw161283 #include "common.h"
27*d39a76e7Sxw161283 #include "regs.h"
28*d39a76e7Sxw161283 #include "mc3.h"
29*d39a76e7Sxw161283 
30*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
31*d39a76e7Sxw161283 # include "fpga_defs.h"
32*d39a76e7Sxw161283 #endif
33*d39a76e7Sxw161283 
34*d39a76e7Sxw161283 struct pemc3 {
35*d39a76e7Sxw161283 	adapter_t *adapter;
36*d39a76e7Sxw161283 	unsigned int size;
37*d39a76e7Sxw161283 	struct pemc3_intr_counts intr_cnt;
38*d39a76e7Sxw161283 };
39*d39a76e7Sxw161283 
40*d39a76e7Sxw161283 #define MC3_INTR_MASK (F_MC3_CORR_ERR | F_MC3_UNCORR_ERR | \
41*d39a76e7Sxw161283 		       V_MC3_PARITY_ERR(M_MC3_PARITY_ERR) | F_MC3_ADDR_ERR)
42*d39a76e7Sxw161283 #define MC3_INTR_FATAL (F_MC3_UNCORR_ERR | V_MC3_PARITY_ERR(M_MC3_PARITY_ERR) | F_MC3_ADDR_ERR)
43*d39a76e7Sxw161283 
t1_mc3_intr_enable(struct pemc3 * mc3)44*d39a76e7Sxw161283 void t1_mc3_intr_enable(struct pemc3 *mc3)
45*d39a76e7Sxw161283 {
46*d39a76e7Sxw161283 	u32 en = t1_read_reg_4(mc3->adapter, A_PL_ENABLE);
47*d39a76e7Sxw161283 
48*d39a76e7Sxw161283 	if (t1_is_asic(mc3->adapter)) {
49*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, MC3_INTR_MASK);
50*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, A_PL_ENABLE, en | F_PL_INTR_MC3);
51*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
52*d39a76e7Sxw161283 	} else {
53*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRENABLE,
54*d39a76e7Sxw161283 			       MC3_INTR_MASK);
55*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, A_PL_ENABLE,
56*d39a76e7Sxw161283 			       en | FPGA_PCIX_INTERRUPT_MC3);
57*d39a76e7Sxw161283 #endif
58*d39a76e7Sxw161283 	}
59*d39a76e7Sxw161283 }
60*d39a76e7Sxw161283 
t1_mc3_intr_disable(struct pemc3 * mc3)61*d39a76e7Sxw161283 void t1_mc3_intr_disable(struct pemc3 *mc3)
62*d39a76e7Sxw161283 {
63*d39a76e7Sxw161283 	u32 pl_intr = t1_read_reg_4(mc3->adapter, A_PL_ENABLE);
64*d39a76e7Sxw161283 
65*d39a76e7Sxw161283 	if (t1_is_asic(mc3->adapter)) {
66*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, 0);
67*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, A_PL_ENABLE,
68*d39a76e7Sxw161283 			       pl_intr & ~F_PL_INTR_MC3);
69*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
70*d39a76e7Sxw161283 	} else {
71*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRENABLE, 0);
72*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, A_PL_ENABLE,
73*d39a76e7Sxw161283 			       pl_intr & ~FPGA_PCIX_INTERRUPT_MC3);
74*d39a76e7Sxw161283 #endif
75*d39a76e7Sxw161283 	}
76*d39a76e7Sxw161283 }
77*d39a76e7Sxw161283 
t1_mc3_intr_clear(struct pemc3 * mc3)78*d39a76e7Sxw161283 void t1_mc3_intr_clear(struct pemc3 *mc3)
79*d39a76e7Sxw161283 {
80*d39a76e7Sxw161283 	if (t1_is_asic(mc3->adapter)) {
81*d39a76e7Sxw161283 		if (t1_is_T1B(mc3->adapter)) {
82*d39a76e7Sxw161283 			/*
83*d39a76e7Sxw161283 			 * Workaround for T1B bug: we must write to enable
84*d39a76e7Sxw161283 			 * register to clear interrupts.
85*d39a76e7Sxw161283 			 */
86*d39a76e7Sxw161283 			u32 old_en;
87*d39a76e7Sxw161283 
88*d39a76e7Sxw161283 			old_en = t1_read_reg_4(mc3->adapter, A_MC3_INT_ENABLE);
89*d39a76e7Sxw161283 			t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE,
90*d39a76e7Sxw161283 				       0xffffffff);
91*d39a76e7Sxw161283 			t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, old_en);
92*d39a76e7Sxw161283 		} else
93*d39a76e7Sxw161283 			t1_write_reg_4(mc3->adapter, A_MC3_INT_CAUSE,
94*d39a76e7Sxw161283 				       0xffffffff);
95*d39a76e7Sxw161283 
96*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, A_PL_CAUSE, F_PL_INTR_MC3);
97*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
98*d39a76e7Sxw161283 	} else {
99*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRCAUSE,
100*d39a76e7Sxw161283 			       0xffffffff);
101*d39a76e7Sxw161283 		t1_write_reg_4(mc3->adapter, A_PL_CAUSE,
102*d39a76e7Sxw161283 			       FPGA_PCIX_INTERRUPT_MC3);
103*d39a76e7Sxw161283 #endif
104*d39a76e7Sxw161283 	}
105*d39a76e7Sxw161283 }
106*d39a76e7Sxw161283 
t1_mc3_intr_handler(struct pemc3 * mc3)107*d39a76e7Sxw161283 int t1_mc3_intr_handler(struct pemc3 *mc3)
108*d39a76e7Sxw161283 {
109*d39a76e7Sxw161283 	adapter_t *adapter = mc3->adapter;
110*d39a76e7Sxw161283 	int cause_reg = A_MC3_INT_CAUSE;
111*d39a76e7Sxw161283 	u32 cause;
112*d39a76e7Sxw161283 
113*d39a76e7Sxw161283 #ifdef CONFIG_CHELSIO_T1_1G
114*d39a76e7Sxw161283 	if (!t1_is_asic(adapter))
115*d39a76e7Sxw161283 		cause_reg = FPGA_MC3_REG_INTRCAUSE;
116*d39a76e7Sxw161283 #endif
117*d39a76e7Sxw161283 	cause = t1_read_reg_4(adapter, cause_reg);
118*d39a76e7Sxw161283 
119*d39a76e7Sxw161283 	if (cause & F_MC3_CORR_ERR) {
120*d39a76e7Sxw161283 		mc3->intr_cnt.corr_err++;
121*d39a76e7Sxw161283 		CH_WARN("%s: MC3 correctable error at addr 0x%x, "
122*d39a76e7Sxw161283 			"data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
123*d39a76e7Sxw161283 			adapter_name(adapter),
124*d39a76e7Sxw161283 			G_MC3_CE_ADDR(t1_read_reg_4(adapter, A_MC3_CE_ADDR)),
125*d39a76e7Sxw161283 			t1_read_reg_4(adapter, A_MC3_CE_DATA0),
126*d39a76e7Sxw161283 			t1_read_reg_4(adapter, A_MC3_CE_DATA1),
127*d39a76e7Sxw161283 			t1_read_reg_4(adapter, A_MC3_CE_DATA2),
128*d39a76e7Sxw161283 			t1_read_reg_4(adapter, A_MC3_CE_DATA3),
129*d39a76e7Sxw161283 			t1_read_reg_4(adapter, A_MC3_CE_DATA4));
130*d39a76e7Sxw161283 	}
131*d39a76e7Sxw161283 
132*d39a76e7Sxw161283 	if (cause & F_MC3_UNCORR_ERR) {
133*d39a76e7Sxw161283 		mc3->intr_cnt.uncorr_err++;
134*d39a76e7Sxw161283 		CH_ALERT("%s: MC3 uncorrectable error at addr 0x%x, "
135*d39a76e7Sxw161283 			 "data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
136*d39a76e7Sxw161283 			 adapter_name(adapter),
137*d39a76e7Sxw161283 			 G_MC3_UE_ADDR(t1_read_reg_4(adapter, A_MC3_UE_ADDR)),
138*d39a76e7Sxw161283 			 t1_read_reg_4(adapter, A_MC3_UE_DATA0),
139*d39a76e7Sxw161283 			 t1_read_reg_4(adapter, A_MC3_UE_DATA1),
140*d39a76e7Sxw161283 			 t1_read_reg_4(adapter, A_MC3_UE_DATA2),
141*d39a76e7Sxw161283 			 t1_read_reg_4(adapter, A_MC3_UE_DATA3),
142*d39a76e7Sxw161283 			 t1_read_reg_4(adapter, A_MC3_UE_DATA4));
143*d39a76e7Sxw161283 	}
144*d39a76e7Sxw161283 
145*d39a76e7Sxw161283 	if (G_MC3_PARITY_ERR(cause)) {
146*d39a76e7Sxw161283 		mc3->intr_cnt.parity_err++;
147*d39a76e7Sxw161283 		CH_ALERT("%s: MC3 parity error 0x%x\n", adapter_name(adapter),
148*d39a76e7Sxw161283 			 G_MC3_PARITY_ERR(cause));
149*d39a76e7Sxw161283 	}
150*d39a76e7Sxw161283 
151*d39a76e7Sxw161283 	if (cause & F_MC3_ADDR_ERR) {
152*d39a76e7Sxw161283 		mc3->intr_cnt.addr_err++;
153*d39a76e7Sxw161283 		CH_ALERT("%s: MC3 address error\n", adapter_name(adapter));
154*d39a76e7Sxw161283 	}
155*d39a76e7Sxw161283 
156*d39a76e7Sxw161283 	if (cause & MC3_INTR_FATAL)
157*d39a76e7Sxw161283 		t1_fatal_err(adapter);
158*d39a76e7Sxw161283 
159*d39a76e7Sxw161283 	if (t1_is_T1B(adapter)) {
160*d39a76e7Sxw161283 		/*
161*d39a76e7Sxw161283 		 * Workaround for T1B bug: we must write to enable register to
162*d39a76e7Sxw161283 		 * clear interrupts.
163*d39a76e7Sxw161283 		 */
164*d39a76e7Sxw161283 		t1_write_reg_4(adapter, A_MC3_INT_ENABLE, cause);
165*d39a76e7Sxw161283 		/* restore enable */
166*d39a76e7Sxw161283 		t1_write_reg_4(adapter, A_MC3_INT_ENABLE, MC3_INTR_MASK);
167*d39a76e7Sxw161283 	} else
168*d39a76e7Sxw161283 		t1_write_reg_4(adapter, cause_reg, cause);
169*d39a76e7Sxw161283 
170*d39a76e7Sxw161283 	return 0;
171*d39a76e7Sxw161283 }
172*d39a76e7Sxw161283 
173*d39a76e7Sxw161283 #define is_MC3A(adapter) (!t1_is_T1B(adapter))
174*d39a76e7Sxw161283 
175*d39a76e7Sxw161283 /*
176*d39a76e7Sxw161283  * Write a value to a register and check that the write completed.  These
177*d39a76e7Sxw161283  * writes normally complete in a cycle or two, so one read should suffice.
178*d39a76e7Sxw161283  * The very first read exists to flush the posted write to the device.
179*d39a76e7Sxw161283  */
wrreg_wait(adapter_t * adapter,unsigned int addr,u32 val)180*d39a76e7Sxw161283 static int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val)
181*d39a76e7Sxw161283 {
182*d39a76e7Sxw161283 	t1_write_reg_4(adapter,	addr, val);
183*d39a76e7Sxw161283 	val = t1_read_reg_4(adapter, addr);                   /* flush */
184*d39a76e7Sxw161283 	if (!(t1_read_reg_4(adapter, addr) & F_BUSY))
185*d39a76e7Sxw161283 		return 0;
186*d39a76e7Sxw161283 	CH_ERR("%s: write to MC3 register 0x%x timed out\n",
187*d39a76e7Sxw161283 	       adapter_name(adapter), addr);
188*d39a76e7Sxw161283 	return -EIO;
189*d39a76e7Sxw161283 }
190*d39a76e7Sxw161283 
191*d39a76e7Sxw161283 #define MC3_DLL_DONE (F_MASTER_DLL_LOCKED | F_MASTER_DLL_MAX_TAP_COUNT)
192*d39a76e7Sxw161283 
t1_mc3_init(struct pemc3 * mc3,unsigned int mc3_clock)193*d39a76e7Sxw161283 int t1_mc3_init(struct pemc3 *mc3, unsigned int mc3_clock)
194*d39a76e7Sxw161283 {
195*d39a76e7Sxw161283 	u32 val;
196*d39a76e7Sxw161283 	unsigned int width, fast_asic, attempts;
197*d39a76e7Sxw161283 	adapter_t *adapter = mc3->adapter;
198*d39a76e7Sxw161283 
199*d39a76e7Sxw161283 	/* Check to see if ASIC is running in slow mode. */
200*d39a76e7Sxw161283 	val = t1_read_reg_4(adapter, A_MC3_CFG);
201*d39a76e7Sxw161283 	width = is_MC3A(adapter) ? G_MC3_WIDTH(val) : 0;
202*d39a76e7Sxw161283 	fast_asic = t1_is_asic(adapter) && !(val & F_MC3_SLOW);
203*d39a76e7Sxw161283 
204*d39a76e7Sxw161283 	val &= ~(V_MC3_BANK_CYCLE(M_MC3_BANK_CYCLE) |
205*d39a76e7Sxw161283 		 V_REFRESH_CYCLE(M_REFRESH_CYCLE) |
206*d39a76e7Sxw161283 		 V_PRECHARGE_CYCLE(M_PRECHARGE_CYCLE) |
207*d39a76e7Sxw161283 		 F_ACTIVE_TO_READ_WRITE_DELAY |
208*d39a76e7Sxw161283 		 V_ACTIVE_TO_PRECHARGE_DELAY(M_ACTIVE_TO_PRECHARGE_DELAY) |
209*d39a76e7Sxw161283 		 V_WRITE_RECOVERY_DELAY(M_WRITE_RECOVERY_DELAY));
210*d39a76e7Sxw161283 
211*d39a76e7Sxw161283 	if (mc3_clock <= 100000000)
212*d39a76e7Sxw161283 		val |= V_MC3_BANK_CYCLE(7) | V_REFRESH_CYCLE(4) |
213*d39a76e7Sxw161283 			V_PRECHARGE_CYCLE(2) | V_ACTIVE_TO_PRECHARGE_DELAY(5) |
214*d39a76e7Sxw161283 			V_WRITE_RECOVERY_DELAY(2);
215*d39a76e7Sxw161283 	else if (mc3_clock <= 133000000)
216*d39a76e7Sxw161283 		val |= V_MC3_BANK_CYCLE(9) | V_REFRESH_CYCLE(5) |
217*d39a76e7Sxw161283 			V_PRECHARGE_CYCLE(3) | F_ACTIVE_TO_READ_WRITE_DELAY |
218*d39a76e7Sxw161283 			V_ACTIVE_TO_PRECHARGE_DELAY(6) |
219*d39a76e7Sxw161283 			V_WRITE_RECOVERY_DELAY(2);
220*d39a76e7Sxw161283 	else
221*d39a76e7Sxw161283 		val |= V_MC3_BANK_CYCLE(0xA) | V_REFRESH_CYCLE(6) |
222*d39a76e7Sxw161283 			V_PRECHARGE_CYCLE(3) | F_ACTIVE_TO_READ_WRITE_DELAY |
223*d39a76e7Sxw161283 			V_ACTIVE_TO_PRECHARGE_DELAY(7) |
224*d39a76e7Sxw161283 			V_WRITE_RECOVERY_DELAY(3);
225*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_CFG, val);
226*d39a76e7Sxw161283 
227*d39a76e7Sxw161283 	val = t1_read_reg_4(adapter, A_MC3_CFG);
228*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_CFG, val | F_CLK_ENABLE);
229*d39a76e7Sxw161283 	val = t1_read_reg_4(adapter, A_MC3_CFG);                 /* flush */
230*d39a76e7Sxw161283 
231*d39a76e7Sxw161283 	if (fast_asic) {                                     /* setup DLLs */
232*d39a76e7Sxw161283 		val = t1_read_reg_4(adapter, A_MC3_STROBE);
233*d39a76e7Sxw161283 		if (is_MC3A(adapter)) {
234*d39a76e7Sxw161283 			t1_write_reg_4(adapter, A_MC3_STROBE,
235*d39a76e7Sxw161283 				       val & ~F_SLAVE_DLL_RESET);
236*d39a76e7Sxw161283 
237*d39a76e7Sxw161283 			/* Wait for slave DLLs to lock */
238*d39a76e7Sxw161283 			DELAY_US(2 * 512 / (mc3_clock / 1000000) + 1);
239*d39a76e7Sxw161283 		} else {
240*d39a76e7Sxw161283 			/* Initialize the master DLL and slave delay lines. */
241*d39a76e7Sxw161283 			t1_write_reg_4(adapter, A_MC3_STROBE,
242*d39a76e7Sxw161283 				       val & ~F_MASTER_DLL_RESET);
243*d39a76e7Sxw161283 
244*d39a76e7Sxw161283 			/* Wait for the master DLL to lock. */
245*d39a76e7Sxw161283 			attempts = 100;
246*d39a76e7Sxw161283 			do {
247*d39a76e7Sxw161283 				DELAY_US(1);
248*d39a76e7Sxw161283 				val = t1_read_reg_4(adapter, A_MC3_STROBE);
249*d39a76e7Sxw161283 			} while (!(val & MC3_DLL_DONE) && --attempts);
250*d39a76e7Sxw161283 			if (!(val & MC3_DLL_DONE)) {
251*d39a76e7Sxw161283 				CH_ERR("%s: MC3 DLL lock failed\n",
252*d39a76e7Sxw161283 				       adapter_name(adapter));
253*d39a76e7Sxw161283 				goto out_fail;
254*d39a76e7Sxw161283 			}
255*d39a76e7Sxw161283 		}
256*d39a76e7Sxw161283 	}
257*d39a76e7Sxw161283 
258*d39a76e7Sxw161283 	/* Initiate a precharge and wait for the precharge to complete. */
259*d39a76e7Sxw161283 	if (wrreg_wait(adapter, A_MC3_PRECHARG, 0))
260*d39a76e7Sxw161283 		goto out_fail;
261*d39a76e7Sxw161283 
262*d39a76e7Sxw161283 	/* Set the SDRAM output drive strength and enable DLLs if needed */
263*d39a76e7Sxw161283 	if (wrreg_wait(adapter, A_MC3_EXT_MODE, fast_asic ? 0 : 1))
264*d39a76e7Sxw161283 		goto out_fail;
265*d39a76e7Sxw161283 
266*d39a76e7Sxw161283 	/* Specify the SDRAM operating parameters. */
267*d39a76e7Sxw161283 	if (wrreg_wait(adapter, A_MC3_MODE, fast_asic ? 0x161 : 0x21))
268*d39a76e7Sxw161283 		goto out_fail;
269*d39a76e7Sxw161283 
270*d39a76e7Sxw161283 	/* Initiate a precharge and wait for the precharge to complete. */
271*d39a76e7Sxw161283 	if (wrreg_wait(adapter, A_MC3_PRECHARG, 0))
272*d39a76e7Sxw161283 		goto out_fail;
273*d39a76e7Sxw161283 
274*d39a76e7Sxw161283 	/* Initiate an immediate refresh and wait for the write to complete. */
275*d39a76e7Sxw161283 	val = t1_read_reg_4(adapter, A_MC3_REFRESH);
276*d39a76e7Sxw161283 	if (wrreg_wait(adapter, A_MC3_REFRESH, val & ~F_REFRESH_ENABLE))
277*d39a76e7Sxw161283 		goto out_fail;
278*d39a76e7Sxw161283 
279*d39a76e7Sxw161283 	/* 2nd immediate refresh as before */
280*d39a76e7Sxw161283 	if (wrreg_wait(adapter, A_MC3_REFRESH, val & ~F_REFRESH_ENABLE))
281*d39a76e7Sxw161283 		goto out_fail;
282*d39a76e7Sxw161283 
283*d39a76e7Sxw161283 	/* Specify the SDRAM operating parameters. */
284*d39a76e7Sxw161283 	if (wrreg_wait(adapter, A_MC3_MODE, fast_asic ? 0x61 : 0x21))
285*d39a76e7Sxw161283 		goto out_fail;
286*d39a76e7Sxw161283 
287*d39a76e7Sxw161283 	/* Convert to KHz first to avoid 64-bit division. */
288*d39a76e7Sxw161283 	mc3_clock /=  1000;                            /* Hz->KHz */
289*d39a76e7Sxw161283 	mc3_clock = mc3_clock * 7812 + mc3_clock / 2;  /* ns */
290*d39a76e7Sxw161283 	mc3_clock /= 1000000;                          /* KHz->MHz, ns->us */
291*d39a76e7Sxw161283 
292*d39a76e7Sxw161283 	/* Enable periodic refresh. */
293*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_REFRESH,
294*d39a76e7Sxw161283 		       F_REFRESH_ENABLE | V_REFRESH_DIVISOR(mc3_clock));
295*d39a76e7Sxw161283 	(void) t1_read_reg_4(adapter, A_MC3_REFRESH);    /* flush */
296*d39a76e7Sxw161283 
297*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_ECC_CNTL,
298*d39a76e7Sxw161283 		       F_ECC_GENERATION_ENABLE | F_ECC_CHECK_ENABLE);
299*d39a76e7Sxw161283 
300*d39a76e7Sxw161283 	/* Use the BIST engine to clear MC3 memory and initialize ECC. */
301*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_BIST_ADDR_BEG, 0);
302*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_BIST_ADDR_END, (mc3->size << width) - 1);
303*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_BIST_DATA, 0);
304*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_BIST_OP, V_OP(1) | 0x1f0);
305*d39a76e7Sxw161283 	(void) t1_read_reg_4(adapter, A_MC3_BIST_OP);              /* flush */
306*d39a76e7Sxw161283 
307*d39a76e7Sxw161283 	attempts = 100;
308*d39a76e7Sxw161283 	do {
309*d39a76e7Sxw161283 		DELAY_MS(100);
310*d39a76e7Sxw161283 		val = t1_read_reg_4(adapter, A_MC3_BIST_OP);
311*d39a76e7Sxw161283 	} while ((val & F_BUSY) && --attempts);
312*d39a76e7Sxw161283 	if (val & F_BUSY) {
313*d39a76e7Sxw161283 		CH_ERR("%s: MC3 BIST timed out\n", adapter_name(adapter));
314*d39a76e7Sxw161283 		goto out_fail;
315*d39a76e7Sxw161283 	}
316*d39a76e7Sxw161283 
317*d39a76e7Sxw161283 	/* Enable normal memory accesses. */
318*d39a76e7Sxw161283 	val = t1_read_reg_4(adapter, A_MC3_CFG);
319*d39a76e7Sxw161283 	t1_write_reg_4(adapter, A_MC3_CFG, val | F_READY);
320*d39a76e7Sxw161283 	return 0;
321*d39a76e7Sxw161283 
322*d39a76e7Sxw161283  out_fail:
323*d39a76e7Sxw161283 	return -1;
324*d39a76e7Sxw161283 }
325*d39a76e7Sxw161283 
mc3_calc_size(const adapter_t * adapter,u32 cfg)326*d39a76e7Sxw161283 static unsigned int __devinit mc3_calc_size(const adapter_t *adapter, u32 cfg)
327*d39a76e7Sxw161283 {
328*d39a76e7Sxw161283 	unsigned int banks = !!(cfg & F_BANKS) + 1;
329*d39a76e7Sxw161283 	unsigned int org = !!(cfg & F_ORGANIZATION) + 1;
330*d39a76e7Sxw161283 	unsigned int density = G_DENSITY(cfg);
331*d39a76e7Sxw161283 
332*d39a76e7Sxw161283 	unsigned int capacity_in_MB = is_MC3A(adapter) ?
333*d39a76e7Sxw161283 		((256 << density) * banks) / (org << G_MC3_WIDTH(cfg)) :
334*d39a76e7Sxw161283 		((128 << density) * (16 / org) * banks) / 8;
335*d39a76e7Sxw161283 
336*d39a76e7Sxw161283 	return capacity_in_MB * 1024 * 1024;
337*d39a76e7Sxw161283 }
338*d39a76e7Sxw161283 
t1_mc3_create(adapter_t * adapter)339*d39a76e7Sxw161283 struct pemc3 * __devinit t1_mc3_create(adapter_t *adapter)
340*d39a76e7Sxw161283 {
341*d39a76e7Sxw161283 	struct pemc3 *mc3 = t1_os_malloc_wait_zero(sizeof(*mc3));
342*d39a76e7Sxw161283 
343*d39a76e7Sxw161283 	if (mc3) {
344*d39a76e7Sxw161283 		mc3->adapter = adapter;
345*d39a76e7Sxw161283 		mc3->size = mc3_calc_size(adapter,
346*d39a76e7Sxw161283 					  t1_read_reg_4(adapter, A_MC3_CFG));
347*d39a76e7Sxw161283 	}
348*d39a76e7Sxw161283 	return mc3;
349*d39a76e7Sxw161283 }
350*d39a76e7Sxw161283 
t1_mc3_destroy(struct pemc3 * mc3)351*d39a76e7Sxw161283 void t1_mc3_destroy(struct pemc3 *mc3)
352*d39a76e7Sxw161283 {
353*d39a76e7Sxw161283 	t1_os_free((void *)mc3, sizeof(*mc3));
354*d39a76e7Sxw161283 }
355*d39a76e7Sxw161283 
t1_mc3_get_size(struct pemc3 * mc3)356*d39a76e7Sxw161283 unsigned int t1_mc3_get_size(struct pemc3 *mc3)
357*d39a76e7Sxw161283 {
358*d39a76e7Sxw161283 	return mc3->size;
359*d39a76e7Sxw161283 }
360*d39a76e7Sxw161283 
t1_mc3_get_intr_counts(struct pemc3 * mc3)361*d39a76e7Sxw161283 const struct pemc3_intr_counts *t1_mc3_get_intr_counts(struct pemc3 *mc3)
362*d39a76e7Sxw161283 {
363*d39a76e7Sxw161283 	return &mc3->intr_cnt;
364*d39a76e7Sxw161283 }
365