[linux-yocto] [PATCH 1/1] mmc: sdhci: Preset value not supported in Baytrail eMMC

chong.yi.chai at intel.com chong.yi.chai at intel.com
Wed Mar 30 20:15:49 PDT 2016


From: "Chai, Chong Yi" <chong.yi.chai at intel.com>

---
 features/soc/baytrail/baytrail.scc                 |   7 +
 .../mmc-block-Fix-checkpatch.pl-warning.patch      |  31 ++
 ...mc-block-implement-write-request-blocking.patch | 180 ++++++++++
 .../mmc-block-refactor-read-only-handling.patch    | 214 ++++++++++++
 ...orce-BYT-SDCARD-host-to-run-with-SDR25-mo.patch |  80 +++++
 ...reset-value-not-supported-in-Baytrail-eMM.patch |  47 +++
 ...dd-DDR50-1.8V-mode-support-for-BayTrail-e.patch |  50 +++
 ...-whole-device-temporary-write-protection-.patch | 367 +++++++++++++++++++++
 8 files changed, 976 insertions(+)
 create mode 100644 features/soc/baytrail/mmc-block-Fix-checkpatch.pl-warning.patch
 create mode 100644 features/soc/baytrail/mmc-block-implement-write-request-blocking.patch
 create mode 100644 features/soc/baytrail/mmc-block-refactor-read-only-handling.patch
 create mode 100644 features/soc/baytrail/mmc-sdhci-Force-BYT-SDCARD-host-to-run-with-SDR25-mo.patch
 create mode 100644 features/soc/baytrail/mmc-sdhci-Preset-value-not-supported-in-Baytrail-eMM.patch
 create mode 100644 features/soc/baytrail/mmc-sdhci-add-DDR50-1.8V-mode-support-for-BayTrail-e.patch
 create mode 100644 features/soc/baytrail/mmc-support-whole-device-temporary-write-protection-.patch

diff --git a/features/soc/baytrail/baytrail.scc b/features/soc/baytrail/baytrail.scc
index 8ac3cfc..bd2bb4b 100644
--- a/features/soc/baytrail/baytrail.scc
+++ b/features/soc/baytrail/baytrail.scc
@@ -37,3 +37,10 @@ patch spi-pxa2xx-auto-switch-between-PIO-and-DMA-with-conf.patch
 patch spi-modify-spidev_test-to-test-automatic-PIO-DMA-swi.patch
 patch spi-pxa2xx-Add-new-ioctl-for-configuring-FIFO-trigge.patch
 patch spi-modify-spidev_test-to-test-modifying-FIFO-trigge.patch
