/* * This is the only exported function * * Call it with the MCI register base address */ int atmel_mci_init(void *regs) { struct mmc *mmc = malloc(sizeof(struct mmc)); if (!mmc) return -1; strcpy(mmc->name, "mci"); mmc->priv = regs; mmc->send_cmd = mci_send_cmd; mmc->set_ios = mci_set_ios; mmc->init = mci_init; mmc->getcd = NULL; mmc->getwp = NULL; /* need to be able to pass these in on a board by board basis */ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->host_caps = MMC_MODE_4BIT; /* * min and max frequencies determined by * max and min of clock divider */ mmc->f_min = get_mci_clk_rate() / (2*256); mmc->f_max = get_mci_clk_rate() / (2*1); mmc->b_max = 0; mmc_register(mmc); return 0; }
/* Setup for MCI Clock and Block Size */ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen) { atmel_mci_t *mci = (atmel_mci_t *)mmc->priv; u32 bus_hz = get_mci_clk_rate(); u32 clkdiv = 255; debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n", bus_hz, hz, blklen); if (hz > 0) { /* find lowest clkdiv yielding a rate <= than requested */ for (clkdiv=0; clkdiv<255; clkdiv++) { if ((bus_hz / (clkdiv+1) / 2) <= hz) break; } } printf("mci: setting clock %u Hz, block size %u\n", (bus_hz / (clkdiv+1)) / 2, blklen); blklen &= 0xfffc; /* On some platforms RDPROOF and WRPROOF are ignored */ writel((MMCI_BF(CLKDIV, clkdiv) | MMCI_BF(BLKLEN, blklen) | MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF)), &mci->mr); /* * On some new platforms BLKLEN in mci->mr is ignored. * Should use the BLKLEN in the block register. */ writel(MMCI_BF(BLKLEN, blklen), &mci->blkr); initialized = 1; }
/* Setup for MCI Clock and Block Size */ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen) { struct atmel_mci_priv *priv = mmc->priv; atmel_mci_t *mci = priv->mci; u32 bus_hz = get_mci_clk_rate(); u32 clkdiv = 255; unsigned int version = atmel_mci_get_version(mci); u32 clkodd = 0; u32 mr; debug("mci: bus_hz is %u, setting clock %u Hz, block size %u\n", bus_hz, hz, blklen); if (hz > 0) { if (version >= 0x500) { clkdiv = DIV_ROUND_UP(bus_hz, hz) - 2; if (clkdiv > 511) clkdiv = 511; clkodd = clkdiv & 1; clkdiv >>= 1; debug("mci: setting clock %u Hz, block size %u\n", bus_hz / (clkdiv * 2 + clkodd + 2), blklen); } else { /* find clkdiv yielding a rate <= than requested */ for (clkdiv = 0; clkdiv < 255; clkdiv++) {
static void mci_set_mode(unsigned long hz, unsigned long blklen) { unsigned long bus_hz; unsigned long clkdiv; bus_hz = get_mci_clk_rate(); clkdiv = (bus_hz / hz) / 2 - 1; pr_debug("mmc: setting clock %lu Hz, block size %lu\n", hz, blklen); if (clkdiv & ~255UL) { clkdiv = 255; printf("mmc: clock %lu too low; setting CLKDIV to 255\n", hz); } blklen &= 0xfffc; mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) | MMCI_BF(BLKLEN, blklen) | MMCI_BIT(RDPROOF) | MMCI_BIT(WRPROOF))); }