Merge branch 'master' of git://www.denx.de/git/u-boot-mmc
diff --git a/README b/README
index ac1ec44..cd0336c 100644
--- a/README
+++ b/README
@@ -3648,6 +3648,57 @@
 	  You will probably want to define these to avoid a really noisy system
 	  when storing the env in UBI.
 
+- CONFIG_ENV_IS_IN_MMC:
+
+	Define this if you have an MMC device which you want to use for the
+	environment.
+
+	- CONFIG_SYS_MMC_ENV_DEV:
+
+	  Specifies which MMC device the environment is stored in.
+
+	- CONFIG_SYS_MMC_ENV_PART (optional):
+
+	  Specifies which MMC partition the environment is stored in. If not
+	  set, defaults to partition 0, the user area. Common values might be
+	  1 (first MMC boot partition), 2 (second MMC boot partition).
+
+	- CONFIG_ENV_OFFSET:
+	- CONFIG_ENV_SIZE:
+
+	  These two #defines specify the offset and size of the environment
+	  area within the specified MMC device.
+
+	  If offset is positive (the usual case), it is treated as relative to
+	  the start of the MMC partition. If offset is negative, it is treated
+	  as relative to the end of the MMC partition. This can be useful if
+	  your board may be fitted with different MMC devices, which have
+	  different sizes for the MMC partitions, and you always want the
+	  environment placed at the very end of the partition, to leave the
+	  maximum possible space before it, to store other data.
+
+	  These two values are in units of bytes, but must be aligned to an
+	  MMC sector boundary.
+
+	- CONFIG_ENV_OFFSET_REDUND (optional):
+
+	  Specifies a second storage area, of CONFIG_ENV_SIZE size, used to
+	  hold a redundant copy of the environment data. This provides a
+	  valid backup copy in case the other copy is corrupted, e.g. due
+	  to a power failure during a "saveenv" operation.
+
+	  This value may also be positive or negative; this is handled in the
+	  same way as CONFIG_ENV_OFFSET.
+
+	  This value is also in units of bytes, but must also be aligned to
+	  an MMC sector boundary.
+
+	- CONFIG_ENV_SIZE_REDUND (optional):
+
+	  This value need not be set, even when CONFIG_ENV_OFFSET_REDUND is
+	  set. If this value is set, it must be set to the same value as
+	  CONFIG_ENV_SIZE.
+
 - CONFIG_SYS_SPI_INIT_OFFSET
 
 	Defines offset to the initial SPI buffer area in DPRAM. The
diff --git a/common/env_mmc.c b/common/env_mmc.c
index 9ca098f..5d3a769 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -53,11 +53,19 @@
 
 __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
 {
-	*env_addr = CONFIG_ENV_OFFSET;
+	s64 offset;
+
+	offset = CONFIG_ENV_OFFSET;
 #ifdef CONFIG_ENV_OFFSET_REDUND
 	if (copy)
-		*env_addr = CONFIG_ENV_OFFSET_REDUND;
+		offset = CONFIG_ENV_OFFSET_REDUND;
 #endif
+
+	if (offset < 0)
+		offset += mmc->capacity;
+
+	*env_addr = offset;
+
 	return 0;
 }
 
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 861f4b9..973b19f 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -178,7 +178,7 @@
 	int timeout;
 	struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
 	struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
-#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
+#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
 	uint wml_value;
 
 	wml_value = data->blocksize/4;
@@ -310,6 +310,9 @@
 	/* Figure out the transfer arguments */
 	xfertyp = esdhc_xfertyp(cmd, data);
 
+	/* Mask all irqs */
+	esdhc_write32(&regs->irqsigen, 0);
+
 	/* Send the command */
 	esdhc_write32(&regs->cmdarg, cmd->cmdarg);
 #if defined(CONFIG_FSL_USDHC)
@@ -320,15 +323,11 @@
 	esdhc_write32(&regs->xfertyp, xfertyp);
 #endif
 
-	/* Mask all irqs */
-	esdhc_write32(&regs->irqsigen, 0);
-
 	/* Wait for the command to complete */
 	while (!(esdhc_read32(&regs->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE)))
 		;
 
 	irqstat = esdhc_read32(&regs->irqstat);
-	esdhc_write32(&regs->irqstat, irqstat);
 
 	/* Reset CMD and DATA portions on error */
 	if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) {
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 0a2f535..e6a296a 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -301,10 +301,12 @@
 		return 0;
 	}
 
-	if (blkcnt > 1)
-		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
-	else
+	if (blkcnt == 0)
+		return 0;
+	else if (blkcnt == 1)
 		cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
+	else
+		cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
 
 	if (mmc->high_capacity)
 		cmd.cmdarg = start;
@@ -700,16 +702,49 @@
 	return 0;
 }
 
