diff options
author | Gary King <gking@nvidia.com> | 2010-05-20 21:24:43 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-05-21 19:34:57 -0700 |
commit | 303b737304f4d57cfc9f7f9f25ac6f78a23863bf (patch) | |
tree | 03d051bfce43fa092b82a5d6cde65534ecd3ae04 | |
parent | 74ca02c6b6f74770e1170d84cbb191e3874315de (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.
Change-Id: Id58abaffddda7d7aeded8573f4aba6cc0c903a24
-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 | 21 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 4 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 3 |
6 files changed, 65 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 32af45c419f4..2ad71ba187df 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 + /* for sector-addressed cards, this will cause csd->capacity to wrap */ + 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); @@ -221,8 +225,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 8fe5e9ece251..79c3c32b6f1c 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 c279fbc4c2e5..2d47bf53a88c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -900,7 +900,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. */ + sdhci_writel(host, cmd->arg + (host->start_offset >> 9), + SDHCI_ARGUMENT); + } else { + sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT); + } +#else sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT); +#endif sdhci_set_transfer_mode(host, cmd->data); @@ -1216,11 +1226,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 }; /*****************************************************************************\ diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index ce5f1d73dc04..98aa621fd22b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -286,6 +286,10 @@ 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; }; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index c3b88ff5654f..31450dc27a43 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -107,6 +107,9 @@ struct mmc_host_ops { int (*get_cd)(struct mmc_host *host); void (*enable_sdio_irq)(struct mmc_host *host, int enable); +#ifdef CONFIG_EMBEDDED_MMC_START_OFFSET + unsigned int (*get_host_offset)(struct mmc_host *host); +#endif }; struct mmc_card; |