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); }
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"); }
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"); }
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; }