+static int mmc_set_capacity(struct mmc *mmc, int part_num)
+{
+	switch (part_num) {
+	case 0:
+		mmc->capacity = mmc->capacity_user;
+		break;
+	case 1:
+	case 2:
+		mmc->capacity = mmc->capacity_boot;
+		break;
+	case 3:
+		mmc->capacity = mmc->capacity_rpmb;
+		break;
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+		mmc->capacity = mmc->capacity_gp[part_num - 4];
+		break;
+	default:
+		return -1;
+	}
+
+	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+
+	return 0;
+}
+
 int mmc_switch_part(int dev_num, unsigned int part_num)
 {
 	struct mmc *mmc = find_mmc_device(dev_num);
+	int ret;
 
 	if (!mmc)
 		return -1;
 
-	return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
-			  (mmc->part_config & ~PART_ACCESS_MASK)
-			  | (part_num & PART_ACCESS_MASK));
+	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
+			 (mmc->part_config & ~PART_ACCESS_MASK)
+			 | (part_num & PART_ACCESS_MASK));
+	if (ret)
+		return ret;
+
+	return mmc_set_capacity(mmc, part_num);
 }
 
 int mmc_getcd(struct mmc *mmc)
@@ -917,7 +952,7 @@
 
 static int mmc_startup(struct mmc *mmc)
 {
-	int err;
+	int err, i;
 	uint mult, freq;
 	u64 cmult, csize, capacity;
 	struct mmc_cmd cmd;
@@ -1035,8 +1070,12 @@
 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
 	}
 
-	mmc->capacity = (csize + 1) << (cmult + 2);
-	mmc->capacity *= mmc->read_bl_len;
+	mmc->capacity_user = (csize + 1) << (cmult + 2);
+	mmc->capacity_user *= mmc->read_bl_len;
+	mmc->capacity_boot = 0;
+	mmc->capacity_rpmb = 0;
+	for (i = 0; i < 4; i++)
+		mmc->capacity_gp[i] = 0;
 
 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
@@ -1075,7 +1114,7 @@
 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
 			capacity *= MMC_MAX_BLOCK_LEN;
 			if ((capacity >> 20) > 2 * 1024)
-				mmc->capacity = capacity;
+				mmc->capacity_user = capacity;
 		}
 
 		switch (ext_csd[EXT_CSD_REV]) {
@@ -1117,8 +1156,25 @@
 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
 		    ext_csd[EXT_CSD_BOOT_MULT])
 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+
+		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
+
+		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
+
+		for (i = 0; i < 4; i++) {
+			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
+			mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) +
+				(ext_csd[idx + 1] << 8) + ext_csd[idx];
+			mmc->capacity_gp[i] *=
+				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+		}
 	}
 
+	err = mmc_set_capacity(mmc, mmc->part_num);
+	if (err)
+		return err;
+
 	if (IS_SD(mmc))
 		err = sd_change_freq(mmc);
 	else
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 1eaea04..c5631bf 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -486,8 +486,10 @@
 		mmc->voltages |= host->voltages;
 
 	mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
-	if (caps & SDHCI_CAN_DO_8BIT)
-		mmc->host_caps |= MMC_MODE_8BIT;
+	if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) {
+		if (caps & SDHCI_CAN_DO_8BIT)
+			mmc->host_caps |= MMC_MODE_8BIT;
+	}
 	if (host->host_caps)
 		mmc->host_caps |= host->host_caps;
 
diff --git a/include/configs/beaver.h b/include/configs/beaver.h
index 058da4f..d51f5f8 100644
--- a/include/configs/beaver.h
+++ b/include/configs/beaver.h
@@ -56,7 +56,7 @@
 
 /* Environment in eMMC, at the end of 2nd "boot sector" */
 #define CONFIG_ENV_IS_IN_MMC
-#define CONFIG_ENV_OFFSET		((1024 * 1024) - CONFIG_ENV_SIZE)
+#define CONFIG_ENV_OFFSET		(-CONFIG_ENV_SIZE)
 #define CONFIG_SYS_MMC_ENV_DEV		0
 #define CONFIG_SYS_MMC_ENV_PART		2
 
diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h
index 6a99175..f3916de 100644
--- a/include/configs/cardhu.h
+++ b/include/configs/cardhu.h
@@ -55,7 +55,7 @@
 
 /* Environment in eMMC, at the end of 2nd "boot sector" */
 #define CONFIG_ENV_IS_IN_MMC
-#define CONFIG_ENV_OFFSET		((512 * 1024) - CONFIG_ENV_SIZE)
+#define CONFIG_ENV_OFFSET		(-CONFIG_ENV_SIZE)
 #define CONFIG_SYS_MMC_ENV_DEV		0
 #define CONFIG_SYS_MMC_ENV_PART		2
 
diff --git a/include/configs/dalmore.h b/include/configs/dalmore.h
index 7b68f7c..6d7a187 100644
--- a/include/configs/dalmore.h
+++ b/include/configs/dalmore.h
@@ -60,7 +60,7 @@
 #define CONFIG_ENV_IS_IN_MMC
 #define CONFIG_SYS_MMC_ENV_DEV		0
 #define CONFIG_SYS_MMC_ENV_PART		2
