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