+patch mmc-sdhci-Preset-value-not-supported-in-Baytrail-eMM.patch
+patch mmc-sdhci-add-DDR50-1.8V-mode-support-for-BayTrail-e.patch
+patch mmc-sdhci-Force-BYT-SDCARD-host-to-run-with-SDR25-mo.patch
+patch mmc-block-refactor-read-only-handling.patch
+patch mmc-block-implement-write-request-blocking.patch
+patch mmc-support-whole-device-temporary-write-protection-.patch
+patch mmc-block-Fix-checkpatch.pl-warning.patch
diff --git a/features/soc/baytrail/mmc-block-Fix-checkpatch.pl-warning.patch b/features/soc/baytrail/mmc-block-Fix-checkpatch.pl-warning.patch
new file mode 100644
index 0000000..c30a27f
--- /dev/null
+++ b/features/soc/baytrail/mmc-block-Fix-checkpatch.pl-warning.patch
@@ -0,0 +1,31 @@
+From 91d5003e1687b17612e564fd41c3546444d69fa5 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Fri, 21 Aug 2015 12:34:31 +0800
+Subject: [PATCH 157/164] mmc: block: Fix checkpatch.pl warning
+
+This commit is to fix the result of running scripts/checkpatch.pl against
+0137-mmc-block-refactor-read-only-handling.patch
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/mmc/card/block.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 9233aa5..aab78e9 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -269,8 +269,8 @@ static ssize_t power_ro_lock_store(struct device *dev,
+ 	/* Hardware WP affects both boot partitions */
+ 	list_for_each_entry(part_md, &md->part, part) {
+ 		if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {
+-			pr_info("%s: Locking boot partition ro until "
+-				"next power on\n", part_md->disk->disk_name);
++			pr_info("%s: Locking boot partition ro until next power on\n",
++				part_md->disk->disk_name);
+ 			part_md->read_only |= MMC_RO_BOOT_WP;
+ 			update_disk_ro(part_md);
+ 		}
+-- 
+1.7.7.6
+
diff --git a/features/soc/baytrail/mmc-block-implement-write-request-blocking.patch b/features/soc/baytrail/mmc-block-implement-write-request-blocking.patch
new file mode 100644
index 0000000..cd50d1e
--- /dev/null
+++ b/features/soc/baytrail/mmc-block-implement-write-request-blocking.patch
@@ -0,0 +1,180 @@
+From 518fbeaeffe4c47f3d5d49c338f4f723bcab197b Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Sun, 26 Jul 2015 13:09:23 +0800
+Subject: [PATCH 138/164] mmc: block: implement write request blocking
+
+This commit will enable write request blocking via
+/sys/block/mmcblkN/block_writes.
+When non-zero is written there, devices is synced, and then all write
+requests to device are errored out.
+
+This is unsafe. Use at own risk.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/mmc/card/Kconfig |   13 +++++++
+ drivers/mmc/card/block.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 95 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
+index 5562308..85dcc33 100644
+--- a/drivers/mmc/card/Kconfig
++++ b/drivers/mmc/card/Kconfig
+@@ -50,6 +50,19 @@ config MMC_BLOCK_BOUNCE
+ 
+ 	  If unsure, say Y here.
+ 
++config MMC_BLOCK_WRB
++	bool "Support write request blocking on SD/MMC devices"
++	depends on MMC_BLOCK
++	default n
++	help
++	  Enabling this adds 'block_writes' sysfs attribute to SD/MMC
++	  block device. If 1 is written to that attribute, device is
++	  immediately sync'ed, and all further write requests will be
++	  errored out.
++
++	  This is unsafe, and should not be used unless you know exactly
++	  what you are doing.
++
+ config SDIO_UART
+ 	tristate "SDIO UART/GPS class support"
+ 	depends on TTY
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 3e07095..3715530 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -105,6 +105,7 @@ struct mmc_blk_data {
+ #define MMC_RO_DEVICE		BIT(0)	/* underlying device is read only */
+ #define MMC_RO_FORCED		BIT(1)	/* read only forced */
+ #define MMC_RO_BOOT_WP		BIT(2)	/* boot partitions write protected */
++#define MMC_RO_WRB		BIT(3)	/* write requests are blocked */
+ 
+ 	unsigned int	part_type;
+ 	unsigned int	name_idx;
+@@ -122,6 +123,9 @@ struct mmc_blk_data {
+ 	unsigned int	part_curr;
+ 	struct device_attribute force_ro;
+ 	struct device_attribute power_ro_lock;
++#ifdef CONFIG_MMC_BLOCK_WRB
++	struct device_attribute block_writes;
++#endif
+ 	int	area_type;
+ };
+ 
+@@ -311,6 +315,56 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+ 	return count;
+ }
+ 
++#ifdef CONFIG_MMC_BLOCK_WRB
++static ssize_t block_writes_show(struct device *dev,
++		struct device_attribute *attr, char *buf)
++{
++	int ret;
++	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
++
++	ret = sprintf(buf, "%d\n", !!(md->read_only & MMC_RO_WRB));
++	mmc_blk_put(md);
++	return ret;
++}
++
++static ssize_t block_writes_store(struct device *dev,
++		struct device_attribute *attr, const char *buf, size_t count)
++{
++	struct mmc_blk_data *md;
++	unsigned long set;
++
++	if (kstrtoul(buf, 0, &set))
++		return -EINVAL;
++
++	md = mmc_blk_get(dev_to_disk(dev));
++
++	if (!set)
++		md->read_only &= ~MMC_RO_WRB;
++	else {
++		struct disk_part_iter piter;
++		struct hd_struct *part;
++		struct block_device *bdev;
++
++		disk_part_iter_init(&piter, md->disk, DISK_PITER_INCL_PART0);
++		while ((part = disk_part_iter_next(&piter))) {
++			bdev = bdget(part_devt(part));
++			if (bdev) {
++				fsync_bdev(bdev);
++				bdput(bdev);
++			}
++		}
++		disk_part_iter_exit(&piter);
++
++		md->read_only |= MMC_RO_WRB;
++	}
++
++	update_disk_ro(md);
++
++	mmc_blk_put(md);
++	return count;
++}
++#endif
++
+ static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
+ {
+ 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
+@@ -2002,6 +2056,16 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ 		/* claim host only for the first request */
+ 		mmc_get_card(card);
+ 
++#ifdef CONFIG_MMC_BLOCK_WRB
++	if (req && (md->read_only & MMC_RO_WRB) &&
++		((cmd_flags & REQ_DISCARD) || rq_data_dir(req) == WRITE)) {
++
++		blk_end_request_all(req, -EIO);
++		ret = 0;
++		goto out;
++	}
++#endif
++
+ 	ret = mmc_blk_part_switch(card, md);
+ 	if (ret) {
+ 		if (req) {
+@@ -2281,6 +2345,10 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
+ 			mmc_packed_clean(&md->queue);
+ 		if (md->disk->flags & GENHD_FL_UP) {
+ 			device_remove_file(disk_to_dev(md->disk), &md->force_ro);
++#ifdef CONFIG_MMC_BLOCK_WRB
++			device_remove_file(disk_to_dev(md->disk),
++						&md->block_writes);
++#endif
+ 			if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+ 					card->ext_csd.boot_ro_lockable)
+ 				device_remove_file(disk_to_dev(md->disk),
+@@ -2320,6 +2388,16 @@ static int mmc_add_disk(struct mmc_blk_data *md)
+ 	ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
+ 	if (ret)
+ 		goto force_ro_fail;
++#ifdef CONFIG_MMC_BLOCK_WRB
++	md->block_writes.show = block_writes_show;
++	md->block_writes.store = block_writes_store;
++	sysfs_attr_init(&md->block_writes.attr);
++	md->block_writes.attr.name = "block_writes";
++	md->block_writes.attr.mode = S_IRUGO | S_IWUSR;
++	ret = device_create_file(disk_to_dev(md->disk), &md->block_writes);
++	if (ret)
++		goto block_writes_fail;
++#endif
+ 
+ 	if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+ 	     card->ext_csd.boot_ro_lockable) {
+@@ -2344,6 +2422,10 @@ static int mmc_add_disk(struct mmc_blk_data *md)
+ 	return ret;
+ 
+ power_ro_lock_fail:
++#ifdef CONFIG_MMC_BLOCK_WRB
++	device_remove_file(disk_to_dev(md->disk), &md->block_writes);
++block_writes_fail:
++#endif
+ 	device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+ force_ro_fail:
+ 	del_gendisk(md->disk);
+-- 
+1.7.7.6
+
diff --git a/features/soc/baytrail/mmc-block-refactor-read-only-handling.patch b/features/soc/baytrail/mmc-block-refactor-read-only-handling.patch
new file mode 100644
index 0000000..4a663ce
--- /dev/null
+++ b/features/soc/baytrail/mmc-block-refactor-read-only-handling.patch
@@ -0,0 +1,214 @@
+From b0c00075c2fe613b91f500a0318a46e7c7e56b68 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Sun, 26 Jul 2015 12:35:21 +0800
+Subject: [PATCH 137/164] mmc: block: refactor read-only handling
+
+There are several reasons why gendisk corresponding to SD/eMMC card or
+hardware partition is read-only for the system:
+- underlying device is readonly (due to write protect GPIO, or due to
+  card lacks support for write commands),
+- due to card-level write protection (currently supported only for eMMC
+  boot partitions),
+- due to software 'force_ro' attribute (currently enabled by default for
+  eMMC boot partitions).
+
+This is managed indirectly, via gendisk's read-only flag.
+
+Since more possible read-only reasons are about to be added, need to
+replace that with explicit handling.
+
+This patch turns 'read_only' field of struct mmc_blk_data into a bitmask,
+with individual bits representing possible read-only reasons. Gendisk
+is marked read-only when at least one bit is set in the mask, and
+is marked read-write when last bit is cleared.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/mmc/card/block.c |   96 ++++++++++++++++++++++++++++++---------------
+ 1 files changed, 64 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index b1e21fc..3e07095 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -102,6 +102,10 @@ struct mmc_blk_data {
+ 
+ 	unsigned int	usage;
+ 	unsigned int	read_only;
++#define MMC_RO_DEVICE		BIT(0)	/* underlying device is read only */
++#define MMC_RO_FORCED		BIT(1)	/* read only forced */
++#define MMC_RO_BOOT_WP		BIT(2)	/* boot partitions write protected */
++
+ 	unsigned int	part_type;
+ 	unsigned int	name_idx;
+ 	unsigned int	reset_done;
+@@ -190,6 +194,11 @@ static void mmc_blk_put(struct mmc_blk_data *md)
+ 	mutex_unlock(&open_lock);
+ }
+ 
++static inline void update_disk_ro(struct mmc_blk_data *md)
++{
++	set_disk_ro(md->disk, !!md->read_only);
++}
++
+ static ssize_t power_ro_lock_show(struct device *dev,
+ 		struct device_attribute *attr, char *buf)
+ {
+@@ -227,29 +236,41 @@ static ssize_t power_ro_lock_store(struct device *dev,
+ 
+ 	mmc_get_card(card);
+ 
++	if (card->ext_csd.boot_ro_lock & (EXT_CSD_BOOT_WP_B_PERM_WP_EN |
++					  EXT_CSD_BOOT_WP_B_PWR_WP_EN)) {
++		mmc_put_card(card);
++		goto out;
++	}
++
+ 	ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
+ 				card->ext_csd.boot_ro_lock |
+ 				EXT_CSD_BOOT_WP_B_PWR_WP_EN,
+ 				card->ext_csd.part_time);
+-	if (ret)
++	if (ret) {
++		mmc_put_card(card);
+ 		pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret);
+-	else
+-		card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
++		goto out;
++	}
+ 
++	card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
+ 	mmc_put_card(card);
+ 
+-	if (!ret) {
+-		pr_info("%s: Locking boot partition ro until next power on\n",
+-			md->disk->disk_name);
+-		set_disk_ro(md->disk, 1);
++	pr_info("%s: Locking boot partition ro until next power on\n",
++		md->disk->disk_name);
++	md->read_only |= MMC_RO_BOOT_WP;
++	update_disk_ro(md);
+ 
+-		list_for_each_entry(part_md, &md->part, part)
+-			if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {
+-				pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name);
+-				set_disk_ro(part_md->disk, 1);
+-			}
++	/* Hardware WP affects both boot partitions */
++	list_for_each_entry(part_md, &md->part, part) {
++		if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {
++			pr_info("%s: Locking boot partition ro until "
++				"next power on\n", part_md->disk->disk_name);
++			part_md->read_only |= MMC_RO_BOOT_WP;
++			update_disk_ro(part_md);
++		}
+ 	}
+ 
++out:
+ 	mmc_blk_put(md);
+ 	return count;
+ }
+@@ -260,9 +281,10 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+ 	int ret;
+ 	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ 
+-	ret = snprintf(buf, PAGE_SIZE, "%d\n",
+-		       get_disk_ro(dev_to_disk(dev)) ^
+-		       md->read_only);
++	/* Show 1 only if 'force_ro' is the only reason of device
++	 * being read only.
++	 */
++	ret = sprintf(buf, "%d\n", md->read_only == MMC_RO_FORCED);
+ 	mmc_blk_put(md);
+ 	return ret;
+ }
+@@ -270,20 +292,23 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+ 			      const char *buf, size_t count)
+ {
+-	int ret;
+-	char *end;
+-	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+-	unsigned long set = simple_strtoul(buf, &end, 0);
+-	if (end == buf) {
+-		ret = -EINVAL;
+-		goto out;
+-	}
++	struct mmc_blk_data *md;
++	unsigned long set;
++
++	if (kstrtoul(buf, 0, &set))
++		return -EINVAL;
++
++	md = mmc_blk_get(dev_to_disk(dev));
++
++	if (set)
++		md->read_only |= MMC_RO_FORCED;
++	else
++		md->read_only &= ~MMC_RO_FORCED;
++
++	update_disk_ro(md);
+ 
+-	set_disk_ro(dev_to_disk(dev), set || md->read_only);
+-	ret = count;
+-out:
+ 	mmc_blk_put(md);
+-	return ret;
++	return count;
+ }
+ 
+ static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
+@@ -2032,7 +2057,7 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
+ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ 					      struct device *parent,
+ 					      sector_t size,
+-					      bool default_ro,
++					      bool force_ro,
+ 					      const char *subname,
+ 					      int area_type)
+ {
+@@ -2069,7 +2094,14 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ 	 * Set the read-only status based on the supported commands
+ 	 * and the write protect switch.
+ 	 */
+-	md->read_only = mmc_blk_readonly(card);
++	if (mmc_blk_readonly(card))
++		md->read_only |= MMC_RO_DEVICE;
++	if (force_ro)
++		md->read_only |= MMC_RO_FORCED;
++	if (area_type == MMC_BLK_DATA_AREA_BOOT &&
++	    (card->ext_csd.boot_ro_lock & (EXT_CSD_BOOT_WP_B_PERM_WP_EN |
++					   EXT_CSD_BOOT_WP_B_PWR_WP_EN)))
++		md->read_only |= MMC_RO_BOOT_WP;
+ 
+ 	md->disk = alloc_disk(perdev_minors);
+ 	if (md->disk == NULL) {
+@@ -2094,7 +2126,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ 	md->disk->private_data = md;
+ 	md->disk->queue = md->queue.queue;
+ 	md->disk->driverfs_dev = parent;
+-	set_disk_ro(md->disk, md->read_only || default_ro);
++	update_disk_ro(md);
+ 	if (area_type & MMC_BLK_DATA_AREA_RPMB)
+ 		md->disk->flags |= GENHD_FL_NO_PART_SCAN;
+ 
+@@ -2182,14 +2214,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
+ 			      struct mmc_blk_data *md,
+ 			      unsigned int part_type,
+ 			      sector_t size,
+-			      bool default_ro,
++			      bool force_ro,
+ 			      const char *subname,
+ 			      int area_type)
+ {
+ 	char cap_str[10];
+ 	struct mmc_blk_data *part_md;
+ 
+-	part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
++	part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, force_ro,
+ 				    subname, area_type);
+ 	if (IS_ERR(part_md))
+ 		return PTR_ERR(part_md);
+-- 
+1.7.7.6
+
diff --git a/features/soc/baytrail/mmc-sdhci-Force-BYT-SDCARD-host-to-run-with-SDR25-mo.patch b/features/soc/baytrail/mmc-sdhci-Force-BYT-SDCARD-host-to-run-with-SDR25-mo.patch
new file mode 100644
index 0000000..ea6a08f
--- /dev/null
+++ b/features/soc/baytrail/mmc-sdhci-Force-BYT-SDCARD-host-to-run-with-SDR25-mo.patch
@@ -0,0 +1,80 @@
+From 7650d0fbd3ceaae2aff81ee50ea8cb0f0b8eefbe Mon Sep 17 00:00:00 2001
+From: "Chew, Kean Ho" <kean.ho.chew at intel.com>
+Date: Mon, 23 Dec 2013 16:14:27 +0800
+Subject: [PATCH 031/164] mmc: sdhci: Force BYT SDCARD host to run with SDR25
+ mode
+
+The clock appears to be unstable when SDCARD host running with
+DDR50 mode, thus causing CRC issue. This is to introduce a new
+quirk to force host with broken DDR50 mode to run with SDR25
+mode.
+
+Signed-off-by: Chew, Kean Ho <kean.ho.chew at intel.com>
+Signed-off-by: Chew, Chiau Ee <chiau.ee.chew at intel.com>
+Signed-off-by: Maurice Petallo <mauricex.r.petallo at intel.com>
+---
+ drivers/mmc/host/sdhci-acpi.c |    3 ++-
+ drivers/mmc/host/sdhci-pci.c  |    3 ++-
+ drivers/mmc/host/sdhci.c      |    3 ++-
+ include/linux/mmc/sdhci.h     |    2 ++
+ 4 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
+index 88863bf..90b1f68 100644
+--- a/drivers/mmc/host/sdhci-acpi.c
++++ b/drivers/mmc/host/sdhci-acpi.c
+@@ -133,7 +133,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
+ 
+ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
+ 	.flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
+ 		   SDHCI_ACPI_RUNTIME_PM,
+-	.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
++	.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
++		   SDHCI_QUIRK2_BROKEN_DDR50,
+ };
+ 
+ struct sdhci_acpi_uid_slot {
+diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
+index dda7dd0..82a4019 100644
+--- a/drivers/mmc/host/sdhci-pci.c
++++ b/drivers/mmc/host/sdhci-pci.c
+@@ -293,7 +293,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
+ };
+ 
+ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
+-	.quirks2	= SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
++	.quirks2	= SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
++			  SDHCI_QUIRK2_BROKEN_DDR50,
+ 	.allow_runtime_pm = true,
+ 	.own_cd_for_runtime_pm = true,
+ };
+diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
+index 22eccbf..b505882 100644
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -3022,7 +3022,8 @@ int sdhci_add_host(struct sdhci_host *host)
+ 	} else if (caps[1] & SDHCI_SUPPORT_SDR50)
+ 		mmc->caps |= MMC_CAP_UHS_SDR50;
+ 
+-	if (caps[1] & SDHCI_SUPPORT_DDR50)
++	if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
++	    !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
+ 		mmc->caps |= MMC_CAP_UHS_DDR50;
+ 
+ 	/* Does the host need tuning for SDR50? */
+diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
+index 362927c4..19353dd 100644
+--- a/include/linux/mmc/sdhci.h
++++ b/include/linux/mmc/sdhci.h
+@@ -100,6 +100,8 @@ struct sdhci_host {
+ #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL		(1<<5)
+ /* Controller does not support HS200 */
+ #define SDHCI_QUIRK2_BROKEN_HS200			(1<<6)
++/* Controller has a broken DDR50 Time Spec */
++#define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
+ 
+ 	int irq;		/* Device IRQ */
+ 	void __iomem *ioaddr;	/* Mapped address */
+-- 
+1.7.7.6
+
diff --git a/features/soc/baytrail/mmc-sdhci-Preset-value-not-supported-in-Baytrail-eMM.patch b/features/soc/baytrail/mmc-sdhci-Preset-value-not-supported-in-Baytrail-eMM.patch
new file mode 100644
index 0000000..64d35cd
--- /dev/null
+++ b/features/soc/baytrail/mmc-sdhci-Preset-value-not-supported-in-Baytrail-eMM.patch
@@ -0,0 +1,47 @@
+From d6e4257c98dc4633fd707e80d696430f2acd8053 Mon Sep 17 00:00:00 2001
+From: Maurice Petallo <mauricex.r.petallo at intel.com>
+Date: Tue, 8 Jul 2014 19:11:00 +0800
+Subject: [PATCH 025/164] mmc: sdhci: Preset value not supported in Baytrail
+ eMMC
+
+"SDHCI_QUIRK2_PRESET_VALUE_BROKEN" quirk is added to prohibit
+preset value enabling for Baytrail eMMC controller.
+
+Signed-off-by: Maurice Petallo <mauricex.r.petallo at intel.com>
+Acked-by: Adrian Hunter <adrian.hunter at intel.com>
+Signed-off-by: Ulf Hansson <ulf.hansson at linaro.org>
+(cherry picked from commit d61b59461b0cd0106f03e566d537b9072029e059)
+
+Signed-off-by: Maurice Petallo <mauricex.r.petallo at intel.com>
+---
+ drivers/mmc/host/sdhci-acpi.c |    1 +
+ drivers/mmc/host/sdhci-pci.c  |    1 +
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
+index 9ce17f6..2a35338 100644
+--- a/drivers/mmc/host/sdhci-acpi.c
++++ b/drivers/mmc/host/sdhci-acpi.c
+@@ -118,6 +118,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
+ 	.caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | MMC_CAP_HW_RESET,
+ 	.caps2   = MMC_CAP2_HC_ERASE_SZ,
+ 	.flags   = SDHCI_ACPI_RUNTIME_PM,
++	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+ };
+ 
+ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
+diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
+index 19bfa0a..4424238 100644
+--- a/drivers/mmc/host/sdhci-pci.c
++++ b/drivers/mmc/host/sdhci-pci.c
+@@ -283,6 +283,7 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
+ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
+ 	.allow_runtime_pm = true,
+ 	.probe_slot	= byt_emmc_probe_slot,
++	.quirks2	= SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+ };
+ 
+ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
+-- 
+1.7.7.6
+
diff --git a/features/soc/baytrail/mmc-sdhci-add-DDR50-1.8V-mode-support-for-BayTrail-e.patch b/features/soc/baytrail/mmc-sdhci-add-DDR50-1.8V-mode-support-for-BayTrail-e.patch
new file mode 100644
index 0000000..8ee105f
--- /dev/null
+++ b/features/soc/baytrail/mmc-sdhci-add-DDR50-1.8V-mode-support-for-BayTrail-e.patch
@@ -0,0 +1,50 @@
+From 9d4bcd4f06fe345ba6ee5b0ed82fda836ecf090c Mon Sep 17 00:00:00 2001
+From: Maurice Petallo <mauricex.r.petallo at intel.com>
+Date: Tue, 8 Jul 2014 19:11:01 +0800
+Subject: [PATCH 026/164] mmc: sdhci: add DDR50 1.8V mode support for BayTrail
+ eMMC Controller
+
+This is to enable DDR50 bus speed mode with 1.8V signaling capability
+for BayTrail ACPI and PCI mode eMMC Controller.
+
+Signed-off-by: Maurice Petallo <mauricex.r.petallo at intel.com>
+Acked-by: Adrian Hunter <adrian.hunter at intel.com>
+Signed-off-by: Ulf Hansson <ulf.hansson at linaro.org>
+(cherry picked from commit f25c33724d1512a72554c0ad4cb70b43ba15374e)
+
+Signed-off-by: Maurice Petallo <mauricex.r.petallo at intel.com>
+---
+ drivers/mmc/host/sdhci-acpi.c |    3 ++-
+ drivers/mmc/host/sdhci-pci.c  |    2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
+index 2a35338..88863bf 100644
+--- a/drivers/mmc/host/sdhci-acpi.c
++++ b/drivers/mmc/host/sdhci-acpi.c
+@@ -115,7 +115,8 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
+ 
+ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
+ 	.chip    = &sdhci_acpi_chip_int,
+-	.caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | MMC_CAP_HW_RESET,
++	.caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
++		   MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR,
+ 	.caps2   = MMC_CAP2_HC_ERASE_SZ,
+ 	.flags   = SDHCI_ACPI_RUNTIME_PM,
+ 	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
+index 4424238..dda7dd0 100644
+--- a/drivers/mmc/host/sdhci-pci.c
++++ b/drivers/mmc/host/sdhci-pci.c
+@@ -268,7 +268,7 @@ static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
+ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
+ {
+ 	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
+-				 MMC_CAP_HW_RESET;
++				 MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR;
+ 	slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
+ 	slot->hw_reset = sdhci_pci_int_hw_reset;
+ 	return 0;
+-- 
+1.7.7.6
+
diff --git a/features/soc/baytrail/mmc-support-whole-device-temporary-write-protection-.patch b/features/soc/baytrail/mmc-support-whole-device-temporary-write-protection-.patch
new file mode 100644
index 0000000..d5f4ece
--- /dev/null
+++ b/features/soc/baytrail/mmc-support-whole-device-temporary-write-protection-.patch
@@ -0,0 +1,367 @@
+From 639b25dce5cf6534503dfdf7cf1015c478a17664 Mon Sep 17 00:00:00 2001
+From: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+Date: Sun, 26 Jul 2015 14:40:37 +0800
+Subject: [PATCH 140/164] mmc: support whole-device temporary write protection
+ over CSD bits 13:12
+
+This commit add support for eMMC whole-device temporary write protection
+feature. mmcblk device get new "card_wp" attribute, that can be used to read
+and change device-side write protection.
+
+For safety reasons, setting permanent write protection is not supported.
+
+Signed-off-by: Wan Ahmad Zainie <wan.ahmad.zainie.wan.mohamad at intel.com>
+---
+ drivers/mmc/Kconfig        |    1 +
+ drivers/mmc/card/block.c   |   81 +++++++++++++++++++++++++++++++++++++++
+ drivers/mmc/core/mmc.c     |    2 +
+ drivers/mmc/core/mmc_ops.c |   91 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/mmc/core/mmc_ops.h |    1 +
+ drivers/mmc/core/sd.c      |    4 ++
+ include/linux/mmc/card.h   |    4 +-
+ include/linux/mmc/core.h   |    1 +
+ 8 files changed, 184 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
+index f2eeb38..74076bc 100644
+--- a/drivers/mmc/Kconfig
++++ b/drivers/mmc/Kconfig
+@@ -5,6 +5,7 @@
+ menuconfig MMC
+ 	tristate "MMC/SD/SDIO card support"
+ 	depends on HAS_IOMEM
++	select CRC7
+ 	help
+ 	  This selects MultiMediaCard, Secure Digital and Secure
+ 	  Digital I/O support.
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 3715530..9233aa5 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -106,6 +106,7 @@ struct mmc_blk_data {
+ #define MMC_RO_FORCED		BIT(1)	/* read only forced */
+ #define MMC_RO_BOOT_WP		BIT(2)	/* boot partitions write protected */
+ #define MMC_RO_WRB		BIT(3)	/* write requests are blocked */
++#define MMC_RO_CARD_WP		BIT(4)	/* card is write protected via CSD */
+ 
+ 	unsigned int	part_type;
+ 	unsigned int	name_idx;
+@@ -126,6 +127,7 @@ struct mmc_blk_data {
+ #ifdef CONFIG_MMC_BLOCK_WRB
+ 	struct device_attribute block_writes;
+ #endif
++	struct device_attribute card_wp;
+ 	int	area_type;
+ };
+ 
+@@ -365,6 +367,69 @@ static ssize_t block_writes_store(struct device *dev,
+ }
+ #endif
+ 
++static ssize_t card_wp_show(struct device *dev, struct device_attribute *attr,
++			     char *buf)
++{
++	int val, ret;
++	struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
++	struct mmc_card *card = md->queue.card;
++
++	if (card->csd.perm_wp)
++		val = 2;
++	else if (card->csd.temp_wp)
++		val = 1;
++	else
++		val = 0;
++
++	ret = sprintf(buf, "%d\n", val);
++	mmc_blk_put(md);
++	return ret;
++}
++
++static ssize_t card_wp_store(struct device *dev, struct device_attribute *attr,
++			      const char *buf, size_t count)
++{
++	struct mmc_blk_data *md, *part_md;
++	struct mmc_card *card;
++	unsigned long set;
++	ssize_t ret;
++
++	if (kstrtoul(buf, 0, &set) || (set != 0 && set != 1))
++		return -EINVAL;
++
++	md = mmc_blk_get(dev_to_disk(dev));
++	card = md->queue.card;
++	mmc_get_card(card);
++
++	if (card->csd.temp_wp == set)
++		goto out_ok;
++
++	ret = mmc_set_card_wp(card, set);
++	if (ret)
++		goto out;
++
++	if (card->csd.perm_wp || card->csd.temp_wp)
++		md->read_only |= MMC_RO_CARD_WP;
++	else
++		md->read_only &= ~MMC_RO_CARD_WP;
++	update_disk_ro(md);
++
++	/* propagate to all hw partitions over the same device */
++	list_for_each_entry(part_md, &md->part, part) {
++		if (card->csd.perm_wp || card->csd.temp_wp)
++			part_md->read_only |= MMC_RO_CARD_WP;
++		else
++			part_md->read_only &= ~MMC_RO_CARD_WP;
++		update_disk_ro(part_md);
++	}
++out_ok:
++	ret = count;
++out:
++	mmc_put_card(card);
++	mmc_blk_put(md);
++	return ret;
++}
++
+ static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
+ {
+ 	struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
+@@ -2166,6 +2231,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ 	    (card->ext_csd.boot_ro_lock & (EXT_CSD_BOOT_WP_B_PERM_WP_EN |
+ 					   EXT_CSD_BOOT_WP_B_PWR_WP_EN)))
+ 		md->read_only |= MMC_RO_BOOT_WP;
++	if (card->csd.perm_wp || card->csd.temp_wp)
++		md->read_only |= MMC_RO_CARD_WP;
+ 
+ 	md->disk = alloc_disk(perdev_minors);
+ 	if (md->disk == NULL) {
+@@ -2349,6 +2416,7 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
+ 			device_remove_file(disk_to_dev(md->disk),
+ 						&md->block_writes);
+ #endif
++			device_remove_file(disk_to_dev(md->disk), &md->card_wp);
+ 			if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+ 					card->ext_csd.boot_ro_lockable)
+ 				device_remove_file(disk_to_dev(md->disk),
+@@ -2380,6 +2448,7 @@ static int mmc_add_disk(struct mmc_blk_data *md)
+ 	struct mmc_card *card = md->queue.card;
+ 
+ 	add_disk(md->disk);
++
+ 	md->force_ro.show = force_ro_show;
+ 	md->force_ro.store = force_ro_store;
+ 	sysfs_attr_init(&md->force_ro.attr);
+@@ -2388,6 +2457,7 @@ static int mmc_add_disk(struct mmc_blk_data *md)
+ 	ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
+ 	if (ret)
+ 		goto force_ro_fail;
++
+ #ifdef CONFIG_MMC_BLOCK_WRB
+ 	md->block_writes.show = block_writes_show;
+ 	md->block_writes.store = block_writes_store;
+@@ -2399,6 +2469,15 @@ static int mmc_add_disk(struct mmc_blk_data *md)
+ 		goto block_writes_fail;
+ #endif
+ 
++	md->card_wp.show = card_wp_show;
++	md->card_wp.store = card_wp_store;
++	sysfs_attr_init(&md->card_wp.attr);
++	md->card_wp.attr.name = "card_wp";
++	md->card_wp.attr.mode = S_IRUGO | S_IWUSR;
++	ret = device_create_file(disk_to_dev(md->disk), &md->card_wp);
++	if (ret)
++		goto card_wp_fail;
++
+ 	if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
+ 	     card->ext_csd.boot_ro_lockable) {
+ 		umode_t mode;
+@@ -2422,6 +2501,8 @@ static int mmc_add_disk(struct mmc_blk_data *md)
+ 	return ret;
+ 
+ power_ro_lock_fail:
++	device_remove_file(disk_to_dev(md->disk), &md->card_wp);
++card_wp_fail:
+ #ifdef CONFIG_MMC_BLOCK_WRB
+ 	device_remove_file(disk_to_dev(md->disk), &md->block_writes);
+ block_writes_fail:
+diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
+index 98e9eb0..eff1b04 100644
+--- a/drivers/mmc/core/mmc.c
++++ b/drivers/mmc/core/mmc.c
+@@ -165,6 +165,8 @@ static int mmc_decode_csd(struct mmc_card *card)
+ 	csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ 	csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ 	csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
++	csd->perm_wp = UNSTUFF_BITS(resp, 13, 1);
++	csd->temp_wp = UNSTUFF_BITS(resp, 12, 1);
+ 
+ 	if (csd->write_blkbits >= 9) {
+ 		a = UNSTUFF_BITS(resp, 42, 5);
+diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
+index e5b5eeb..2f2b29b 100644
+--- a/drivers/mmc/core/mmc_ops.c
++++ b/drivers/mmc/core/mmc_ops.c
+@@ -13,6 +13,7 @@
+ #include <linux/export.h>
+ #include <linux/types.h>
+ #include <linux/scatterlist.h>
++#include <linux/crc7.h>
+ 
+ #include <linux/mmc/host.h>
+ #include <linux/mmc/card.h>
+@@ -637,3 +638,93 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
+ 
+ 	return 0;
+ }
++
++int mmc_program_csd(struct mmc_card *card, u8 *csd_128be)
++{
++	struct mmc_request mrq = {NULL};
++	struct mmc_command cmd = {0};
++	struct mmc_data data = {0};
++	struct scatterlist sg;
++	void *data_buf;
++	int is_on_stack;
++	int len = 16;
++
++	is_on_stack = object_is_on_stack(csd_128be);
++	if (is_on_stack) {
++		/*
++		 * dma onto stack is unsafe/nonportable, but callers to this
++		 * routine normally provide temporary on-stack buffers ...
++		 */
++		data_buf = kmalloc(len, GFP_KERNEL);
++		if (!data_buf)
++			return -ENOMEM;
++		memcpy(data_buf, csd_128be, len);
++	} else
++		data_buf = csd_128be;
++
++	mrq.cmd = &cmd;
++	mrq.data = &data;
++
++	cmd.opcode = MMC_PROGRAM_CSD;
++	cmd.arg = 0;
++	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
++
++	data.blksz = len;
++	data.blocks = 1;
++	data.flags = MMC_DATA_WRITE;
++	data.sg = &sg;
++	data.sg_len = 1;
++
++	sg_init_one(&sg, data_buf, len);
++
++	mmc_set_data_timeout(&data, card);
++
++	mmc_wait_for_req(card->host, &mrq);
++
++	if (is_on_stack)
++		kfree(data_buf);
++
++	if (cmd.error)
++		return cmd.error;
++	if (data.error)
++		return data.error;
++
++	return 0;
++}
++
++int mmc_set_card_wp(struct mmc_card *card, int wp)
++{
++	u8 csd_be128[16];
++	int i, ret;
++
++	if (card->csd.temp_wp == !!wp)
++		return 0;
++
++	for (i = 0; i < 4; i++)
++		((u32 *)csd_be128)[i] = cpu_to_be32(card->raw_csd[i]);
++
++	/* update bit 12 with new temp_wp value */
++	if (wp)
++		csd_be128[14] |= 0x10;
++	else
++		csd_be128[14] &= ~0x10;
++
++	/* set CRC7 into bits 7:1, and 1 into bit 0 */
++	csd_be128[15] = (crc7(0, csd_be128, 15) << 1) | 0x1;
++
++	ret = mmc_program_csd(card, csd_be128);
++
++	if (!ret) {
++		/* update cached csd without re-reading */
++		if (wp) {
++			card->raw_csd[3] |= BIT(12);
++			card->csd.temp_wp = 1;
++		} else {
++			card->raw_csd[3] &= ~BIT(12);
++			card->csd.temp_wp = 0;
++		}
++	}
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(mmc_set_card_wp);
+diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
+index 80ae9f4..47884d5 100644
+--- a/drivers/mmc/core/mmc_ops.h
++++ b/drivers/mmc/core/mmc_ops.h
+@@ -26,6 +26,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
+ int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
+ int mmc_bus_test(struct mmc_card *card, u8 bus_width);
+ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
++int mmc_program_csd(struct mmc_card *card, u8 *csd_128be);
+ 
+ #endif
+ 
+diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
+index 692fdb1..3654766 100644
+--- a/drivers/mmc/core/sd.c
++++ b/drivers/mmc/core/sd.c
+@@ -130,6 +130,8 @@ static int mmc_decode_csd(struct mmc_card *card)
+ 		csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ 		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ 		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
++		csd->perm_wp = UNSTUFF_BITS(resp, 13, 1);
++		csd->temp_wp = UNSTUFF_BITS(resp, 12, 1);
+ 
+ 		if (UNSTUFF_BITS(resp, 46, 1)) {
+ 			csd->erase_size = 1;
+@@ -170,6 +172,8 @@ static int mmc_decode_csd(struct mmc_card *card)
+ 		csd->r2w_factor = 4; /* Unused */
+ 		csd->write_blkbits = 9;
+ 		csd->write_partial = 0;
++		csd->perm_wp = UNSTUFF_BITS(resp, 13, 1);
++		csd->temp_wp = UNSTUFF_BITS(resp, 12, 1);
+ 		csd->erase_size = 1;
+ 		break;
+ 	default:
+diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
+index b730272..ce301b8 100644
+--- a/include/linux/mmc/card.h
++++ b/include/linux/mmc/card.h
+@@ -42,7 +42,9 @@ struct mmc_csd {
+ 	unsigned int		read_partial:1,
+ 				read_misalign:1,
+ 				write_partial:1,
+-				write_misalign:1;
++				write_misalign:1,
++				perm_wp:1,
++				temp_wp:1;
+ };
+ 
+ struct mmc_ext_csd {
+diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
+index 87079fc..de843f8 100644
+--- a/include/linux/mmc/core.h
++++ b/include/linux/mmc/core.h
+@@ -155,6 +155,7 @@ extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
+ 			bool);
+ extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
+ extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
++extern int mmc_set_card_wp(struct mmc_card *card, int wp);
+ 
+ #define MMC_ERASE_ARG		0x00000000
+ #define MMC_SECURE_ERASE_ARG	0x80000000
+-- 
+1.7.7.6
+
-- 
1.9.1



More information about the linux-yocto mailing list