-#define CONFIG_ENV_OFFSET		((4096 * 1024) - CONFIG_ENV_SIZE)
+#define CONFIG_ENV_OFFSET		(-CONFIG_ENV_SIZE)
 
 #define MACH_TYPE_DALMORE	4304	/* not yet in mach-types.h */
 
diff --git a/include/configs/paz00.h b/include/configs/paz00.h
index eac1ef9..9e2686a 100644
--- a/include/configs/paz00.h
+++ b/include/configs/paz00.h
@@ -46,7 +46,7 @@
 
 /* Environment in eMMC, at the end of 2nd "boot sector" */
 #define CONFIG_ENV_IS_IN_MMC
-#define CONFIG_ENV_OFFSET ((1024 * 1024) - CONFIG_ENV_SIZE)
+#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE)
 #define CONFIG_SYS_MMC_ENV_DEV 0
 #define CONFIG_SYS_MMC_ENV_PART 2
 
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
index f66173e..f0da1fc 100644
--- a/include/configs/seaboard.h
+++ b/include/configs/seaboard.h
@@ -72,7 +72,7 @@
 
 /* Environment in eMMC, at the end of 2nd "boot sector" */
 #define CONFIG_ENV_IS_IN_MMC
-#define CONFIG_ENV_OFFSET ((512 * 1024) - CONFIG_ENV_SIZE)
+#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE)
 #define CONFIG_SYS_MMC_ENV_DEV 0
 #define CONFIG_SYS_MMC_ENV_PART 2
 
diff --git a/include/configs/ventana.h b/include/configs/ventana.h
index 5755f11..41a7176 100644
--- a/include/configs/ventana.h
+++ b/include/configs/ventana.h
@@ -52,7 +52,7 @@
 
 /* Environment in eMMC, at the end of 2nd "boot sector" */
 #define CONFIG_ENV_IS_IN_MMC
-#define CONFIG_ENV_OFFSET ((1024 * 1024) - CONFIG_ENV_SIZE)
+#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE)
 #define CONFIG_SYS_MMC_ENV_DEV 0
 #define CONFIG_SYS_MMC_ENV_PART 2
 
diff --git a/include/configs/whistler.h b/include/configs/whistler.h
index 9542c7e..994edec 100644
--- a/include/configs/whistler.h
+++ b/include/configs/whistler.h
@@ -61,12 +61,12 @@
 
 /*
  * Environment in eMMC, at the end of 2nd "boot sector". Note: This assumes
- * the user plugged the standard 8MB MoviNAND card into J29/HSMMC/POP. If
+ * the user plugged the standard 8GB MoviNAND card into J29/HSMMC/POP. If
  * they didn't, the boot sector layout may be different. However, use of that
  * particular card is standard practice as far as I know.
  */
 #define CONFIG_ENV_IS_IN_MMC
-#define CONFIG_ENV_OFFSET ((512 * 1024) - CONFIG_ENV_SIZE)
+#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE)
 #define CONFIG_SYS_MMC_ENV_DEV 0
 #define CONFIG_SYS_MMC_ENV_PART 2
 
diff --git a/include/environment.h b/include/environment.h
index 4c6a37b..460ccb4 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -75,6 +75,12 @@
 # endif
 #endif	/* CONFIG_ENV_IS_IN_FLASH */
 
+#if defined(CONFIG_ENV_IS_IN_MMC)
+# ifdef CONFIG_ENV_OFFSET_REDUND
+#  define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+# endif
+#endif
+
 #if defined(CONFIG_ENV_IS_IN_NAND)
 # if defined(CONFIG_ENV_OFFSET_OOB)
 #  ifdef CONFIG_ENV_OFFSET_REDUND
diff --git a/include/mmc.h b/include/mmc.h
index 566db59..ea198d8 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -158,7 +158,9 @@
 /*
  * EXT_CSD fields
  */
+#define EXT_CSD_GP_SIZE_MULT		143	/* R/W */
 #define EXT_CSD_PARTITIONING_SUPPORT	160	/* RO */
+#define EXT_CSD_RPMB_MULT		168	/* RO */
 #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
 #define EXT_CSD_PART_CONF		179	/* R/W */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
@@ -166,6 +168,7 @@
 #define EXT_CSD_REV			192	/* RO */
 #define EXT_CSD_CARD_TYPE		196	/* RO */
 #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
+#define EXT_CSD_HC_WP_GRP_SIZE		221	/* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
 #define EXT_CSD_BOOT_MULT		226	/* RO */
 
@@ -263,6 +266,10 @@
 	uint write_bl_len;
 	uint erase_grp_size;
 	u64 capacity;
+	u64 capacity_user;
+	u64 capacity_boot;
+	u64 capacity_rpmb;
+	u64 capacity_gp[4];
 	block_dev_desc_t block_dev;
 	int (*send_cmd)(struct mmc *mmc,
 			struct mmc_cmd *cmd, struct mmc_data *data);