From: "Chai, Chong Yi" <chong.yi.c...@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.moha...@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.moha...@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.moha...@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.moha...@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.moha...@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.moha...@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.c...@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.c...@intel.com> +Signed-off-by: Chew, Chiau Ee <chiau.ee.c...@intel.com> +Signed-off-by: Maurice Petallo <mauricex.r.peta...@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.peta...@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.peta...@intel.com> +Acked-by: Adrian Hunter <adrian.hun...@intel.com> +Signed-off-by: Ulf Hansson <ulf.hans...@linaro.org> +(cherry picked from commit d61b59461b0cd0106f03e566d537b9072029e059) + +Signed-off-by: Maurice Petallo <mauricex.r.peta...@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.peta...@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.peta...@intel.com> +Acked-by: Adrian Hunter <adrian.hun...@intel.com> +Signed-off-by: Ulf Hansson <ulf.hans...@linaro.org> +(cherry picked from commit f25c33724d1512a72554c0ad4cb70b43ba15374e) + +Signed-off-by: Maurice Petallo <mauricex.r.peta...@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.moha...@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.moha...@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 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto