summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-05-20 21:24:43 -0700
committerGary King <gking@nvidia.com>2010-05-21 19:34:57 -0700
commit303b737304f4d57cfc9f7f9f25ac6f78a23863bf (patch)
tree03d051bfce43fa092b82a5d6cde65534ecd3ae04
parent74ca02c6b6f74770e1170d84cbb191e3874315de (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/Kconfig12
-rw-r--r--drivers/mmc/core/mmc.c15
-rw-r--r--drivers/mmc/core/sd.c11
-rw-r--r--drivers/mmc/host/sdhci.c21
-rw-r--r--drivers/mmc/host/sdhci.h4
-rw-r--r--include/linux/mmc/host.h3
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;