diff options
author | Gary King <gking@nvidia.com> | 2009-12-07 18:01:10 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2009-12-07 21:40:18 -0800 |
commit | 3d75c203e23751cb8201371d82e6236a58a2d2ca (patch) | |
tree | f11f308ec2dd770eda79190a44da5c57481db1e6 /drivers/mmc | |
parent | 4d0aa11e0bd9715b33645abc2bb2c9401e2e6d1b (diff) |
mmc: Add CONFIG_EMBEDDED_MMC_START_OFFSET configuration
enables platforms to specify a non-zero offset for the MBR and kernel-visible
file systems, for embedded systems which store proprietary data at the start
of the eMMC device.
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/Kconfig | 12 | ||||
-rw-r--r-- | drivers/mmc/core/mmc.c | 15 | ||||
-rw-r--r-- | drivers/mmc/core/sd.c | 11 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 28 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 7 |
5 files changed, 72 insertions, 1 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index f2eeb38efa65..1f8494e86d34 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -12,6 +12,18 @@ menuconfig MMC If you want MMC/SD/SDIO support, you should say Y here and also to your specific host controller driver. +config EMBEDDED_MMC_START_OFFSET + bool "MMC start sector offset" + depends on MMC != n + help + This enables a per-controller fixed offset in sectors / bytes to + the location of the master boot record in the device, and reduces + the capacity of the device by a corresponding amount. This is + primarily used by embedded systems with embedded MMC storage where + the initial sectors are used by boot firmware. If you do not know + if this applies to your system, say N here. + + config MMC_DEBUG bool "MMC debugging" depends on MMC != n diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3e35075b7a13..c49b21decbf1 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -141,6 +141,10 @@ static int mmc_decode_csd(struct mmc_card *card) e = UNSTUFF_BITS(resp, 47, 3); m = UNSTUFF_BITS(resp, 62, 12); csd->capacity = (1 + m) << (e + 2); +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + BUG_ON(card->host->ops->get_host_offset(card->host) >= csd->capacity); + csd->capacity -= card->host->ops->get_host_offset(card->host); +#endif csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); csd->read_partial = UNSTUFF_BITS(resp, 79, 1); @@ -222,8 +226,17 @@ static int mmc_read_ext_csd(struct mmc_card *card) ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; - if (card->ext_csd.sectors) + if (card->ext_csd.sectors) { +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + unsigned offs; + offs = card->host->ops->get_host_offset(card->host); + offs >>= 9; + BUG_ON(offs >= card->ext_csd.sectors); + card->ext_csd.sectors -= offs; +#endif mmc_card_set_blockaddr(card); + } + } switch (ext_csd[EXT_CSD_CARD_TYPE]) { diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 9486936f7ed6..b5ee533f0e29 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -110,6 +110,11 @@ static int mmc_decode_csd(struct mmc_card *card) e = UNSTUFF_BITS(resp, 47, 3); m = UNSTUFF_BITS(resp, 62, 12); csd->capacity = (1 + m) << (e + 2); +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + BUG_ON(card->host->ops->get_host_offset(card->host) >= + csd->capacity); + csd->capacity -= card->host->ops->get_host_offset(card->host); +#endif csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); csd->read_partial = UNSTUFF_BITS(resp, 79, 1); @@ -138,6 +143,12 @@ static int mmc_decode_csd(struct mmc_card *card) m = UNSTUFF_BITS(resp, 48, 22); csd->capacity = (1 + m) << 10; +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + BUG_ON((card->host->ops->get_host_offset(card->host) >> 9) >= + csd->capacity); + csd->capacity -= + (card->host->ops->get_host_offset(card->host) >> 9); +#endif csd->read_blkbits = 9; csd->read_partial = 0; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index accb592764ed..09a5c6d8e168 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -821,7 +821,17 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) sdhci_prepare_data(host, cmd->data); +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + if (cmd->data) { + /* It is assumed that the device is block addressed. */ + writel(cmd->arg + (host->start_offset >> 9), + host->ioaddr + SDHCI_ARGUMENT); + } else { + writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT); + } +#else writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT); +#endif sdhci_set_transfer_mode(host, cmd->data); @@ -1120,11 +1130,22 @@ out: spin_unlock_irqrestore(&host->lock, flags); } +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET +static unsigned int sdhci_get_host_offset(struct mmc_host *mmc) { + struct sdhci_host *host; + host = mmc_priv(mmc); + return host->start_offset; +} +#endif + static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, .get_ro = sdhci_get_ro, .enable_sdio_irq = sdhci_enable_sdio_irq, +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + .get_host_offset = sdhci_get_host_offset, +#endif }; /*****************************************************************************\ @@ -1612,6 +1633,13 @@ int sdhci_add_host(struct sdhci_host *host) mmc_dev(host->mmc)->dma_mask = &host->dma_mask; } +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + if (host->ops->get_startoffset) + host->start_offset = host->ops->get_startoffset(host); + else + host->start_offset = 0; +#endif + host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; if (host->max_clk == 0) { diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 43c37c68d07a..7dea10fb06a8 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -262,12 +262,19 @@ struct sdhci_host { struct timer_list timer; /* Timer for timeouts */ +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + unsigned int start_offset; /* Zero-offset for MBR */ +#endif + unsigned long private[0] ____cacheline_aligned; }; struct sdhci_ops { int (*enable_dma)(struct sdhci_host *host); +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + unsigned int (*get_startoffset)(struct sdhci_host *host); +#endif }; |