Beispiel #1
0
void t1_mc4_intr_clear(struct pemc4 *mc4)
{
	if (t1_is_asic(mc4->adapter)) {
		t1_write_reg_4(mc4->adapter, A_MC4_INT_CAUSE, 0xffffffff);
		t1_write_reg_4(mc4->adapter, A_PL_CAUSE, F_PL_INTR_MC4);
	}
}
static void tp_init(adapter_t * ap, const struct tp_params *p,
		    unsigned int tp_clk)
{
	u32 val;

	if (!t1_is_asic(ap))
		return;

	val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
		F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
	if (!p->pm_size)
		val |= F_OFFLOAD_DISABLE;
	else
		val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM;
	writel(val, ap->regs + A_TP_IN_CONFIG);
	writel(F_TP_OUT_CSPI_CPL |
	       F_TP_OUT_ESPI_ETHERNET |
	       F_TP_OUT_ESPI_GENERATE_IP_CSUM |
	       F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG);
	writel(V_IP_TTL(64) |
	       F_PATH_MTU   |
	       V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
	       V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG);
	if (is_T2(ap) && ap->params.nports > 1) {
		u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);

		writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
		       V_DROP_TICKS_CNT(drop_ticks) |
		       V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
		       ap->regs + A_TP_TX_DROP_CONFIG);
	}
}
Beispiel #3
0
void t1_mc3_intr_clear(struct pemc3 *mc3)
{
	if (t1_is_asic(mc3->adapter)) {
		if (t1_is_T1B(mc3->adapter)) {
			/*
			 * Workaround for T1B bug: we must write to enable
			 * register to clear interrupts.
			 */
			u32 old_en;

			old_en = t1_read_reg_4(mc3->adapter, A_MC3_INT_ENABLE);
			t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE,
				       0xffffffff);
			t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, old_en);
		} else
			t1_write_reg_4(mc3->adapter, A_MC3_INT_CAUSE,
				       0xffffffff);

		t1_write_reg_4(mc3->adapter, A_PL_CAUSE, F_PL_INTR_MC3);
#ifdef CONFIG_CHELSIO_T1_1G
	} else {
		t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRCAUSE,
			       0xffffffff);
		t1_write_reg_4(mc3->adapter, A_PL_CAUSE,
			       FPGA_PCIX_INTERRUPT_MC3);
