diff --git a/board/armltd/vexpress/ca9x4_ct_vxp.c b/board/armltd/vexpress/ca9x4_ct_vxp.c index 0b36d1280a..d5e109ec06 100644 --- a/board/armltd/vexpress/ca9x4_ct_vxp.c +++ b/board/armltd/vexpress/ca9x4_ct_vxp.c @@ -33,6 +33,8 @@ * MA 02111-1307 USA */ #include +#include +#include #include #include #include @@ -90,8 +92,25 @@ int board_eth_init(bd_t *bis) int cpu_mmc_init(bd_t *bis) { int rc = 0; + (void) bis; #ifdef CONFIG_ARM_PL180_MMCI - rc = arm_pl180_mmci_init(); + struct pl180_mmc_host *host; + + host = malloc(sizeof(struct pl180_mmc_host)); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(*host)); + + strcpy(host->name, "MMC"); + host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; + host->pwr_init = INIT_PWR; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN; + host->voltages = VOLTAGE_WINDOW_MMC; + host->caps = 0; + host->clock_in = ARM_MCLK; + host->clock_min = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); + host->clock_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; + rc = arm_pl180_mmci_init(host); #endif return rc; } diff --git a/board/st-ericsson/snowball/snowball.c b/board/st-ericsson/snowball/snowball.c index 67fc5dfff1..8c743c0adb 100644 --- a/board/st-ericsson/snowball/snowball.c +++ b/board/st-ericsson/snowball/snowball.c @@ -29,6 +29,9 @@ #include #include +#ifdef CONFIG_MMC +#include "../../../drivers/mmc/arm_pl180_mmci.h" +#endif #include "db8500_pins.h" /* @@ -250,9 +253,96 @@ int board_late_init(void) if ((raise_ab8500_gpio16() < 0)) printf("error: cant' raise GPIO16\n"); + return 0; +} + #ifdef CONFIG_MMC +/* + * emmc_host_init - initialize the emmc controller. + * Configure GPIO settings, set initial clock and power for emmc slot. + * Initialize mmc struct and register with mmc framework. + */ +static int emmc_host_init(void) +{ + struct pl180_mmc_host *host; + + host = malloc(sizeof(struct pl180_mmc_host)); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(*host)); + + host->base = (struct sdi_registers *)CFG_EMMC_BASE; + host->pwr_init = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 | + SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN; + strcpy(host->name, "EMMC"); + host->caps = MMC_MODE_8BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz; + host->voltages = VOLTAGE_WINDOW_MMC; + host->clock_min = ARM_MCLK / (2 + SDI_CLKCR_CLKDIV_INIT_V2); + host->clock_max = ARM_MCLK / 2; + host->clock_in = ARM_MCLK; + host->version2 = 1; + + return arm_pl180_mmci_init(host); +} + +/* + * mmc_host_init - initialize the external mmc controller. + * Configure GPIO settings, set initial clock and power for mmc slot. + * Initialize mmc struct and register with mmc framework. + */ +static int mmc_host_init(void) +{ + struct pl180_mmc_host *host; + u32 sdi_u32; + + host = malloc(sizeof(struct pl180_mmc_host)); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(*host)); + + host->base = (struct sdi_registers *)CFG_MMC_BASE; + sdi_u32 = 0xBF; + writel(sdi_u32, &host->base->power); + host->pwr_init = 0xBF; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 | + SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN; + strcpy(host->name, "MMC"); + host->caps = MMC_MODE_8BIT; + host->b_max = 0; + host->voltages = VOLTAGE_WINDOW_SD; + host->clock_min = ARM_MCLK / (2 + SDI_CLKCR_CLKDIV_INIT_V2); + host->clock_max = ARM_MCLK / 2; + host->clock_in = ARM_MCLK; + host->version2 = 1; + + return arm_pl180_mmci_init(host); +} + +/* + * board_mmc_init - initialize all the mmc/sd host controllers. + * Called by generic mmc framework. + */ +int board_mmc_init(bd_t *bis) +{ + int error; + + (void) bis; + + error = emmc_host_init(); + if (error) { + printf("emmc_host_init() %d\n", error); + return -1; + } + u8500_mmc_power_init(); -#endif /* CONFIG_MMC */ + + error = mmc_host_init(); + if (error) { + printf("mmc_host_init() %d\n", error); + return -1; + } return 0; } +#endif /* CONFIG_MMC */ diff --git a/board/st-ericsson/u8500/u8500_href.c b/board/st-ericsson/u8500/u8500_href.c index 3de80dfd69..ec559e33e0 100644 --- a/board/st-ericsson/u8500/u8500_href.c +++ b/board/st-ericsson/u8500/u8500_href.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -374,12 +375,27 @@ static int u8500_mmci_board_init(void) int board_mmc_init(bd_t *bd) { + struct pl180_mmc_host *host; + if (u8500_mmci_board_init()) return -ENODEV; - if (arm_pl180_mmci_init()) - return -ENODEV; - return 0; + host = malloc(sizeof(struct pl180_mmc_host)); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(*host)); + + strcpy(host->name, "MMC"); + host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; + host->pwr_init = INIT_PWR; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN; + host->voltages = VOLTAGE_WINDOW_MMC; + host->caps = 0; + host->clock_in = ARM_MCLK; + host->clock_min = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); + host->clock_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; + + return arm_pl180_mmci_init(host); } #endif diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 09d443ee39..db2c7ab75c 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 -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,8 +49,8 @@ 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)) { printf("CMD%d CRC error\n", cmd->cmdidx); @@ -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 42fbe3e386..06709ed7fb 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/include/configs/snowball.h b/include/configs/snowball.h index ed70d65dfc..30f4a4eb55 100644 --- a/include/configs/snowball.h +++ b/include/configs/snowball.h @@ -228,6 +228,14 @@ #define CONFIG_SYS_TEXT_BASE 0x0 #endif +/* + * MMC related configs + */ +#define CONFIG_ARM_PL180_MMCI +#define MMC_BLOCK_SIZE 512 +#define CFG_EMMC_BASE 0x80114000 +#define CFG_MMC_BASE 0x80126000 + /* * FLASH and environment organization */