diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/Makefile | 4 | ||||
-rw-r--r-- | drivers/mmc/arm_pl180_mmci.c | 133 | ||||
-rw-r--r-- | drivers/mmc/arm_pl180_mmci.h | 27 | ||||
-rw-r--r-- | drivers/mmc/fsl_esdhc.c | 5 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 48 | ||||
-rw-r--r-- | drivers/mmc/mxsmmc.c | 208 | ||||
-rw-r--r-- | drivers/mmc/pxa_mmc_gen.c | 8 | ||||
-rw-r--r-- | drivers/mmc/s5p_sdhci.c | 18 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 30 | ||||
-rw-r--r-- | drivers/mmc/sh_mmcif.c | 2 | ||||
-rw-r--r-- | drivers/mmc/spl_mmc_load.c | 62 | ||||
-rw-r--r-- | drivers/mmc/tegra_mmc.c | 34 | ||||
-rw-r--r-- | drivers/mmc/tegra_mmc.h | 131 |
13 files changed, 328 insertions, 382 deletions
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index c567737..2b96cdc 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -25,6 +25,10 @@ include $(TOPDIR)/config.mk LIB := $(obj)libmmc.o +ifdef CONFIG_SPL_MMC_LOAD +COBJS-$(CONFIG_SPL_MMC_LOAD) += spl_mmc_load.o +endif + COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 09d443e..af1380a 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -32,14 +32,10 @@ #include "arm_pl180_mmci.h" #include <malloc.h> -struct mmc_host { - struct sdi_registers *base; -}; - static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) { u32 hoststatus, statusmask; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL; if ((cmd->resp_type & MMC_RSP_PRESENT)) @@ -53,10 +49,10 @@ static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) writel(statusmask, &host->base->status_clear); if (hoststatus & SDI_STA_CTIMEOUT) { - printf("CMD%d time out\n", cmd->cmdidx); - return -ETIMEDOUT; + debug("CMD%d time out\n", cmd->cmdidx); + return TIMEOUT; } else if ((hoststatus & SDI_STA_CCRCFAIL) && - (cmd->flags & MMC_RSP_CRC)) { + (cmd->resp_type & MMC_RSP_CRC)) { printf("CMD%d CRC error\n", cmd->cmdidx); return -EILSEQ; } @@ -80,7 +76,7 @@ static int do_command(struct mmc *dev, struct mmc_cmd *cmd) { int result; u32 sdi_cmd = 0; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN); @@ -112,7 +108,7 @@ static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize) { u32 *tempbuff = dest; u64 xfercount = blkcount * blksize; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; u32 status, status_err; debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); @@ -168,7 +164,7 @@ static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize) u32 *tempbuff = src; int i; u64 xfercount = blkcount * blksize; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; u32 status, status_err; debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); @@ -227,14 +223,19 @@ static int do_data_transfer(struct mmc *dev, struct mmc_data *data) { int error = -ETIMEDOUT; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; u32 blksz = 0; u32 data_ctrl = 0; u32 data_len = (u32) (data->blocks * data->blocksize); - blksz = (ffs(data->blocksize) - 1); - data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK); - data_ctrl |= SDI_DCTRL_DTEN; + if (!host->version2) { + blksz = (ffs(data->blocksize) - 1); + data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK); + } else { + blksz = data->blocksize; + data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT); + } + data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE; writel(SDI_DTIMER_DEFAULT, &host->base->datatimer); writel(data_len, &host->base->datalength); @@ -257,7 +258,7 @@ static int do_data_transfer(struct mmc *dev, writel(data_ctrl, &host->base->datactrl); error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks, - (u32)data->blocksize); + (u32)data->blocksize); } return error; @@ -280,17 +281,16 @@ static int host_request(struct mmc *dev, /* MMC uses open drain drivers in the enumeration phase */ static int mmc_host_reset(struct mmc *dev) { - struct mmc_host *host = dev->priv; - u32 sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON; + struct pl180_mmc_host *host = dev->priv; - writel(sdi_u32, &host->base->power); + writel(host->pwr_init, &host->base->power); return 0; } static void host_set_ios(struct mmc *dev) { - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; u32 sdi_clkcr; sdi_clkcr = readl(&host->base->clock); @@ -298,15 +298,26 @@ static void host_set_ios(struct mmc *dev) /* Ramp up the clock rate */ if (dev->clock) { u32 clkdiv = 0; + u32 tmp_clock; - if (dev->clock >= dev->f_max) + if (dev->clock >= dev->f_max) { + clkdiv = 0; dev->clock = dev->f_max; + } else { + clkdiv = (host->clock_in / dev->clock) - 2; + } - clkdiv = ((ARM_MCLK / dev->clock) / 2) - 1; + tmp_clock = host->clock_in / (clkdiv + 2); + while (tmp_clock > dev->clock) { + clkdiv++; + tmp_clock = host->clock_in / (clkdiv + 2); + } if (clkdiv > SDI_CLKCR_CLKDIV_MASK) clkdiv = SDI_CLKCR_CLKDIV_MASK; + tmp_clock = host->clock_in / (clkdiv + 2); + dev->clock = tmp_clock; sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK); sdi_clkcr |= clkdiv; } @@ -322,8 +333,11 @@ static void host_set_ios(struct mmc *dev) case 4: buswidth |= SDI_CLKCR_WIDBUS_4; break; + case 8: + buswidth |= SDI_CLKCR_WIDBUS_8; + break; default: - printf("Invalid bus width\n"); + printf("Invalid bus width: %d\n", dev->bus_width); break; } sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK); @@ -334,83 +348,40 @@ static void host_set_ios(struct mmc *dev) udelay(CLK_CHANGE_DELAY); } -struct mmc *alloc_mmc_struct(void) -{ - struct mmc_host *host = NULL; - struct mmc *mmc_device = NULL; - - host = malloc(sizeof(struct mmc_host)); - if (!host) - return NULL; - - mmc_device = malloc(sizeof(struct mmc)); - if (!mmc_device) - goto err; - - mmc_device->priv = host; - return mmc_device; - -err: - free(host); - return NULL; -} - /* * mmc_host_init - initialize the mmc controller. * Set initial clock and power for mmc slot. * Initialize mmc struct and register with mmc framework. */ -static int arm_pl180_mmci_host_init(struct mmc *dev) +int arm_pl180_mmci_init(struct pl180_mmc_host *host) { - struct mmc_host *host = dev->priv; + struct mmc *dev; u32 sdi_u32; - host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; + dev = malloc(sizeof(struct mmc)); + if (!dev) + return -ENOMEM; - /* Initially set power-on, full voltage & MMCI read */ - sdi_u32 = INIT_PWR; - writel(sdi_u32, &host->base->power); + memset(dev, 0, sizeof(struct mmc)); + dev->priv = host; - /* setting clk freq 505KHz */ - sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN; - writel(sdi_u32, &host->base->clock); + writel(host->pwr_init, &host->base->power); + writel(host->clkdiv_init, &host->base->clock); udelay(CLK_CHANGE_DELAY); /* Disable mmc interrupts */ sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK; writel(sdi_u32, &host->base->mask0); - - sprintf(dev->name, "MMC"); - dev->clock = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT + 1)); + strncpy(dev->name, host->name, sizeof(dev->name)); dev->send_cmd = host_request; dev->set_ios = host_set_ios; dev->init = mmc_host_reset; dev->getcd = NULL; - dev->host_caps = 0; - dev->voltages = VOLTAGE_WINDOW_MMC; - dev->f_min = dev->clock; - dev->f_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; - - return 0; -} - -int arm_pl180_mmci_init(void) -{ - int error; - struct mmc *dev; - - dev = alloc_mmc_struct(); - if (!dev) - return -1; - - error = arm_pl180_mmci_host_init(dev); - if (error) { - printf("mmci_host_init error - %d\n", error); - return -1; - } - - dev->b_max = 0; - + dev->host_caps = host->caps; + dev->voltages = host->voltages; + dev->f_min = host->clock_min; + dev->f_max = host->clock_max; + dev->b_max = host->b_max; mmc_register(dev); debug("registered mmc interface number is:%d\n", dev->block_dev.dev); diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index 42fbe3e..06709ed 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -26,8 +26,6 @@ #ifndef __ARM_PL180_MMCI_H__ #define __ARM_PL180_MMCI_H__ -int arm_pl180_mmci_init(void); - #define COMMAND_REG_DELAY 300 #define DATA_REG_DELAY 1000 #define CLK_CHANGE_DELAY 2000 @@ -59,8 +57,13 @@ int arm_pl180_mmci_init(void); #define SDI_CLKCR_WIDBUS_MASK 0x00001800 #define SDI_CLKCR_WIDBUS_1 0x00000000 #define SDI_CLKCR_WIDBUS_4 0x00000800 +/* V2 only */ +#define SDI_CLKCR_WIDBUS_8 0x00001000 +#define SDI_CLKCR_NEDGE 0x00002000 +#define SDI_CLKCR_HWFC_EN 0x00004000 -#define SDI_CLKCR_CLKDIV_INIT 0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */ +#define SDI_CLKCR_CLKDIV_INIT_V1 0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */ +#define SDI_CLKCR_CLKDIV_INIT_V2 0x000000FD /* SDI command register bits */ #define SDI_CMD_CMDINDEX_MASK 0x000000FF @@ -144,6 +147,8 @@ int arm_pl180_mmci_init(void); #define SDI_DCTRL_DBOOTMODEEN 0x00002000 #define SDI_DCTRL_BUSYMODE 0x00004000 #define SDI_DCTRL_DDR_MODE 0x00008000 +#define SDI_DCTRL_DBLOCKSIZE_V2_MASK 0x7fff0000 +#define SDI_DCTRL_DBLOCKSIZE_V2_SHIFT 16 #define SDI_FIFO_BURST_SIZE 8 @@ -180,4 +185,20 @@ struct sdi_registers { u32 pcell_id3; /* 0xFFC*/ }; +struct pl180_mmc_host { + struct sdi_registers *base; + char name[32]; + unsigned int b_max; + unsigned int voltages; + unsigned int caps; + unsigned int clock_in; + unsigned int clock_min; + unsigned int clock_max; + unsigned int clkdiv_init; + unsigned int pwr_init; + int version2; +}; + +int arm_pl180_mmci_init(struct pl180_mmc_host *); + #endif diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index b6c969d..3f8d30d 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -479,9 +479,10 @@ static int esdhc_init(struct mmc *mmc) while ((esdhc_read32(®s->sysctl) & SYSCTL_RSTA) && --timeout) udelay(1000); +#ifndef ARCH_MXC /* Enable cache snooping */ - if (cfg && !cfg->no_snoop) - esdhc_write32(®s->scr, 0x00000040); + esdhc_write32(®s->scr, 0x00000040); +#endif esdhc_write32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN); diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index c1c2862..a60cfe1 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -151,7 +151,6 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) printf("CMD_SEND:%d\n", cmd->cmdidx); printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); - printf("\t\tFLAG\t\t\t %d\n", cmd->flags); ret = mmc->send_cmd(mmc, cmd, data); switch (cmd->resp_type) { case MMC_RSP_NONE: @@ -213,7 +212,6 @@ int mmc_send_status(struct mmc *mmc, int timeout) cmd.resp_type = MMC_RSP_R1; if (!mmc_host_is_spi(mmc)) cmd.cmdarg = mmc->rca << 16; - cmd.flags = 0; do { err = mmc_send_cmd(mmc, &cmd, NULL); @@ -238,7 +236,7 @@ int mmc_send_status(struct mmc *mmc, int timeout) status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; printf("CURR STATE:%d\n", status); #endif - if (!timeout) { + if (timeout <= 0) { printf("Timeout waiting card ready\n"); return TIMEOUT; } @@ -253,7 +251,6 @@ int mmc_set_blocklen(struct mmc *mmc, int len) cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = len; - cmd.flags = 0; return mmc_send_cmd(mmc, &cmd, NULL); } @@ -299,7 +296,6 @@ static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt) cmd.cmdidx = start_cmd; cmd.cmdarg = start; cmd.resp_type = MMC_RSP_R1; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); if (err) @@ -386,7 +382,6 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) cmd.cmdarg = start * mmc->write_bl_len; cmd.resp_type = MMC_RSP_R1; - cmd.flags = 0; data.src = src; data.blocks = blkcnt; @@ -405,7 +400,6 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; cmd.cmdarg = 0; cmd.resp_type = MMC_RSP_R1b; - cmd.flags = 0; if (mmc_send_cmd(mmc, &cmd, NULL)) { printf("mmc fail to send stop cmd\n"); return 0; @@ -459,7 +453,6 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) cmd.cmdarg = start * mmc->read_bl_len; cmd.resp_type = MMC_RSP_R1; - cmd.flags = 0; data.dest = dst; data.blocks = blkcnt; @@ -473,7 +466,6 @@ int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; cmd.cmdarg = 0; cmd.resp_type = MMC_RSP_R1b; - cmd.flags = 0; if (mmc_send_cmd(mmc, &cmd, NULL)) { printf("mmc fail to send stop cmd\n"); return 0; @@ -525,7 +517,6 @@ int mmc_go_idle(struct mmc* mmc) cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; cmd.cmdarg = 0; cmd.resp_type = MMC_RSP_NONE; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -548,7 +539,6 @@ sd_send_op_cond(struct mmc *mmc) cmd.cmdidx = MMC_CMD_APP_CMD; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = 0; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -589,7 +579,6 @@ sd_send_op_cond(struct mmc *mmc) cmd.cmdidx = MMC_CMD_SPI_READ_OCR; cmd.resp_type = MMC_RSP_R3; cmd.cmdarg = 0; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -618,7 +607,6 @@ int mmc_send_op_cond(struct mmc *mmc) cmd.cmdidx = MMC_CMD_SEND_OP_COND; cmd.resp_type = MMC_RSP_R3; cmd.cmdarg = 0; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -638,8 +626,6 @@ int mmc_send_op_cond(struct mmc *mmc) if (mmc->host_caps & MMC_MODE_HC) cmd.cmdarg |= OCR_HCS; - cmd.flags = 0; - err = mmc_send_cmd(mmc, &cmd, NULL); if (err) @@ -655,7 +641,6 @@ int mmc_send_op_cond(struct mmc *mmc) cmd.cmdidx = MMC_CMD_SPI_READ_OCR; cmd.resp_type = MMC_RSP_R3; cmd.cmdarg = 0; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -673,7 +658,7 @@ int mmc_send_op_cond(struct mmc *mmc) } -int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd) +int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) { struct mmc_cmd cmd; struct mmc_data data; @@ -683,9 +668,8 @@ int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd) cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = 0; - cmd.flags = 0; - data.dest = ext_csd; + data.dest = (char *)ext_csd; data.blocks = 1; data.blocksize = 512; data.flags = MMC_DATA_READ; @@ -707,7 +691,6 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8); - cmd.flags = 0; ret = mmc_send_cmd(mmc, &cmd, NULL); @@ -721,7 +704,7 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) int mmc_change_freq(struct mmc *mmc) { - ALLOC_CACHE_ALIGN_BUFFER(char, ext_csd, 512); + ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, 512); char cardtype; int err; @@ -800,7 +783,6 @@ int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) cmd.cmdarg = (mode << 31) | 0xffffff; cmd.cmdarg &= ~(0xf << (group * 4)); cmd.cmdarg |= value << (group * 4); - cmd.flags = 0; data.dest = (char *)resp; data.blocksize = 64; @@ -829,7 +811,6 @@ int sd_change_freq(struct mmc *mmc) cmd.cmdidx = MMC_CMD_APP_CMD; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = mmc->rca << 16; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -839,7 +820,6 @@ int sd_change_freq(struct mmc *mmc) cmd.cmdidx = SD_CMD_APP_SEND_SCR; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = 0; - cmd.flags = 0; timeout = 3; @@ -983,8 +963,8 @@ int mmc_startup(struct mmc *mmc) uint mult, freq; u64 cmult, csize, capacity; struct mmc_cmd cmd; - ALLOC_CACHE_ALIGN_BUFFER(char, ext_csd, 512); - ALLOC_CACHE_ALIGN_BUFFER(char, test_csd, 512); + ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, 512); + ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, 512); int timeout = 1000; #ifdef CONFIG_MMC_SPI_CRC_ON @@ -992,7 +972,6 @@ int mmc_startup(struct mmc *mmc) cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = 1; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); if (err) @@ -1005,7 +984,6 @@ int mmc_startup(struct mmc *mmc) MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ cmd.resp_type = MMC_RSP_R2; cmd.cmdarg = 0; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -1023,7 +1001,6 @@ int mmc_startup(struct mmc *mmc) cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; cmd.cmdarg = mmc->rca << 16; cmd.resp_type = MMC_RSP_R6; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -1038,7 +1015,6 @@ int mmc_startup(struct mmc *mmc) cmd.cmdidx = MMC_CMD_SEND_CSD; cmd.resp_type = MMC_RSP_R2; cmd.cmdarg = mmc->rca << 16; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -1115,7 +1091,6 @@ int mmc_startup(struct mmc *mmc) cmd.cmdidx = MMC_CMD_SELECT_CARD; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = mmc->rca << 16; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); if (err) @@ -1162,7 +1137,8 @@ int mmc_startup(struct mmc *mmc) } /* store the partition info of emmc */ - if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) + if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || + ext_csd[EXT_CSD_BOOT_MULT]) mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; } @@ -1182,7 +1158,6 @@ int mmc_startup(struct mmc *mmc) cmd.cmdidx = MMC_CMD_APP_CMD; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = mmc->rca << 16; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); if (err) @@ -1191,7 +1166,6 @@ int mmc_startup(struct mmc *mmc) cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = 2; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); if (err) return err; @@ -1259,7 +1233,9 @@ int mmc_startup(struct mmc *mmc) (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff); sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28, (mmc->cid[2] >> 24) & 0xf); +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) init_part(&mmc->block_dev); +#endif return 0; } @@ -1273,7 +1249,6 @@ int mmc_send_if_cond(struct mmc *mmc) /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa; cmd.resp_type = MMC_RSP_R7; - cmd.flags = 0; err = mmc_send_cmd(mmc, &cmd, NULL); @@ -1311,10 +1286,9 @@ int mmc_register(struct mmc *mmc) block_dev_desc_t *mmc_get_dev(int dev) { struct mmc *mmc = find_mmc_device(dev); - if (!mmc) + if (!mmc || mmc_init(mmc)) return NULL; - mmc_init(mmc); return &mmc->block_dev; } #endif diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index 4187a94..c80b41b 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -43,16 +43,9 @@ #include <asm/arch/sys_proto.h> #include <asm/arch/dma.h> -/* - * CONFIG_MXS_MMC_DMA: This feature is highly experimental and has no - * performance benefit unless you operate the platform with - * data cache enabled. This is disabled by default, enable - * only if you know what you're doing. - */ - struct mxsmmc_priv { int id; - struct mx28_ssp_regs *regs; + struct mxs_ssp_regs *regs; uint32_t clkseq_bypass; uint32_t *clkctrl_ssp; uint32_t buswidth; @@ -61,6 +54,91 @@ struct mxsmmc_priv { }; #define MXSMMC_MAX_TIMEOUT 10000 +#define MXSMMC_SMALL_TRANSFER 512 + +static int mxsmmc_send_cmd_pio(struct mxsmmc_priv *priv, struct mmc_data *data) +{ + struct mxs_ssp_regs *ssp_regs = priv->regs; + uint32_t *data_ptr; + int timeout = MXSMMC_MAX_TIMEOUT; + uint32_t reg; + uint32_t data_count = data->blocksize * data->blocks; + + if (data->flags & MMC_DATA_READ) { + data_ptr = (uint32_t *)data->dest; + while (data_count && --timeout) { + reg = readl(&ssp_regs->hw_ssp_status); + if (!(reg & SSP_STATUS_FIFO_EMPTY)) { + *data_ptr++ = readl(&ssp_regs->hw_ssp_data); + data_count -= 4; + timeout = MXSMMC_MAX_TIMEOUT; + } else + udelay(1000); + } + } else { + data_ptr = (uint32_t *)data->src; + timeout *= 100; + while (data_count && --timeout) { + reg = readl(&ssp_regs->hw_ssp_status); + if (!(reg & SSP_STATUS_FIFO_FULL)) { + writel(*data_ptr++, &ssp_regs->hw_ssp_data); + data_count -= 4; + timeout = MXSMMC_MAX_TIMEOUT; + } else + udelay(1000); + } + } + + return timeout ? 0 : COMM_ERR; +} + +static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data) +{ + uint32_t data_count = data->blocksize * data->blocks; + uint32_t cache_data_count; + int dmach; + struct mxs_dma_desc *desc = priv->desc; + + memset(desc, 0, sizeof(struct mxs_dma_desc)); + desc->address = (dma_addr_t)desc; + + if (data_count % ARCH_DMA_MINALIGN) + cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN); + else + cache_data_count = data_count; + + if (data->flags & MMC_DATA_READ) { + priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; + priv->desc->cmd.address = (dma_addr_t)data->dest; + } else { + priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; + priv->desc->cmd.address = (dma_addr_t)data->src; + + /* Flush data to DRAM so DMA can pick them up */ + flush_dcache_range((uint32_t)priv->desc->cmd.address, + (uint32_t)(priv->desc->cmd.address + cache_data_count)); + } + + /* Invalidate the area, so no writeback into the RAM races with DMA */ + invalidate_dcache_range((uint32_t)priv->desc->cmd.address, + (uint32_t)(priv->desc->cmd.address + cache_data_count)); + + priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | + (data_count << MXS_DMA_DESC_BYTES_OFFSET); + + dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + priv->id; + mxs_dma_desc_append(dmach, priv->desc); + if (mxs_dma_go(dmach)) + return COMM_ERR; + + /* The data arrived into DRAM, invalidate cache over them */ + if (data->flags & MMC_DATA_READ) { + invalidate_dcache_range((uint32_t)priv->desc->cmd.address, + (uint32_t)(priv->desc->cmd.address + cache_data_count)); + } + + return 0; +} /* * Sends a command out on the bus. Takes the mmc pointer, @@ -70,16 +148,11 @@ static int mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv; - struct mx28_ssp_regs *ssp_regs = priv->regs; + struct mxs_ssp_regs *ssp_regs = priv->regs; uint32_t reg; int timeout; - uint32_t data_count; uint32_t ctrl0; -#ifndef CONFIG_MXS_MMC_DMA - uint32_t *data_ptr; -#else - uint32_t cache_data_count; -#endif + int ret; debug("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx); @@ -117,6 +190,11 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (cmd->resp_type & MMC_RSP_136) /* It's a 136 bits response */ ctrl0 |= SSP_CTRL0_LONG_RESP; + if (data && (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER)) + writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_clr); + else + writel(SSP_CTRL1_DMA_ENABLE, &ssp_regs->hw_ssp_ctrl1_set); + /* Command index */ reg = readl(&ssp_regs->hw_ssp_cmd0); reg &= ~(SSP_CMD0_CMD_MASK | SSP_CMD0_APPEND_8CYC); @@ -197,75 +275,23 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) if (!data) return 0; - data_count = data->blocksize * data->blocks; - timeout = MXSMMC_MAX_TIMEOUT; - -#ifdef CONFIG_MXS_MMC_DMA - if (data_count % ARCH_DMA_MINALIGN) - cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN); - else - cache_data_count = data_count; - - if (data->flags & MMC_DATA_READ) { - priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE; - priv->desc->cmd.address = (dma_addr_t)data->dest; - } else { - priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ; - priv->desc->cmd.address = (dma_addr_t)data->src; - - /* Flush data to DRAM so DMA can pick them up */ - flush_dcache_range((uint32_t)priv->desc->cmd.address, - (uint32_t)(priv->desc->cmd.address + cache_data_count)); - } - - priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM | - (data_count << MXS_DMA_DESC_BYTES_OFFSET); - - - mxs_dma_desc_append(MXS_DMA_CHANNEL_AHB_APBH_SSP0, priv->desc); - if (mxs_dma_go(MXS_DMA_CHANNEL_AHB_APBH_SSP0)) { - printf("MMC%d: DMA transfer failed\n", mmc->block_dev.dev); - return COMM_ERR; - } - - /* The data arrived into DRAM, invalidate cache over them */ - if (data->flags & MMC_DATA_READ) { - invalidate_dcache_range((uint32_t)priv->desc->cmd.address, - (uint32_t)(priv->desc->cmd.address + cache_data_count)); - } -#else - if (data->flags & MMC_DATA_READ) { - data_ptr = (uint32_t *)data->dest; - while (data_count && --timeout) { - reg = readl(&ssp_regs->hw_ssp_status); - if (!(reg & SSP_STATUS_FIFO_EMPTY)) { - *data_ptr++ = readl(&ssp_regs->hw_ssp_data); - data_count -= 4; - timeout = MXSMMC_MAX_TIMEOUT; - } else - udelay(1000); + if (data->blocksize * data->blocks < MXSMMC_SMALL_TRANSFER) { + ret = mxsmmc_send_cmd_pio(priv, data); + if (ret) { + printf("MMC%d: Data timeout with command %d " + "(status 0x%08x)!\n", + mmc->block_dev.dev, cmd->cmdidx, reg); + return ret; } } else { - data_ptr = (uint32_t *)data->src; - timeout *= 100; - while (data_count && --timeout) { - reg = readl(&ssp_regs->hw_ssp_status); - if (!(reg & SSP_STATUS_FIFO_FULL)) { - writel(*data_ptr++, &ssp_regs->hw_ssp_data); - data_count -= 4; - timeout = MXSMMC_MAX_TIMEOUT; - } else - udelay(1000); + ret = mxsmmc_send_cmd_dma(priv, data); + if (ret) { + printf("MMC%d: DMA transfer failed\n", + mmc->block_dev.dev); + return ret; } } - if (!timeout) { - printf("MMC%d: Data timeout with command %d (status 0x%08x)!\n", - mmc->block_dev.dev, cmd->cmdidx, reg); - return COMM_ERR; - } -#endif - /* Check data errors */ reg = readl(&ssp_regs->hw_ssp_status); if (reg & @@ -282,7 +308,7 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) static void mxsmmc_set_ios(struct mmc *mmc) { struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv; - struct mx28_ssp_regs *ssp_regs = priv->regs; + struct mxs_ssp_regs *ssp_regs = priv->regs; /* Set the clock speed */ if (mmc->clock) @@ -311,16 +337,16 @@ static void mxsmmc_set_ios(struct mmc *mmc) static int mxsmmc_init(struct mmc *mmc) { struct mxsmmc_priv *priv = (struct mxsmmc_priv *)mmc->priv; - struct mx28_ssp_regs *ssp_regs = priv->regs; + struct mxs_ssp_regs *ssp_regs = priv->regs; /* Reset SSP */ - mx28_reset_block(&ssp_regs->hw_ssp_ctrl0_reg); + mxs_reset_block(&ssp_regs->hw_ssp_ctrl0_reg); /* 8 bits word length in MMC mode */ clrsetbits_le32(&ssp_regs->hw_ssp_ctrl1, - SSP_CTRL1_SSP_MODE_MASK | SSP_CTRL1_WORD_LENGTH_MASK, - SSP_CTRL1_SSP_MODE_SD_MMC | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS | - SSP_CTRL1_DMA_ENABLE); + SSP_CTRL1_SSP_MODE_MASK | SSP_CTRL1_WORD_LENGTH_MASK | + SSP_CTRL1_DMA_ENABLE, + SSP_CTRL1_SSP_MODE_SD_MMC | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS); /* Set initial bit clock 400 KHz */ mx28_set_ssp_busclock(priv->id, 400); @@ -335,8 +361,8 @@ static int mxsmmc_init(struct mmc *mmc) int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int)) { - struct mx28_clkctrl_regs *clkctrl_regs = - (struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE; + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; struct mmc *mmc = NULL; struct mxsmmc_priv *priv = NULL; int ret; @@ -366,22 +392,22 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int)) priv->id = id; switch (id) { case 0: - priv->regs = (struct mx28_ssp_regs *)MXS_SSP0_BASE; + priv->regs = (struct mxs_ssp_regs *)MXS_SSP0_BASE; priv->clkseq_bypass = CLKCTRL_CLKSEQ_BYPASS_SSP0; priv->clkctrl_ssp = &clkctrl_regs->hw_clkctrl_ssp0; break; case 1: - priv->regs = (struct mx28_ssp_regs *)MXS_SSP1_BASE; + priv->regs = (struct mxs_ssp_regs *)MXS_SSP1_BASE; priv->clkseq_bypass = CLKCTRL_CLKSEQ_BYPASS_SSP1; priv->clkctrl_ssp = &clkctrl_regs->hw_clkctrl_ssp1; break; case 2: - priv->regs = (struct mx28_ssp_regs *)MXS_SSP2_BASE; + priv->regs = (struct mxs_ssp_regs *)MXS_SSP2_BASE; priv->clkseq_bypass = CLKCTRL_CLKSEQ_BYPASS_SSP2; priv->clkctrl_ssp = &clkctrl_regs->hw_clkctrl_ssp2; break; case 3: - priv->regs = (struct mx28_ssp_regs *)MXS_SSP3_BASE; + priv->regs = (struct mxs_ssp_regs *)MXS_SSP3_BASE; priv->clkseq_bypass = CLKCTRL_CLKSEQ_BYPASS_SSP3; priv->clkctrl_ssp = &clkctrl_regs->hw_clkctrl_ssp3; break; diff --git a/drivers/mmc/pxa_mmc_gen.c b/drivers/mmc/pxa_mmc_gen.c index 2c5bf17..b3ec441 100644 --- a/drivers/mmc/pxa_mmc_gen.c +++ b/drivers/mmc/pxa_mmc_gen.c @@ -118,7 +118,7 @@ static int pxa_mmc_start_cmd(struct mmc *mmc, struct mmc_cmd *cmd, int ret; /* The card can send a "busy" response */ - if (cmd->flags & MMC_RSP_BUSY) + if (cmd->resp_type & MMC_RSP_BUSY) cmdat |= MMC_CMDAT_BUSY; /* Inform the controller about response type */ @@ -181,9 +181,11 @@ static int pxa_mmc_cmd_done(struct mmc *mmc, struct mmc_cmd *cmd) /* The command response didn't arrive */ if (stat & MMC_STAT_TIME_OUT_RESPONSE) return -ETIMEDOUT; - else if (stat & MMC_STAT_RES_CRC_ERROR && cmd->flags & MMC_RSP_CRC) { + else if (stat & MMC_STAT_RES_CRC_ERROR + && cmd->resp_type & MMC_RSP_CRC) { #ifdef PXAMMC_CRC_SKIP - if (cmd->flags & MMC_RSP_136 && cmd->response[0] & (1 << 31)) + if (cmd->resp_type & MMC_RSP_136 + && cmd->response[0] & (1 << 31)) printf("Ignoring CRC, this may be dangerous!\n"); else #endif diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index 1d4481b..b978236 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -21,6 +21,7 @@ #include <malloc.h> #include <sdhci.h> #include <asm/arch/mmc.h> +#include <asm/arch/clk.h> static char *S5P_NAME = "SAMSUNG SDHCI"; static void s5p_sdhci_set_control_reg(struct sdhci_host *host) @@ -54,7 +55,7 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host) * 00 = Delay3 (inverter delay) * 10 = Delay4 (inverter delay + 2ns) */ - val = SDHCI_CTRL3_FCSEL3 | SDHCI_CTRL3_FCSEL1; + val = SDHCI_CTRL3_FCSEL0 | SDHCI_CTRL3_FCSEL1; sdhci_writel(host, val, SDHCI_CONTROL3); /* @@ -69,7 +70,7 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host) sdhci_writel(host, ctrl, SDHCI_CONTROL2); } -int s5p_sdhci_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks) +int s5p_sdhci_init(u32 regbase, int index, int bus_width) { struct sdhci_host *host = NULL; host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); @@ -80,19 +81,18 @@ int s5p_sdhci_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks) host->name = S5P_NAME; host->ioaddr = (void *)regbase; - host->quirks = quirks; - host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE; + host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | + SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR; host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - if (quirks & SDHCI_QUIRK_REG32_RW) - host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16; - else - host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); host->set_control_reg = &s5p_sdhci_set_control_reg; + host->set_clock = set_mmc_clk; + host->index = index; host->host_caps = MMC_MODE_HC; - add_sdhci(host, max_clk, min_clk); + add_sdhci(host, 52000000, 400000); return 0; } diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 1709643..2e3c408 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -260,7 +260,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) if (clock == 0) return 0; - if (host->version >= SDHCI_SPEC_300) { + if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) { /* Version 3.00 divisors must be a multiple of 2. */ if (mmc->f_max <= clock) div = 1; @@ -279,6 +279,9 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) } div >>= 1; + if (host->set_clock) + host->set_clock(host->index, div); + clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; @@ -347,10 +350,10 @@ void sdhci_set_ios(struct mmc *mmc) ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); if (mmc->bus_width == 8) { ctrl &= ~SDHCI_CTRL_4BITBUS; - if (host->version >= SDHCI_SPEC_300) + if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) ctrl |= SDHCI_CTRL_8BITBUS; } else { - if (host->version >= SDHCI_SPEC_300) + if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) ctrl &= ~SDHCI_CTRL_8BITBUS; if (mmc->bus_width == 4) ctrl |= SDHCI_CTRL_4BITBUS; @@ -381,12 +384,25 @@ int sdhci_init(struct mmc *mmc) } } + sdhci_set_power(host, fls(mmc->voltages) - 1); + + if (host->quirks & SDHCI_QUIRK_NO_CD) { + unsigned int status; + + sdhci_writel(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST, + SDHCI_HOST_CONTROL); + + status = sdhci_readl(host, SDHCI_PRESENT_STATE); + while ((!(status & SDHCI_CARD_PRESENT)) || + (!(status & SDHCI_CARD_STATE_STABLE)) || + (!(status & SDHCI_CARD_DETECT_PIN_LEVEL))) + status = sdhci_readl(host, SDHCI_PRESENT_STATE); + } + /* Eable all state */ sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_ENABLE); sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_SIGNAL_ENABLE); - sdhci_set_power(host, fls(mmc->voltages) - 1); - return 0; } @@ -421,7 +437,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) if (max_clk) mmc->f_max = max_clk; else { - if (host->version >= SDHCI_SPEC_300) + if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; else @@ -436,7 +452,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) if (min_clk) mmc->f_min = min_clk; else { - if (host->version >= SDHCI_SPEC_300) + if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_300; else mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_200; diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c index 2835e24..4588568 100644 --- a/drivers/mmc/sh_mmcif.c +++ b/drivers/mmc/sh_mmcif.c @@ -593,7 +593,7 @@ int mmcif_mmc_init(void) mmc->f_max = CLKDEV_EMMC_DATA; mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT | - MMC_MODE_8BIT; + MMC_MODE_8BIT | MMC_MODE_HC; memcpy(mmc->name, DRIVER_NAME, sizeof(DRIVER_NAME)); mmc->send_cmd = sh_mmcif_request; mmc->set_ios = sh_mmcif_set_ios; diff --git a/drivers/mmc/spl_mmc_load.c b/drivers/mmc/spl_mmc_load.c new file mode 100644 index 0000000..79a68fb --- /dev/null +++ b/drivers/mmc/spl_mmc_load.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <mmc.h> + +DECLARE_GLOBAL_DATA_PTR; + +static void mmc_load_image(struct mmc *mmc) +{ + s32 err; + void (*uboot)(void) __noreturn; + + err = mmc->block_dev.block_read(0, CONFIG_SYS_MMC_U_BOOT_OFFS, + CONFIG_SYS_MMC_U_BOOT_SIZE/512, + (u32 *)CONFIG_SYS_TEXT_BASE); + + if (err <= 0) { + printf("spl: error reading image %s, err - %d\n", + "u-boot.img", err); + hang(); + } + uboot = (void *) CONFIG_SYS_TEXT_BASE; + (*uboot)(); +} + +void spl_mmc_load(void) +{ + struct mmc *mmc; + int err; + void (mmc_load_image)(struct mmc *mmc) __noreturn; + + mmc_initialize(gd->bd); + mmc = find_mmc_device(0); + if (!mmc) { + puts("spl: mmc device not found!!\n"); + hang(); + } else { + puts("spl: mmc device found\n"); + } + err = mmc_init(mmc); + if (err) { + printf("spl: mmc init failed: err - %d\n", err); + hang(); + } + mmc_load_image(mmc); +} diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index 29bf583..ca8fad8 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -25,7 +25,7 @@ #include <asm/io.h> #include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> -#include "tegra_mmc.h" +#include <asm/arch/tegra_mmc.h> /* support 4 mmc hosts */ struct mmc mmc_dev[4]; @@ -39,31 +39,31 @@ struct mmc_host mmc_host[4]; * @param host Structure to fill in (base, reg, mmc_id) * @param dev_index Device index (0-3) */ -static void tegra2_get_setup(struct mmc_host *host, int dev_index) +static void tegra_get_setup(struct mmc_host *host, int dev_index) { - debug("tegra2_get_base_mmc: dev_index = %d\n", dev_index); + debug("tegra_get_setup: dev_index = %d\n", dev_index); switch (dev_index) { case 1: - host->base = TEGRA2_SDMMC3_BASE; + host->base = TEGRA_SDMMC3_BASE; host->mmc_id = PERIPH_ID_SDMMC3; break; case 2: - host->base = TEGRA2_SDMMC2_BASE; + host->base = TEGRA_SDMMC2_BASE; host->mmc_id = PERIPH_ID_SDMMC2; break; case 3: - host->base = TEGRA2_SDMMC1_BASE; + host->base = TEGRA_SDMMC1_BASE; host->mmc_id = PERIPH_ID_SDMMC1; break; case 0: default: - host->base = TEGRA2_SDMMC4_BASE; + host->base = TEGRA_SDMMC4_BASE; host->mmc_id = PERIPH_ID_SDMMC4; break; } - host->reg = (struct tegra2_mmc *)host->base; + host->reg = (struct tegra_mmc *)host->base; } static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data) @@ -345,7 +345,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) debug(" mmc_change_clock called\n"); /* - * Change Tegra2 SDMMCx clock divisor here. Source is 216MHz, + * Change Tegra SDMMCx clock divisor here. Source is 216MHz, * PLLP_OUT0 */ if (clock == 0) @@ -494,11 +494,11 @@ static int mmc_core_init(struct mmc *mmc) return 0; } -int tegra2_mmc_getcd(struct mmc *mmc) +int tegra_mmc_getcd(struct mmc *mmc) { struct mmc_host *host = (struct mmc_host *)mmc->priv; - debug("tegra2_mmc_getcd called\n"); + debug("tegra_mmc_getcd called\n"); if (host->cd_gpio >= 0) return !gpio_get_value(host->cd_gpio); @@ -506,13 +506,13 @@ int tegra2_mmc_getcd(struct mmc *mmc) return 1; } -int tegra2_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio) +int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio) { struct mmc_host *host; char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */ struct mmc *mmc; - debug(" tegra2_mmc_init: index %d, bus width %d " + debug(" tegra_mmc_init: index %d, bus width %d " "pwr_gpio %d cd_gpio %d\n", dev_index, bus_width, pwr_gpio, cd_gpio); @@ -521,7 +521,7 @@ int tegra2_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio) host->clock = 0; host->pwr_gpio = pwr_gpio; host->cd_gpio = cd_gpio; - tegra2_get_setup(host, dev_index); + tegra_get_setup(host, dev_index); clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000); @@ -539,12 +539,12 @@ int tegra2_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio) mmc = &mmc_dev[dev_index]; - sprintf(mmc->name, "Tegra2 SD/MMC"); + sprintf(mmc->name, "Tegra SD/MMC"); mmc->priv = host; mmc->send_cmd = mmc_send_cmd; mmc->set_ios = mmc_set_ios; mmc->init = mmc_core_init; - mmc->getcd = tegra2_mmc_getcd; + mmc->getcd = tegra_mmc_getcd; mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; if (bus_width == 8) @@ -559,7 +559,7 @@ int tegra2_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio) * max freq is highest HS eMMC clock as per the SD/MMC spec * (actually 52MHz) * Both of these are the closest equivalents w/216MHz source - * clock and Tegra2 SDMMC divisors. + * clock and Tegra SDMMC divisors. */ mmc->f_min = 375000; mmc->f_max = 48000000; diff --git a/drivers/mmc/tegra_mmc.h b/drivers/mmc/tegra_mmc.h deleted file mode 100644 index f9cdcaa..0000000 --- a/drivers/mmc/tegra_mmc.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * (C) Copyright 2009 SAMSUNG Electronics - * Minkyu Kang <mk7.kang@samsung.com> - * Portions Copyright (C) 2011-2012 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __TEGRA_MMC_H_ -#define __TEGRA_MMC_H_ - -#define TEGRA2_SDMMC1_BASE 0xC8000000 -#define TEGRA2_SDMMC2_BASE 0xC8000200 -#define TEGRA2_SDMMC3_BASE 0xC8000400 -#define TEGRA2_SDMMC4_BASE 0xC8000600 - -#ifndef __ASSEMBLY__ -struct tegra2_mmc { - unsigned int sysad; /* _SYSTEM_ADDRESS_0 */ - unsigned short blksize; /* _BLOCK_SIZE_BLOCK_COUNT_0 15:00 */ - unsigned short blkcnt; /* _BLOCK_SIZE_BLOCK_COUNT_0 31:16 */ - unsigned int argument; /* _ARGUMENT_0 */ - unsigned short trnmod; /* _CMD_XFER_MODE_0 15:00 xfer mode */ - unsigned short cmdreg; /* _CMD_XFER_MODE_0 31:16 cmd reg */ - unsigned int rspreg0; /* _RESPONSE_R0_R1_0 CMD RESP 31:00 */ - unsigned int rspreg1; /* _RESPONSE_R2_R3_0 CMD RESP 63:32 */ - unsigned int rspreg2; /* _RESPONSE_R4_R5_0 CMD RESP 95:64 */ - unsigned int rspreg3; /* _RESPONSE_R6_R7_0 CMD RESP 127:96 */ - unsigned int bdata; /* _BUFFER_DATA_PORT_0 */ - unsigned int prnsts; /* _PRESENT_STATE_0 */ - unsigned char hostctl; /* _POWER_CONTROL_HOST_0 7:00 */ - unsigned char pwrcon; /* _POWER_CONTROL_HOST_0 15:8 */ - unsigned char blkgap; /* _POWER_CONTROL_HOST_9 23:16 */ - unsigned char wakcon; /* _POWER_CONTROL_HOST_0 31:24 */ - unsigned short clkcon; /* _CLOCK_CONTROL_0 15:00 */ - unsigned char timeoutcon; /* _TIMEOUT_CTRL 23:16 */ - unsigned char swrst; /* _SW_RESET_ 31:24 */ - unsigned int norintsts; /* _INTERRUPT_STATUS_0 */ - unsigned int norintstsen; /* _INTERRUPT_STATUS_ENABLE_0 */ - unsigned int norintsigen; /* _INTERRUPT_SIGNAL_ENABLE_0 */ - unsigned short acmd12errsts; /* _AUTO_CMD12_ERR_STATUS_0 15:00 */ - unsigned char res1[2]; /* _RESERVED 31:16 */ - unsigned int capareg; /* _CAPABILITIES_0 */ - unsigned char res2[4]; /* RESERVED, offset 44h-47h */ - unsigned int maxcurr; /* _MAXIMUM_CURRENT_0 */ - unsigned char res3[4]; /* RESERVED, offset 4Ch-4Fh */ - unsigned short setacmd12err; /* offset 50h */ - unsigned short setinterr; /* offset 52h */ - unsigned char admaerr; /* offset 54h */ - unsigned char res4[3]; /* RESERVED, offset 55h-57h */ - unsigned long admaaddr; /* offset 58h-5Fh */ - unsigned char res5[0x9c]; /* RESERVED, offset 60h-FBh */ - unsigned short slotintstatus; /* offset FCh */ - unsigned short hcver; /* HOST Version */ - unsigned char res6[0x100]; /* RESERVED, offset 100h-1FFh */ -}; - -#define TEGRA_MMC_HOSTCTL_DMASEL_MASK (3 << 3) -#define TEGRA_MMC_HOSTCTL_DMASEL_SDMA (0 << 3) -#define TEGRA_MMC_HOSTCTL_DMASEL_ADMA2_32BIT (2 << 3) -#define TEGRA_MMC_HOSTCTL_DMASEL_ADMA2_64BIT (3 << 3) - -#define TEGRA_MMC_TRNMOD_DMA_ENABLE (1 << 0) -#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE (1 << 1) -#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE (0 << 4) -#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ (1 << 4) -#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT (1 << 5) - -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK (3 << 0) -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE (0 << 0) -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 (1 << 0) -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 (2 << 0) -#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY (3 << 0) - -#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK (1 << 3) -#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK (1 << 4) -#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER (1 << 5) - -#define TEGRA_MMC_PRNSTS_CMD_INHIBIT_CMD (1 << 0) -#define TEGRA_MMC_PRNSTS_CMD_INHIBIT_DAT (1 << 1) - -#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE (1 << 0) -#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE (1 << 1) -#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE (1 << 2) - -#define TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_SHIFT 8 -#define TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_MASK (0xff << 8) - -#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL (1 << 0) -#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE (1 << 1) -#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE (1 << 2) - -#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE (1 << 0) -#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE (1 << 1) -#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT (1 << 3) -#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT (1 << 15) -#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT (1 << 16) - -#define TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE (1 << 0) -#define TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE (1 << 1) -#define TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT (1 << 3) -#define TEGRA_MMC_NORINTSTSEN_BUFFER_WRITE_READY (1 << 4) -#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY (1 << 5) - -#define TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE (1 << 1) - -struct mmc_host { - struct tegra2_mmc *reg; - unsigned int version; /* SDHCI spec. version */ - unsigned int clock; /* Current clock (MHz) */ - unsigned int base; /* Base address, SDMMC1/2/3/4 */ - enum periph_id mmc_id; /* Peripheral ID: PERIPH_ID_... */ - int pwr_gpio; /* Power GPIO */ - int cd_gpio; /* Change Detect GPIO */ -}; - -#endif /* __ASSEMBLY__ */ -#endif /* __TEGRA_MMC_H_ */ |