Exemple #1
0
static void
finishcmd(u32int cmd, u32int arg)
{
	u32int *r;

	/*
	 * Once card is selected, use faster clock.
	 * If card bus width changes, change host bus width.
	 */
	r = (u32int*)AddrSdio;
	if(cmd == MMCSelect){
		delay(10);
		WR(Clockdiv, clkdiv(Clkfreq/SDfreq - 1));
		delay(10);
		ctlr.fastclock = 1;
	} else if(cmd == Setbuswidth)
		switch(arg){
		case 0:
			WR(Hostctl, r[Hostctl] & ~Dwidth4);
			break;
		case 2:
			WR(Hostctl, r[Hostctl] | Dwidth4);
			break;
		}
}
static void lpc32xx_nand_init(void)
{
	unsigned int clk;

	/* Configure controller for no software write protection, x8 bus
	   width, large block device, and 4 address words */

	/* unlock controller registers with magic key */
	writel(LOCK_PR_UNLOCK_KEY,
	       &lpc32xx_nand_mlc_registers->lock_pr);

	/* enable large blocks and large NANDs */
	writel(ICR_LARGE_BLOCKS | ICR_ADDR4,
	       &lpc32xx_nand_mlc_registers->icr);

	/* Make sure MLC interrupts are disabled */
	writel(0, &lpc32xx_nand_mlc_registers->irq_mr);

	/* Normal chip enable operation */
	writel(CEH_NORMAL_CE,
	       &lpc32xx_nand_mlc_registers->ceh);

	/* Setup NAND timing */
	clk = get_hclk_clk_rate();

	writel(
		clkdiv(CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY, 0x03, 24) |
		clkdiv(CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY, 0x1F, 19) |
		clkdiv(CONFIG_LPC32XX_NAND_MLC_NAND_TA,    0x07, 16) |
		clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_HIGH,    0x0F, 12) |
		clkdiv(CONFIG_LPC32XX_NAND_MLC_RD_LOW,     0x0F, 8) |
		clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_HIGH,    0x0F, 4) |
		clkdiv(CONFIG_LPC32XX_NAND_MLC_WR_LOW,     0x0F, 0),
		&lpc32xx_nand_mlc_registers->time_reg);
}
Exemple #3
0
static void
sdioenable(void)
{
	u32int *r;

	r = (u32int*)AddrSdio;
	WR(Clockdiv, clkdiv(Clkfreq/Initfreq - 1));
	delay(10);
	WR(Clockctl, r[Clockctl] & ~Sdclken);
	WR(Hostctl, Pushpullen|Bigendian|Cardtypemem);
	WR(Irpten, 0);
	WR(Interrupt, ~0);
	WR(ErrIntr, ~0);
	WR(Irptmask, ~0);
	WR(ErrIrptmask, ~Dtoerr);
	intrenable(Irqlo, IRQ0sdio, sdiointerrupt, &ctlr, "sdio");
}
Exemple #4
0
static void
emmcenable(void)
{
	u32int *r;
	int i;

	r = (u32int*)EMMCREGS;
	WR(Control1, clkdiv(emmc.extclk/Initfreq - 1) |
		DTO<<Datatoshift | Clkgendiv | Clken | Clkintlen);
	for(i = 0; i < 1000; i++){
		delay(1);
		if(r[Control1] & Clkstable)
			break;
	}
	if(i == 1000)
		print("SD clock won't initialise!\n");
	WR(Irptmask, ~(Dtoerr|Cardintr));
	intrenable(IRQmmc, mmcinterrupt, nil, 0, "mmc");
}
Exemple #5
0
static int
emmccmd(u32int cmd, u32int arg, u32int *resp)
{
	u32int *r;
	u32int c;
	int i;
	ulong now;

	r = (u32int*)EMMCREGS;
	assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
	c = (cmd << Indexshift) | cmdinfo[cmd];
	if(r[Status] & Cmdinhibit){
		print("emmccmd: need to reset Cmdinhibit intr %ux stat %ux\n",
			r[Interrupt], r[Status]);
		WR(Control1, r[Control1] | Srstcmd);
		while(r[Control1] & Srstcmd)
			;
		while(r[Status] & Cmdinhibit)
			;
	}
	if((r[Status] & Datinhibit) &&
	   ((c & Isdata) || (c & Respmask) == Resp48busy)){
		print("emmccmd: need to reset Datinhibit intr %ux stat %ux\n",
			r[Interrupt], r[Status]);
		WR(Control1, r[Control1] | Srstdata);
		while(r[Control1] & Srstdata)
			;
		while(r[Status] & Datinhibit)
			;
	}
	WR(Arg1, arg);
	if((i = r[Interrupt]) != 0){
		if(i != Cardinsert)
			print("emmc: before command, intr was %ux\n", i);
		WR(Interrupt, i);
	}
	WR(Cmdtm, c);
	now = m->ticks;
	while(((i=r[Interrupt])&(Cmddone|Err)) == 0)
		if(m->ticks-now > HZ)
			break;
	if((i&(Cmddone|Err)) != Cmddone){
		if((i&~Err) != Ctoerr)
			print("emmc: cmd %ux error intr %ux stat %ux\n", c, i, r[Status]);
		WR(Interrupt, i);
		if(r[Status]&Cmdinhibit){
			WR(Control1, r[Control1]|Srstcmd);
			while(r[Control1]&Srstcmd)
				;
		}
		error(Eio);
	}
	WR(Interrupt, i & ~(Datadone|Readrdy|Writerdy));
	switch(c & Respmask){
	case Resp136:
		resp[0] = r[Resp0]<<8;
		resp[1] = r[Resp0]>>24 | r[Resp1]<<8;
		resp[2] = r[Resp1]>>24 | r[Resp2]<<8;
		resp[3] = r[Resp2]>>24 | r[Resp3]<<8;
		break;
	case Resp48:
	case Resp48busy:
		resp[0] = r[Resp0];
		break;
	case Respnone:
		resp[0] = 0;
		break;
	}
	if((c & Respmask) == Resp48busy){
		WR(Irpten, Datadone|Err);
		tsleep(&emmc.r, datadone, 0, 3000);
		WR(Irpten, 0);
		emmc.datadone = 0;
		i = r[Interrupt];
		if((i & Datadone) == 0)
			print("emmcio: no Datadone after CMD%d\n", cmd);
		if(i & Err)
			print("emmcio: CMD%d error interrupt %ux\n",
				cmd, r[Interrupt]);
		WR(Interrupt, i);
	}
	/*
	 * Once card is selected, use faster clock
	 */
	if(cmd == MMCSelect){
		delay(10);
		WR(Control1, clkdiv(emmc.extclk/SDfreq - 1) |
			DTO<<Datatoshift | Clkgendiv | Clken | Clkintlen);
		for(i = 0; i < 1000; i++){
			delay(1);
			if(r[Control1] & Clkstable)
				break;
		}
		delay(10);
		emmc.fastclock = 1;
	}
	/*
	 * If card bus width changes, change host bus width
	 */
	if(cmd == Setbuswidth){
		switch(arg){
		case 0:
			WR(Control0, r[Control0] & ~Dwidth4);
			break;
		case 2:
			WR(Control0, r[Control0] | Dwidth4);
			break;
		}
	}
	return 0;
}