#endif
	}
}
Beispiel #4
0
void t1_mc4_intr_disable(struct pemc4 *mc4)
{
	u32 pl_intr;

	if (t1_is_asic(mc4->adapter)) {
		t1_write_reg_4(mc4->adapter, A_MC4_INT_ENABLE, 0);

		pl_intr = t1_read_reg_4(mc4->adapter, A_PL_ENABLE);
		t1_write_reg_4(mc4->adapter, A_PL_ENABLE,
			       pl_intr & ~F_PL_INTR_MC4);
	}
}
void t1_tp_intr_clear(struct petp *tp)
{
#ifdef CONFIG_CHELSIO_T1_1G
	if (!t1_is_asic(tp->adapter)) {
		writel(0xffffffff,
		       tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
		writel(FPGA_PCIX_INTERRUPT_TP, tp->adapter->regs + A_PL_CAUSE);
		return;
	}
#endif
	writel(0xffffffff, tp->adapter->regs + A_TP_INT_CAUSE);
	writel(F_PL_INTR_TP, tp->adapter->regs + A_PL_CAUSE);
}
int t1_tp_intr_handler(struct petp *tp)
{
	u32 cause;

#ifdef CONFIG_CHELSIO_T1_1G
	
	if (!t1_is_asic(tp->adapter))
		return 1;
#endif

	cause = readl(tp->adapter->regs + A_TP_INT_CAUSE);
	writel(cause, tp->adapter->regs + A_TP_INT_CAUSE);
	return 0;
}
Beispiel #7
0
static int mv88x201x_interrupt_disable(struct cphy *cphy)
{
	/* Disable PHY LASI interrupts. */
	cphy_mdio_write(cphy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0x0);

	/* Disable Marvell interrupts through Elmer0. */
	if (t1_is_asic(cphy->adapter)) {
		u32 elmer;

		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
		elmer &= ~ELMER0_GP_BIT6;
		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
	}
	return 0;
}
static int mv88x201x_interrupt_disable(struct cphy *cphy)
{
	/* Disable PHY LASI interrupts. */
	(void) mdio_write(cphy, 0x1, 0x9002, 0x0);

	/* Disable Marvell interrupts through Elmer0. */
	if (t1_is_asic(cphy->adapter)) {
		u32 elmer;

		(void) t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
		elmer &= ~ELMER0_GP_BIT6;
		(void) t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
	}
	return 0;
}
Beispiel #9
0
void t1_mc3_intr_disable(struct pemc3 *mc3)
{
	u32 pl_intr = t1_read_reg_4(mc3->adapter, A_PL_ENABLE);

	if (t1_is_asic(mc3->adapter)) {
		t1_write_reg_4(mc3->adapter, A_MC3_INT_ENABLE, 0);
		t1_write_reg_4(mc3->adapter, A_PL_ENABLE,
			       pl_intr & ~F_PL_INTR_MC3);
#ifdef CONFIG_CHELSIO_T1_1G
	} else {
		t1_write_reg_4(mc3->adapter, FPGA_MC3_REG_INTRENABLE, 0);
		t1_write_reg_4(mc3->adapter, A_PL_ENABLE,
			       pl_intr & ~FPGA_PCIX_INTERRUPT_MC3);
#endif
	}
}
Beispiel #10
0
static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
{
	/* Disable all phy interrupts. */
	(void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0);

	/* Disable Marvell interrupts through Elmer0. */
	if (t1_is_asic(cphy->adapter)) {
		u32 elmer;

		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
		elmer &= ~ELMER0_GP_BIT1;
		if (is_T2(cphy->adapter))
		    elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
	}
	return 0;
}
Beispiel #11
0
static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
{
	
	(void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER,
		   INTR_ENABLE_MASK);

	
	if (t1_is_asic(cphy->adapter)) {
		u32 elmer;

		t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
		elmer |= ELMER0_GP_BIT1;
		if (is_T2(cphy->adapter))
		    elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
		t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
	}
	return 0;
}
Beispiel #12
0
static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
{
	u32 elmer;

	
	(void) simple_mdio_read(cphy,
			MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer);

	
	if (t1_is_asic(cphy->adapter)) {
		t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
		elmer |= ELMER0_GP_BIT1;
		if (is_T2(cphy->adapter))
		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
		t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
	}
	return 0;
}
void t1_tp_intr_disable(struct petp *tp)
{
	u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE);

#ifdef CONFIG_CHELSIO_T1_1G
	if (!t1_is_asic(tp->adapter)) {
		
		writel(0, tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_ENABLE);
		writel(tp_intr & ~FPGA_PCIX_INTERRUPT_TP,
		       tp->adapter->regs + A_PL_ENABLE);
	} else
#endif
	{
		writel(0, tp->adapter->regs + A_TP_INT_ENABLE);
		writel(tp_intr & ~F_PL_INTR_TP,
		       tp->adapter->regs + A_PL_ENABLE);
	}
}
Beispiel #14
0
static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
{
	u32 elmer;

	/* Clear PHY interrupts by reading the register. */
	(void) simple_mdio_read(cphy,
			MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer);

	/* Clear Marvell interrupts through Elmer0. */
	if (t1_is_asic(cphy->adapter)) {
		t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
		elmer |= ELMER0_GP_BIT1;
		if (is_T2(cphy->adapter))
		    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
		t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
	}
	return 0;
}
static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
{
	/* Enable PHY interrupts. */
	(void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER,
		   INTR_ENABLE_MASK);

	/* Enable Marvell interrupts through Elmer0. */
	if (t1_is_asic(cphy->adapter)) {
		u32 elmer;

		(void) t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
		elmer |= ELMER0_GP_BIT1;
		if (is_T2(cphy->adapter)) {
			elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
		}
		(void) t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
	}
	return 0;
}
Beispiel #16
0
void t1_tp_intr_enable(struct petp *tp)
{
	u32 tp_intr = readl(tp->adapter->regs + A_PL_ENABLE);

#ifdef CONFIG_CHELSIO_T1_1G
	if (!t1_is_asic(tp->adapter)) {
		/* FPGA */
		writel(0xffffffff,
		       tp->adapter->regs + FPGA_TP_ADDR_INTERRUPT_ENABLE);
		writel(tp_intr | FPGA_PCIX_INTERRUPT_TP,
		       tp->adapter->regs + A_PL_ENABLE);
	} else
#endif
	{
		/* We don't use any TP interrupts */
		writel(0, tp->adapter->regs + A_TP_INT_ENABLE);
		writel(tp_intr | F_PL_INTR_TP,
		       tp->adapter->regs + A_PL_ENABLE);
	}
}
static int mv88x201x_interrupt_clear(struct cphy *cphy)
{
	u32 elmer;
	u32 val;

#ifdef MV88x2010_LINK_STATUS_BUGS
	/* Required to read twice before clear takes affect. */
	(void) mdio_read(cphy, 0x1, 0x9003, &val);
	(void) mdio_read(cphy, 0x1, 0x9004, &val);
	(void) mdio_read(cphy, 0x1, 0x9005, &val);

	/* Read this register after the others above it else
	 * the register doesn't clear correctly. 
	 */
	(void) mdio_read(cphy, 0x1, 0x1, &val);
#endif

	/* Clear link status. */
	(void) mdio_read(cphy, 0x1, 0x1, &val);
	/* Clear PHY LASI interrupts. */
	(void) mdio_read(cphy, 0x1, 0x9005, &val);

#ifdef MV88x2010_LINK_STATUS_BUGS
	/* Do it again. */
	(void) mdio_read(cphy, 0x1, 0x9003, &val);
	(void) mdio_read(cphy, 0x1, 0x9004, &val);
#endif

	/* Clear Marvell interrupts through Elmer0. */
	if (t1_is_asic(cphy->adapter)) {
		(void) t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
		elmer |= ELMER0_GP_BIT6;
		(void) t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
	}
	return 0;
}
Beispiel #18
0
int t1_mc3_intr_handler(struct pemc3 *mc3)
{
	adapter_t *adapter = mc3->adapter;
	int cause_reg = A_MC3_INT_CAUSE;
	u32 cause;

#ifdef CONFIG_CHELSIO_T1_1G
	if (!t1_is_asic(adapter))
		cause_reg = FPGA_MC3_REG_INTRCAUSE;
#endif
	cause = t1_read_reg_4(adapter, cause_reg);

	if (cause & F_MC3_CORR_ERR) {
		mc3->intr_cnt.corr_err++;
		CH_WARN("%s: MC3 correctable error at addr 0x%x, "
			"data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
			adapter_name(adapter),
			G_MC3_CE_ADDR(t1_read_reg_4(adapter, A_MC3_CE_ADDR)),
			t1_read_reg_4(adapter, A_MC3_CE_DATA0),
			t1_read_reg_4(adapter, A_MC3_CE_DATA1),
			t1_read_reg_4(adapter, A_MC3_CE_DATA2),
			t1_read_reg_4(adapter, A_MC3_CE_DATA3),
			t1_read_reg_4(adapter, A_MC3_CE_DATA4));
	}

	if (cause & F_MC3_UNCORR_ERR) {
		mc3->intr_cnt.uncorr_err++;
		CH_ALERT("%s: MC3 uncorrectable error at addr 0x%x, "
			 "data 0x%x 0x%x 0x%x 0x%x 0x%x\n",
			 adapter_name(adapter),
			 G_MC3_UE_ADDR(t1_read_reg_4(adapter, A_MC3_UE_ADDR)),
			 t1_read_reg_4(adapter, A_MC3_UE_DATA0),
			 t1_read_reg_4(adapter, A_MC3_UE_DATA1),
			 t1_read_reg_4(adapter, A_MC3_UE_DATA2),
			 t1_read_reg_4(adapter, A_MC3_UE_DATA3),
			 t1_read_reg_4(adapter, A_MC3_UE_DATA4));
	}

	if (G_MC3_PARITY_ERR(cause)) {
		mc3->intr_cnt.parity_err++;
		CH_ALERT("%s: MC3 parity error 0x%x\n", adapter_name(adapter),
			 G_MC3_PARITY_ERR(cause));
	}

	if (cause & F_MC3_ADDR_ERR) {
		mc3->intr_cnt.addr_err++;
		CH_ALERT("%s: MC3 address error\n", adapter_name(adapter));
	}

	if (cause & MC3_INTR_FATAL)
		t1_fatal_err(adapter);

	if (t1_is_T1B(adapter)) {
		/*
		 * Workaround for T1B bug: we must write to enable register to
		 * clear interrupts.
		 */
		t1_write_reg_4(adapter, A_MC3_INT_ENABLE, cause);
		/* restore enable */
		t1_write_reg_4(adapter, A_MC3_INT_ENABLE, MC3_INTR_MASK);
	} else
		t1_write_reg_4(adapter, cause_reg, cause);

	return 0;
}
Beispiel #19
0
int t1_mc4_init(struct pemc4 *mc4, unsigned int mc4_clock)
{
	int attempts;
	u32 val;
	unsigned int width, ext_mode, slow_mode;
	adapter_t *adapter = mc4->adapter;

	/* Power up the FCRAMs. */
	val = t1_read_reg_4(adapter, A_MC4_CFG);
	t1_write_reg_4(adapter, A_MC4_CFG, val | F_POWER_UP);
	val = t1_read_reg_4(adapter, A_MC4_CFG);               /* flush */

	if (is_MC4A(adapter)) {
		slow_mode = val & F_MC4A_SLOW;
		width = G_MC4A_WIDTH(val);

		/* If we're not in slow mode, we are using the DLLs */
		if (!slow_mode) {
			/* Clear Reset */
			val = t1_read_reg_4(adapter, A_MC4_STROBE);
			t1_write_reg_4(adapter, A_MC4_STROBE,
				       val & ~F_SLAVE_DLL_RESET);

			/* Wait for slave DLLs to lock */
			DELAY_US(2 * 512 / (mc4_clock / 1000000) + 1);
		}
	} else {
		slow_mode = val & F_MC4_SLOW;
		width = !!(val & F_MC4_NARROW);

		/* Initializes the master DLL and slave delay lines. */
		if (t1_is_asic(adapter) && !slow_mode) {
			val = t1_read_reg_4(adapter, A_MC4_STROBE);
			t1_write_reg_4(adapter, A_MC4_STROBE,
				       val & ~F_MASTER_DLL_RESET);

			/* Wait for the master DLL to lock. */
			attempts = 100;
			do {
				DELAY_US(1);
				val = t1_read_reg_4(adapter, A_MC4_STROBE);
			} while (!(val & MC4_DLL_DONE) && --attempts);
			if (!(val & MC4_DLL_DONE)) {
				CH_ERR("%s: MC4 DLL lock failed\n",
				       adapter_name(adapter));
				goto out_fail;
			}
		}
	}

	mc4->nwords = 4 >> width;

	/* Set the FCRAM output drive strength and enable DLLs if needed */
	ext_mode = t1_is_asic(adapter) && !slow_mode ? 0 : 1;
	if (wrreg_wait(adapter, A_MC4_EXT_MODE, ext_mode))
		goto out_fail;

	/* Specify the FCRAM operating parameters */
	if (wrreg_wait(adapter, A_MC4_MODE, 0x32))
		goto out_fail;

	/* Initiate an immediate refresh and wait for the write to complete. */
	val = t1_read_reg_4(adapter, A_MC4_REFRESH);
	if (wrreg_wait(adapter, A_MC4_REFRESH, val & ~F_REFRESH_ENABLE))
		goto out_fail;

	/* 2nd immediate refresh as before */
	if (wrreg_wait(adapter, A_MC4_REFRESH, val & ~F_REFRESH_ENABLE))
		goto out_fail;

	/* Convert to KHz first to avoid 64-bit division. */
	mc4_clock /= 1000;                            /* Hz->KHz */
	mc4_clock = mc4_clock * 7812 + mc4_clock / 2; /* ns */
	mc4_clock /= 1000000;                         /* KHz->MHz, ns->us */

	/* Enable periodic refresh. */
	t1_write_reg_4(adapter, A_MC4_REFRESH,
		       F_REFRESH_ENABLE | V_REFRESH_DIVISOR(mc4_clock));
	(void) t1_read_reg_4(adapter, A_MC4_REFRESH);    /* flush */

	t1_write_reg_4(adapter, A_MC4_ECC_CNTL,
		       F_ECC_GENERATION_ENABLE | F_ECC_CHECK_ENABLE);

	/* Use the BIST engine to clear all of the MC4 memory. */
	t1_write_reg_4(adapter, A_MC4_BIST_ADDR_BEG, 0);
	t1_write_reg_4(adapter, A_MC4_BIST_ADDR_END, (mc4->size << width) - 1);
	t1_write_reg_4(adapter, A_MC4_BIST_DATA, 0);
	t1_write_reg_4(adapter, A_MC4_BIST_OP, V_OP(1) | 0x1f0);
	(void) t1_read_reg_4(adapter, A_MC4_BIST_OP);              /* flush */

	attempts = 100;
	do {
		DELAY_MS(100);
		val = t1_read_reg_4(adapter, A_MC4_BIST_OP);
	} while ((val & F_BUSY) && --attempts);
	if (val & F_BUSY) {
		CH_ERR("%s: MC4 BIST timed out\n", adapter_name(adapter));
		goto out_fail;
	}

	/* Enable normal memory accesses. */
	val = t1_read_reg_4(adapter, A_MC4_CFG);
	t1_write_reg_4(adapter, A_MC4_CFG, val | F_READY);
	val = t1_read_reg_4(adapter, A_MC4_CFG);               /* flush */
	return 0;

 out_fail:
	return -1;
}
Beispiel #20
0
int t1_mc3_init(struct pemc3 *mc3, unsigned int mc3_clock)
{
	u32 val;
	unsigned int width, fast_asic, attempts;
	adapter_t *adapter = mc3->adapter;

	/* Check to see if ASIC is running in slow mode. */
	val = t1_read_reg_4(adapter, A_MC3_CFG);
	width = is_MC3A(adapter) ? G_MC3_WIDTH(val) : 0;
	fast_asic = t1_is_asic(adapter) && !(val & F_MC3_SLOW);

	val &= ~(V_MC3_BANK_CYCLE(M_MC3_BANK_CYCLE) |
		 V_REFRESH_CYCLE(M_REFRESH_CYCLE) |
		 V_PRECHARGE_CYCLE(M_PRECHARGE_CYCLE) |
		 F_ACTIVE_TO_READ_WRITE_DELAY |
		 V_ACTIVE_TO_PRECHARGE_DELAY(M_ACTIVE_TO_PRECHARGE_DELAY) |
		 V_WRITE_RECOVERY_DELAY(M_WRITE_RECOVERY_DELAY));

	if (mc3_clock <= 100000000)
		val |= V_MC3_BANK_CYCLE(7) | V_REFRESH_CYCLE(4) |
			V_PRECHARGE_CYCLE(2) | V_ACTIVE_TO_PRECHARGE_DELAY(5) |
			V_WRITE_RECOVERY_DELAY(2);
	else if (mc3_clock <= 133000000)
		val |= V_MC3_BANK_CYCLE(9) | V_REFRESH_CYCLE(5) |
			V_PRECHARGE_CYCLE(3) | F_ACTIVE_TO_READ_WRITE_DELAY |
			V_ACTIVE_TO_PRECHARGE_DELAY(6) |
			V_WRITE_RECOVERY_DELAY(2);
	else
		val |= V_MC3_BANK_CYCLE(0xA) | V_REFRESH_CYCLE(6) |
			V_PRECHARGE_CYCLE(3) | F_ACTIVE_TO_READ_WRITE_DELAY |
			V_ACTIVE_TO_PRECHARGE_DELAY(7) |
			V_WRITE_RECOVERY_DELAY(3);
	t1_write_reg_4(adapter, A_MC3_CFG, val);

	val = t1_read_reg_4(adapter, A_MC3_CFG);
	t1_write_reg_4(adapter, A_MC3_CFG, val | F_CLK_ENABLE);
	val = t1_read_reg_4(adapter, A_MC3_CFG);                 /* flush */

	if (fast_asic) {                                     /* setup DLLs */
		val = t1_read_reg_4(adapter, A_MC3_STROBE);
		if (is_MC3A(adapter)) {
			t1_write_reg_4(adapter, A_MC3_STROBE,
				       val & ~F_SLAVE_DLL_RESET);

			/* Wait for slave DLLs to lock */
			DELAY_US(2 * 512 / (mc3_clock / 1000000) + 1);
		} else {
			/* Initialize the master DLL and slave delay lines. */
			t1_write_reg_4(adapter, A_MC3_STROBE,
				       val & ~F_MASTER_DLL_RESET);

			/* Wait for the master DLL to lock. */
			attempts = 100;
			do {
				DELAY_US(1);
				val = t1_read_reg_4(adapter, A_MC3_STROBE);
			} while (!(val & MC3_DLL_DONE) && --attempts);
			if (!(val & MC3_DLL_DONE)) {
				CH_ERR("%s: MC3 DLL lock failed\n",
				       adapter_name(adapter));
				goto out_fail;
			}
		}
	}

	/* Initiate a precharge and wait for the precharge to complete. */
	if (wrreg_wait(adapter, A_MC3_PRECHARG, 0))
		goto out_fail;

	/* Set the SDRAM output drive strength and enable DLLs if needed */
	if (wrreg_wait(adapter, A_MC3_EXT_MODE, fast_asic ? 0 : 1))
		goto out_fail;

	/* Specify the SDRAM operating parameters. */
	if (wrreg_wait(adapter, A_MC3_MODE, fast_asic ? 0x161 : 0x21))
		goto out_fail;

	/* Initiate a precharge and wait for the precharge to complete. */
	if (wrreg_wait(adapter, A_MC3_PRECHARG, 0))
		goto out_fail;

	/* Initiate an immediate refresh and wait for the write to complete. */
	val = t1_read_reg_4(adapter, A_MC3_REFRESH);
	if (wrreg_wait(adapter, A_MC3_REFRESH, val & ~F_REFRESH_ENABLE))
		goto out_fail;

	/* 2nd immediate refresh as before */
	if (wrreg_wait(adapter, A_MC3_REFRESH, val & ~F_REFRESH_ENABLE))
		goto out_fail;

	/* Specify the SDRAM operating parameters. */
	if (wrreg_wait(adapter, A_MC3_MODE, fast_asic ? 0x61 : 0x21))
		goto out_fail;

	/* Convert to KHz first to avoid 64-bit division. */
	mc3_clock /=  1000;                            /* Hz->KHz */
	mc3_clock = mc3_clock * 7812 + mc3_clock / 2;  /* ns */
	mc3_clock /= 1000000;                          /* KHz->MHz, ns->us */

	/* Enable periodic refresh. */
	t1_write_reg_4(adapter, A_MC3_REFRESH,
		       F_REFRESH_ENABLE | V_REFRESH_DIVISOR(mc3_clock));
	(void) t1_read_reg_4(adapter, A_MC3_REFRESH);    /* flush */

	t1_write_reg_4(adapter, A_MC3_ECC_CNTL,
		       F_ECC_GENERATION_ENABLE | F_ECC_CHECK_ENABLE);

	/* Use the BIST engine to clear MC3 memory and initialize ECC. */
	t1_write_reg_4(adapter, A_MC3_BIST_ADDR_BEG, 0);
	t1_write_reg_4(adapter, A_MC3_BIST_ADDR_END, (mc3->size << width) - 1);
	t1_write_reg_4(adapter, A_MC3_BIST_DATA, 0);
	t1_write_reg_4(adapter, A_MC3_BIST_OP, V_OP(1) | 0x1f0);
	(void) t1_read_reg_4(adapter, A_MC3_BIST_OP);              /* flush */

	attempts = 100;
	do {
		DELAY_MS(100);
		val = t1_read_reg_4(adapter, A_MC3_BIST_OP);
	} while ((val & F_BUSY) && --attempts);
	if (val & F_BUSY) {
		CH_ERR("%s: MC3 BIST timed out\n", adapter_name(adapter));
		goto out_fail;
	}

	/* Enable normal memory accesses. */
	val = t1_read_reg_4(adapter, A_MC3_CFG);
	t1_write_reg_4(adapter, A_MC3_CFG, val | F_READY);
	return 0;

 out_fail:
	return -1;
}