You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'mmc-v4.8' of git://git.linaro.org/people/ulf.hansson/mmc
Pull MMC updates from Ulf Hansson: "MMC core: - A couple of changes to improve the support for erase/discard/trim cmds - Add eMMC HS400 enhanced strobe support - Show OCR and DSR registers in SYSFS for MMC/SD cards - Correct and improve busy detection logic for MMC switch (CMD6) cmds - Disable HPI cmds for certain broken Hynix eMMC cards - Allow MMC hosts to specify non-support for SD and MMC cmds - Some minor additional fixes MMC host: - sdhci: Re-works, fixes and clean-ups - sdhci: Add HW auto re-tuning support - sdhci: Re-factor code to prepare for adding support for eMMC CMDQ - sdhci-esdhc-imx: Fixes and clean-ups - sdhci-esdhc-imx: Update system PM support - sdhci-esdhc-imx: Enable HW auto re-tuning - sdhci-bcm2835: Remove driver as sdhci-iproc is used instead - sdhci-brcmstb: Add new driver for Broadcom BRCMSTB SoCs - sdhci-msm: Add support for UHS cards - sdhci-tegra: Improve support for UHS cards - sdhci-of-arasan: Update phy support for Rockchip SoCs - sdhci-of-arasan: Deploy enhanced strobe support - dw_mmc: Some fixes and clean-ups - dw_mmc: Enable support for erase/discard/trim cmds - dw_mmc: Enable CMD23 support - mediatek: Some fixes related to the eMMC HS400 support - sh_mmcif: Improve support for HW busy detection - rtsx_pci: Enable support for erase/discard/trim cmds" * tag 'mmc-v4.8' of git://git.linaro.org/people/ulf.hansson/mmc: (135 commits) mmc: rtsx_pci: Remove deprecated create_singlethread_workqueue mmc: rtsx_pci: Enable MMC_CAP_ERASE to allow erase/discard/trim requests mmc: rtsx_pci: Use the provided busy timeout from the mmc core mmc: sdhci-pltfm: Drop define for SDHCI_PLTFM_PMOPS mmc: sdhci-pltfm: Convert to use the SET_SYSTEM_SLEEP_PM_OPS mmc: sdhci-pltfm: Make sdhci_pltfm_suspend|resume() static mmc: sdhci-esdhc-imx: Use common sdhci_suspend|resume_host() mmc: sdhci-esdhc-imx: Assign system PM ops within #ifdef CONFIG_PM_SLEEP mmc: sdhci-sirf: Remove non needed #ifdef CONFIG_PM* for dev_pm_ops mmc: sdhci-s3c: Remove non needed #ifdef CONFIG_PM for dev_pm_ops mmc: sdhci-pxav3: Remove non needed #ifdef CONFIG_PM for dev_pm_ops mmc: sdhci-of-esdhc: Simplify code by using SIMPLE_DEV_PM_OPS mmc: sdhci-acpi: Simplify code by using SET_SYSTEM_SLEEP_PM_OPS mmc: sdhci-pci-core: Simplify code by using SET_SYSTEM_SLEEP_PM_OPS mmc: Change the max discard sectors and erase response when HW busy detect phy: rockchip-emmc: Wait even longer for the DLL to lock phy: rockchip-emmc: Be tolerant to card clock of 0 in power on mmc: sdhci-of-arasan: Revert: Always power the PHY off/on when clock changes mmc: sdhci-msm: Add support for UHS cards mmc: sdhci-msm: Add set_uhs_signaling() implementation ...
This commit is contained in:
@@ -9,8 +9,12 @@ Device Tree Bindings for the Arasan SDHCI Controller
|
||||
[4] Documentation/devicetree/bindings/phy/phy-bindings.txt
|
||||
|
||||
Required Properties:
|
||||
- compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or
|
||||
'arasan,sdhci-4.9a' or 'arasan,sdhci-5.1'
|
||||
- compatible: Compatibility string. One of:
|
||||
- "arasan,sdhci-8.9a": generic Arasan SDHCI 8.9a PHY
|
||||
- "arasan,sdhci-4.9a": generic Arasan SDHCI 4.9a PHY
|
||||
- "arasan,sdhci-5.1": generic Arasan SDHCI 5.1 PHY
|
||||
- "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY
|
||||
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
|
||||
- reg: From mmc bindings: Register location and length.
|
||||
- clocks: From clock bindings: Handles to clock inputs.
|
||||
- clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
|
||||
@@ -22,6 +26,17 @@ Required Properties for "arasan,sdhci-5.1":
|
||||
- phys: From PHY bindings: Phandle for the Generic PHY for arasan.
|
||||
- phy-names: MUST be "phy_arasan".
|
||||
|
||||
Optional Properties:
|
||||
- arasan,soc-ctl-syscon: A phandle to a syscon device (see ../mfd/syscon.txt)
|
||||
used to access core corecfg registers. Offsets of registers in this
|
||||
syscon are determined based on the main compatible string for the device.
|
||||
- clock-output-names: If specified, this will be the name of the card clock
|
||||
which will be exposed by this device. Required if #clock-cells is
|
||||
specified.
|
||||
- #clock-cells: If specified this should be the value <0>. With this property
|
||||
in place we will export a clock representing the Card Clock. This clock
|
||||
is expected to be consumed by our PHY. You must also specify
|
||||
|
||||
Example:
|
||||
sdhci@e0100000 {
|
||||
compatible = "arasan,sdhci-8.9a";
|
||||
@@ -42,3 +57,19 @@ Example:
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
} ;
|
||||
|
||||
sdhci: sdhci@fe330000 {
|
||||
compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
|
||||
reg = <0x0 0xfe330000 0x0 0x10000>;
|
||||
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
arasan,soc-ctl-syscon = <&grf>;
|
||||
assigned-clocks = <&cru SCLK_EMMC>;
|
||||
assigned-clock-rates = <200000000>;
|
||||
clock-output-names = "emmc_cardclock";
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
#clock-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
Broadcom BCM2835 SDHCI controller
|
||||
|
||||
This file documents differences between the core properties described
|
||||
by mmc.txt and the properties that represent the BCM2835 controller.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "brcm,bcm2835-sdhci".
|
||||
- clocks : The clock feeding the SDHCI controller.
|
||||
|
||||
Example:
|
||||
|
||||
sdhci: sdhci {
|
||||
compatible = "brcm,bcm2835-sdhci";
|
||||
reg = <0x7e300000 0x100>;
|
||||
interrupts = <2 30>;
|
||||
clocks = <&clk_mmc>;
|
||||
bus-width = <4>;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
* BROADCOM BRCMSTB/BMIPS SDHCI Controller
|
||||
|
||||
This file documents differences between the core properties in mmc.txt
|
||||
and the properties used by the sdhci-brcmstb driver.
|
||||
|
||||
NOTE: The driver disables all UHS speed modes by default and depends
|
||||
on Device Tree properties to enable them for SoC/Board combinations
|
||||
that support them.
|
||||
|
||||
Required properties:
|
||||
- compatible: "brcm,bcm7425-sdhci"
|
||||
|
||||
Refer to clocks/clock-bindings.txt for generic clock consumer properties.
|
||||
|
||||
Example:
|
||||
|
||||
sdhci@f03e0100 {
|
||||
compatible = "brcm,bcm7425-sdhci";
|
||||
reg = <0xf03e0000 0x100>;
|
||||
interrupts = <0x0 0x26 0x0>;
|
||||
sdhci,auto-cmd12;
|
||||
clocks = <&sw_sdio>;
|
||||
sd-uhs-sdr50;
|
||||
sd-uhs-ddr50;
|
||||
};
|
||||
|
||||
sdhci@f03e0300 {
|
||||
non-removable;
|
||||
bus-width = <0x8>;
|
||||
compatible = "brcm,bcm7425-sdhci";
|
||||
reg = <0xf03e0200 0x100>;
|
||||
interrupts = <0x0 0x27 0x0>;
|
||||
sdhci,auto-cmd12;
|
||||
clocks = <sw_sdio>;
|
||||
mmc-hs200-1_8v;
|
||||
};
|
||||
@@ -28,6 +28,8 @@ Optional properties:
|
||||
transparent level shifters on the outputs of the controller. Two cells are
|
||||
required, first cell specifies minimum slot voltage (mV), second cell
|
||||
specifies maximum slot voltage (mV). Several ranges could be specified.
|
||||
- fsl,tuning-start-tap: Specify the start dealy cell point when send first CMD19
|
||||
in tuning procedure.
|
||||
- fsl,tuning-step: Specify the increasing delay cell steps in tuning procedure.
|
||||
The uSDHC use one delay cell as default increasing step to do tuning process.
|
||||
This property allows user to change the tuning step to more than one delay
|
||||
|
||||
@@ -46,8 +46,12 @@ Optional properties:
|
||||
- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
|
||||
- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
|
||||
- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
|
||||
- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported
|
||||
- dsr: Value the card's (optional) Driver Stage Register (DSR) should be
|
||||
programmed with. Valid range: [0 .. 0xffff].
|
||||
- no-sdio: controller is limited to send sdio cmd during initialization
|
||||
- no-sd: controller is limited to send sd cmd during initialization
|
||||
- no-mmc: controller is limited to send mmc cmd during initialization
|
||||
|
||||
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
|
||||
polarity properties, we have to fix the meaning of the "normal" and "inverted"
|
||||
|
||||
@@ -7,6 +7,13 @@ Required properties:
|
||||
- reg: PHY register address offset and length in "general
|
||||
register files"
|
||||
|
||||
Optional clocks using the clock bindings (see ../clock/clock-bindings.txt),
|
||||
specified by name:
|
||||
- clock-names: Should contain "emmcclk". Although this is listed as optional
|
||||
(because most boards can get basic functionality without having
|
||||
access to it), it is strongly suggested.
|
||||
- clocks: Should have a phandle to the card clock exported by the SDHCI driver.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -20,6 +27,8 @@ grf: syscon@ff770000 {
|
||||
emmcphy: phy@f780 {
|
||||
compatible = "rockchip,rk3399-emmc-phy";
|
||||
reg = <0xf780 0x20>;
|
||||
clocks = <&sdhci>;
|
||||
clock-names = "emmcclk";
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -28,6 +28,8 @@ All attributes are read-only.
|
||||
preferred_erase_size Preferred erase size
|
||||
raw_rpmb_size_mult RPMB partition size
|
||||
rel_sectors Reliable write sector count
|
||||
ocr Operation Conditions Register
|
||||
dsr Driver Stage Register
|
||||
|
||||
Note on Erase Size and Preferred Erase Size:
|
||||
|
||||
|
||||
@@ -7863,6 +7863,7 @@ M: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
T: git git://git.linaro.org/people/ulf.hansson/mmc.git
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/mmc/
|
||||
F: drivers/mmc/
|
||||
F: include/linux/mmc/
|
||||
F: include/uapi/linux/mmc/
|
||||
@@ -10355,6 +10356,13 @@ F: tools/testing/selftests/seccomp/*
|
||||
K: \bsecure_computing
|
||||
K: \bTIF_SECCOMP\b
|
||||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) Broadcom BRCMSTB DRIVER
|
||||
M: Al Cooper <alcooperx@gmail.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
L: bcm-kernel-feedback-list@broadcom.com
|
||||
S: Maintained
|
||||
F: drivers/mmc/host/sdhci-brcmstb*
|
||||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
|
||||
M: Ben Dooks <ben-linux@fluff.org>
|
||||
M: Jaehoon Chung <jh80.chung@samsung.com>
|
||||
|
||||
@@ -1801,8 +1801,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
|
||||
do_data_tag = (card->ext_csd.data_tag_unit_size) &&
|
||||
(prq->cmd_flags & REQ_META) &&
|
||||
(rq_data_dir(prq) == WRITE) &&
|
||||
((brq->data.blocks * brq->data.blksz) >=
|
||||
card->ext_csd.data_tag_unit_size);
|
||||
blk_rq_bytes(prq) >= card->ext_csd.data_tag_unit_size;
|
||||
/* Argument of CMD23 */
|
||||
packed_cmd_hdr[(i * 2)] = cpu_to_le32(
|
||||
(do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
|
||||
@@ -1977,8 +1976,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
||||
* When 4KB native sector is enabled, only 8 blocks
|
||||
* multiple read or write is allowed
|
||||
*/
|
||||
if ((brq->data.blocks & 0x07) &&
|
||||
(card->ext_csd.data_sector_size == 4096)) {
|
||||
if (mmc_large_sector(card) &&
|
||||
!IS_ALIGNED(blk_rq_sectors(rqc), 8)) {
|
||||
pr_err("%s: Transfer size is not 4KB sector size aligned\n",
|
||||
req->rq_disk->disk_name);
|
||||
mq_rq = mq->mqrq_cur;
|
||||
@@ -2501,12 +2500,6 @@ force_ro_fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CID_MANFID_SANDISK 0x2
|
||||
#define CID_MANFID_TOSHIBA 0x11
|
||||
#define CID_MANFID_MICRON 0x13
|
||||
#define CID_MANFID_SAMSUNG 0x15
|
||||
#define CID_MANFID_KINGSTON 0x70
|
||||
|
||||
static const struct mmc_fixup blk_fixups[] =
|
||||
{
|
||||
MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
|
||||
|
||||
@@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
|
||||
mmc_card_ddr52(card) ? "DDR " : "",
|
||||
type);
|
||||
} else {
|
||||
pr_info("%s: new %s%s%s%s%s card at address %04x\n",
|
||||
pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
|
||||
mmc_hostname(card->host),
|
||||
mmc_card_uhs(card) ? "ultra high speed " :
|
||||
(mmc_card_hs(card) ? "high speed " : ""),
|
||||
mmc_card_hs400(card) ? "HS400 " :
|
||||
(mmc_card_hs200(card) ? "HS200 " : ""),
|
||||
mmc_card_hs400es(card) ? "Enhanced strobe " : "",
|
||||
mmc_card_ddr52(card) ? "DDR " : "",
|
||||
uhs_bus_speed_mode, type, card->rca);
|
||||
}
|
||||
|
||||
+73
-22
@@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
|
||||
host->ios.bus_width = MMC_BUS_WIDTH_1;
|
||||
host->ios.timing = MMC_TIMING_LEGACY;
|
||||
host->ios.drv_type = 0;
|
||||
host->ios.enhanced_strobe = false;
|
||||
|
||||
/*
|
||||
* Make sure we are in non-enhanced strobe mode before we
|
||||
* actually enable it in ext_csd.
|
||||
*/
|
||||
if ((host->caps2 & MMC_CAP2_HS400_ES) &&
|
||||
host->ops->hs400_enhanced_strobe)
|
||||
host->ops->hs400_enhanced_strobe(host, &host->ios);
|
||||
|
||||
mmc_set_ios(host);
|
||||
}
|
||||
@@ -1925,17 +1934,15 @@ void mmc_init_erase(struct mmc_card *card)
|
||||
* to that size and alignment.
|
||||
*
|
||||
* For SD cards that define Allocation Unit size, limit erases to one
|
||||
* Allocation Unit at a time. For MMC cards that define High Capacity
|
||||
* Erase Size, whether it is switched on or not, limit to that size.
|
||||
* Otherwise just have a stab at a good value. For modern cards it
|
||||
* will end up being 4MiB. Note that if the value is too small, it
|
||||
* can end up taking longer to erase.
|
||||
* Allocation Unit at a time.
|
||||
* For MMC, have a stab at ai good value and for modern cards it will
|
||||
* end up being 4MiB. Note that if the value is too small, it can end
|
||||
* up taking longer to erase. Also note, erase_size is already set to
|
||||
* High Capacity Erase Size if available when this function is called.
|
||||
*/
|
||||
if (mmc_card_sd(card) && card->ssr.au) {
|
||||
card->pref_erase = card->ssr.au;
|
||||
card->erase_shift = ffs(card->ssr.au) - 1;
|
||||
} else if (card->ext_csd.hc_erase_size) {
|
||||
card->pref_erase = card->ext_csd.hc_erase_size;
|
||||
} else if (card->erase_size) {
|
||||
sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
|
||||
if (sz < 128)
|
||||
@@ -2060,7 +2067,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
unsigned int to, unsigned int arg)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
unsigned int qty = 0;
|
||||
unsigned int qty = 0, busy_timeout = 0;
|
||||
bool use_r1b_resp = false;
|
||||
unsigned long timeout;
|
||||
int err;
|
||||
|
||||
@@ -2128,8 +2136,22 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
cmd.opcode = MMC_ERASE;
|
||||
cmd.arg = arg;
|
||||
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);
|
||||
busy_timeout = mmc_erase_timeout(card, arg, qty);
|
||||
/*
|
||||
* If the host controller supports busy signalling and the timeout for
|
||||
* the erase operation does not exceed the max_busy_timeout, we should
|
||||
* use R1B response. Or we need to prevent the host from doing hw busy
|
||||
* detection, which is done by converting to a R1 response instead.
|
||||
*/
|
||||
if (card->host->max_busy_timeout &&
|
||||
busy_timeout > card->host->max_busy_timeout) {
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
|
||||
} else {
|
||||
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.busy_timeout = busy_timeout;
|
||||
use_r1b_resp = true;
|
||||
}
|
||||
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, 0);
|
||||
if (err) {
|
||||
pr_err("mmc_erase: erase error %d, status %#x\n",
|
||||
@@ -2141,7 +2163,14 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
if (mmc_host_is_spi(card->host))
|
||||
goto out;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
|
||||
/*
|
||||
* In case of when R1B + MMC_CAP_WAIT_WHILE_BUSY is used, the polling
|
||||
* shall be avoided.
|
||||
*/
|
||||
if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
|
||||
goto out;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(busy_timeout);
|
||||
do {
|
||||
memset(&cmd, 0, sizeof(struct mmc_command));
|
||||
cmd.opcode = MMC_SEND_STATUS;
|
||||
@@ -2321,23 +2350,41 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
|
||||
unsigned int arg)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
|
||||
unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout;
|
||||
unsigned int last_timeout = 0;
|
||||
|
||||
if (card->erase_shift)
|
||||
if (card->erase_shift) {
|
||||
max_qty = UINT_MAX >> card->erase_shift;
|
||||
else if (mmc_card_sd(card))
|
||||
min_qty = card->pref_erase >> card->erase_shift;
|
||||
} else if (mmc_card_sd(card)) {
|
||||
max_qty = UINT_MAX;
|
||||
else
|
||||
min_qty = card->pref_erase;
|
||||
} else {
|
||||
max_qty = UINT_MAX / card->erase_size;
|
||||
min_qty = card->pref_erase / card->erase_size;
|
||||
}
|
||||
|
||||
/* Find the largest qty with an OK timeout */
|
||||
/*
|
||||
* We should not only use 'host->max_busy_timeout' as the limitation
|
||||
* when deciding the max discard sectors. We should set a balance value
|
||||
* to improve the erase speed, and it can not get too long timeout at
|
||||
* the same time.
|
||||
*
|
||||
* Here we set 'card->pref_erase' as the minimal discard sectors no
|
||||
* matter what size of 'host->max_busy_timeout', but if the
|
||||
* 'host->max_busy_timeout' is large enough for more discard sectors,
|
||||
* then we can continue to increase the max discard sectors until we
|
||||
* get a balance value.
|
||||
*/
|
||||
do {
|
||||
y = 0;
|
||||
for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
|
||||
timeout = mmc_erase_timeout(card, arg, qty + x);
|
||||
if (timeout > host->max_busy_timeout)
|
||||
|
||||
if (qty + x > min_qty &&
|
||||
timeout > host->max_busy_timeout)
|
||||
break;
|
||||
|
||||
if (timeout < last_timeout)
|
||||
break;
|
||||
last_timeout = timeout;
|
||||
@@ -2491,17 +2538,21 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
|
||||
|
||||
mmc_go_idle(host);
|
||||
|
||||
mmc_send_if_cond(host, host->ocr_avail);
|
||||
if (!(host->caps2 & MMC_CAP2_NO_SD))
|
||||
mmc_send_if_cond(host, host->ocr_avail);
|
||||
|
||||
/* Order's important: probe SDIO, then SD, then MMC */
|
||||
if (!(host->caps2 & MMC_CAP2_NO_SDIO))
|
||||
if (!mmc_attach_sdio(host))
|
||||
return 0;
|
||||
|
||||
if (!mmc_attach_sd(host))
|
||||
return 0;
|
||||
if (!mmc_attach_mmc(host))
|
||||
return 0;
|
||||
if (!(host->caps2 & MMC_CAP2_NO_SD))
|
||||
if (!mmc_attach_sd(host))
|
||||
return 0;
|
||||
|
||||
if (!(host->caps2 & MMC_CAP2_NO_MMC))
|
||||
if (!mmc_attach_mmc(host))
|
||||
return 0;
|
||||
|
||||
mmc_power_off(host);
|
||||
return -EIO;
|
||||
|
||||
@@ -148,7 +148,8 @@ static int mmc_ios_show(struct seq_file *s, void *data)
|
||||
str = "mmc HS200";
|
||||
break;
|
||||
case MMC_TIMING_MMC_HS400:
|
||||
str = "mmc HS400";
|
||||
str = mmc_card_hs400es(host->card) ?
|
||||
"mmc HS400 enhanced strobe" : "mmc HS400";
|
||||
break;
|
||||
default:
|
||||
str = "invalid";
|
||||
|
||||
@@ -313,6 +313,14 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
|
||||
if (of_property_read_bool(np, "mmc-hs400-1_2v"))
|
||||
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
|
||||
if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
|
||||
host->caps2 |= MMC_CAP2_HS400_ES;
|
||||
if (of_property_read_bool(np, "no-sdio"))
|
||||
host->caps2 |= MMC_CAP2_NO_SDIO;
|
||||
if (of_property_read_bool(np, "no-sd"))
|
||||
host->caps2 |= MMC_CAP2_NO_SD;
|
||||
if (of_property_read_bool(np, "no-mmc"))
|
||||
host->caps2 |= MMC_CAP2_NO_MMC;
|
||||
|
||||
host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
|
||||
if (host->dsr_req && (host->dsr & ~0xffff)) {
|
||||
|
||||
+174
-79
@@ -45,6 +45,17 @@ static const unsigned int tacc_mant[] = {
|
||||
35, 40, 45, 50, 55, 60, 70, 80,
|
||||
};
|
||||
|
||||
static const struct mmc_fixup mmc_ext_csd_fixups[] = {
|
||||
/*
|
||||
* Certain Hynix eMMC 4.41 cards might get broken when HPI feature
|
||||
* is used so disable the HPI feature for such buggy cards.
|
||||
*/
|
||||
MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
|
||||
0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
|
||||
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
#define UNSTUFF_BITS(resp,start,size) \
|
||||
({ \
|
||||
const int __size = size; \
|
||||
@@ -235,6 +246,11 @@ static void mmc_select_card_type(struct mmc_card *card)
|
||||
avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
|
||||
}
|
||||
|
||||
if ((caps2 & MMC_CAP2_HS400_ES) &&
|
||||
card->ext_csd.strobe_support &&
|
||||
(avail_type & EXT_CSD_CARD_TYPE_HS400))
|
||||
avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
|
||||
|
||||
card->ext_csd.hs_max_dtr = hs_max_dtr;
|
||||
card->ext_csd.hs200_max_dtr = hs200_max_dtr;
|
||||
card->mmc_avail_type = avail_type;
|
||||
@@ -370,6 +386,9 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
*/
|
||||
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
|
||||
|
||||
/* fixup device after ext_csd revision field is updated */
|
||||
mmc_fixup_device(card, mmc_ext_csd_fixups);
|
||||
|
||||
card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
|
||||
card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
|
||||
card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
|
||||
@@ -386,6 +405,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
mmc_card_set_blockaddr(card);
|
||||
}
|
||||
|
||||
card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
|
||||
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
|
||||
mmc_select_card_type(card);
|
||||
|
||||
@@ -500,7 +520,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
card->cid.year += 16;
|
||||
|
||||
/* check whether the eMMC card supports BKOPS */
|
||||
if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
|
||||
if (!mmc_card_broken_hpi(card) &&
|
||||
ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
|
||||
card->ext_csd.bkops = 1;
|
||||
card->ext_csd.man_bkops_en =
|
||||
(ext_csd[EXT_CSD_BKOPS_EN] &
|
||||
@@ -513,7 +534,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
}
|
||||
|
||||
/* check whether the eMMC card supports HPI */
|
||||
if (!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
|
||||
if (!mmc_card_broken_hpi(card) &&
|
||||
!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
|
||||
card->ext_csd.hpi = 1;
|
||||
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
|
||||
card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
|
||||
@@ -727,6 +749,7 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
|
||||
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
|
||||
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
|
||||
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
|
||||
MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
|
||||
|
||||
static ssize_t mmc_fwrev_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
@@ -744,6 +767,22 @@ static ssize_t mmc_fwrev_show(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL);
|
||||
|
||||
static ssize_t mmc_dsr_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct mmc_card *card = mmc_dev_to_card(dev);
|
||||
struct mmc_host *host = card->host;
|
||||
|
||||
if (card->csd.dsr_imp && host->dsr_req)
|
||||
return sprintf(buf, "0x%x\n", host->dsr);
|
||||
else
|
||||
/* return default DSR value */
|
||||
return sprintf(buf, "0x%x\n", 0x404);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
|
||||
|
||||
static struct attribute *mmc_std_attrs[] = {
|
||||
&dev_attr_cid.attr,
|
||||
&dev_attr_csd.attr,
|
||||
@@ -762,6 +801,8 @@ static struct attribute *mmc_std_attrs[] = {
|
||||
&dev_attr_enhanced_area_size.attr,
|
||||
&dev_attr_raw_rpmb_size_mult.attr,
|
||||
&dev_attr_rel_sectors.attr,
|
||||
&dev_attr_ocr.attr,
|
||||
&dev_attr_dsr.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(mmc_std);
|
||||
@@ -959,6 +1000,19 @@ static int mmc_select_bus_width(struct mmc_card *card)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Caller must hold re-tuning */
|
||||
static int mmc_switch_status(struct mmc_card *card)
|
||||
{
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
err = mmc_send_status(card, &status);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mmc_switch_status_error(card->host, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch to the high-speed mode
|
||||
*/
|
||||
@@ -969,9 +1023,11 @@ static int mmc_select_hs(struct mmc_card *card)
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
|
||||
card->ext_csd.generic_cmd6_time,
|
||||
true, true, true);
|
||||
if (!err)
|
||||
true, false, true);
|
||||
if (!err) {
|
||||
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
|
||||
err = mmc_switch_status(card);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1047,23 +1103,9 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Caller must hold re-tuning */
|
||||
static int mmc_switch_status(struct mmc_card *card)
|
||||
{
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
err = mmc_send_status(card, &status);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mmc_switch_status_error(card->host, status);
|
||||
}
|
||||
|
||||
static int mmc_select_hs400(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
bool send_status = true;
|
||||
unsigned int max_dtr;
|
||||
int err = 0;
|
||||
u8 val;
|
||||
@@ -1075,19 +1117,12 @@ static int mmc_select_hs400(struct mmc_card *card)
|
||||
host->ios.bus_width == MMC_BUS_WIDTH_8))
|
||||
return 0;
|
||||
|
||||
if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
|
||||
send_status = false;
|
||||
|
||||
/* Reduce frequency to HS frequency */
|
||||
max_dtr = card->ext_csd.hs_max_dtr;
|
||||
mmc_set_clock(host, max_dtr);
|
||||
|
||||
/* Switch card to HS mode */
|
||||
val = EXT_CSD_TIMING_HS;
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, val,
|
||||
card->ext_csd.generic_cmd6_time,
|
||||
true, send_status, true);
|
||||
true, false, true);
|
||||
if (err) {
|
||||
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
@@ -1097,11 +1132,13 @@ static int mmc_select_hs400(struct mmc_card *card)
|
||||
/* Set host controller to HS timing */
|
||||
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
|
||||
|
||||
if (!send_status) {
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
/* Reduce frequency to HS frequency */
|
||||
max_dtr = card->ext_csd.hs_max_dtr;
|
||||
mmc_set_clock(host, max_dtr);
|
||||
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
/* Switch card to DDR */
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
@@ -1120,7 +1157,7 @@ static int mmc_select_hs400(struct mmc_card *card)
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, val,
|
||||
card->ext_csd.generic_cmd6_time,
|
||||
true, send_status, true);
|
||||
true, false, true);
|
||||
if (err) {
|
||||
pr_err("%s: switch to hs400 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
@@ -1131,11 +1168,9 @@ static int mmc_select_hs400(struct mmc_card *card)
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
|
||||
mmc_set_bus_speed(card);
|
||||
|
||||
if (!send_status) {
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1153,14 +1188,10 @@ int mmc_hs200_to_hs400(struct mmc_card *card)
|
||||
int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
bool send_status = true;
|
||||
unsigned int max_dtr;
|
||||
int err;
|
||||
u8 val;
|
||||
|
||||
if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
|
||||
send_status = false;
|
||||
|
||||
/* Reduce frequency to HS */
|
||||
max_dtr = card->ext_csd.hs_max_dtr;
|
||||
mmc_set_clock(host, max_dtr);
|
||||
@@ -1169,49 +1200,43 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
val = EXT_CSD_TIMING_HS;
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
|
||||
val, card->ext_csd.generic_cmd6_time,
|
||||
true, send_status, true);
|
||||
true, false, true);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
|
||||
|
||||
if (!send_status) {
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
/* Switch HS DDR to HS */
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
|
||||
EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
|
||||
true, send_status, true);
|
||||
true, false, true);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS);
|
||||
|
||||
if (!send_status) {
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
/* Switch HS to HS200 */
|
||||
val = EXT_CSD_TIMING_HS200 |
|
||||
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
|
||||
val, card->ext_csd.generic_cmd6_time, true,
|
||||
send_status, true);
|
||||
val, card->ext_csd.generic_cmd6_time,
|
||||
true, false, true);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
|
||||
|
||||
if (!send_status) {
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
mmc_set_bus_speed(card);
|
||||
|
||||
@@ -1223,6 +1248,78 @@ out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mmc_select_hs400es(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
int err = 0;
|
||||
u8 val;
|
||||
|
||||
if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
|
||||
err = -ENOTSUPP;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
err = mmc_select_bus_width(card);
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
|
||||
/* Switch card to HS mode */
|
||||
err = mmc_select_hs(card);
|
||||
if (err) {
|
||||
pr_err("%s: switch to high-speed failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
/* Switch card to DDR with strobe bit */
|
||||
val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
val,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
if (err) {
|
||||
pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Switch card to HS400 */
|
||||
val = EXT_CSD_TIMING_HS400 |
|
||||
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, val,
|
||||
card->ext_csd.generic_cmd6_time,
|
||||
true, false, true);
|
||||
if (err) {
|
||||
pr_err("%s: switch to hs400es failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Set host controller to HS400 timing and frequency */
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
|
||||
|
||||
/* Controller enable enhanced strobe function */
|
||||
host->ios.enhanced_strobe = true;
|
||||
if (host->ops->hs400_enhanced_strobe)
|
||||
host->ops->hs400_enhanced_strobe(host, &host->ios);
|
||||
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
|
||||
__func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mmc_select_driver_type(struct mmc_card *card)
|
||||
{
|
||||
int card_drv_type, drive_strength, drv_type;
|
||||
@@ -1250,7 +1347,6 @@ static void mmc_select_driver_type(struct mmc_card *card)
|
||||
static int mmc_select_hs200(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
bool send_status = true;
|
||||
unsigned int old_timing, old_signal_voltage;
|
||||
int err = -EINVAL;
|
||||
u8 val;
|
||||
@@ -1268,34 +1364,30 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
|
||||
mmc_select_driver_type(card);
|
||||
|
||||
if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
|
||||
send_status = false;
|
||||
|
||||
/*
|
||||
* Set the bus width(4 or 8) with host's support and
|
||||
* switch to HS200 mode if bus width is set successfully.
|
||||
*/
|
||||
err = mmc_select_bus_width(card);
|
||||
if (err >= 0) {
|
||||
if (err > 0) {
|
||||
val = EXT_CSD_TIMING_HS200 |
|
||||
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, val,
|
||||
card->ext_csd.generic_cmd6_time,
|
||||
true, send_status, true);
|
||||
true, false, true);
|
||||
if (err)
|
||||
goto err;
|
||||
old_timing = host->ios.timing;
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
|
||||
if (!send_status) {
|
||||
err = mmc_switch_status(card);
|
||||
/*
|
||||
* mmc_select_timing() assumes timing has not changed if
|
||||
* it is a switch error.
|
||||
*/
|
||||
if (err == -EBADMSG)
|
||||
mmc_set_timing(host, old_timing);
|
||||
}
|
||||
|
||||
err = mmc_switch_status(card);
|
||||
/*
|
||||
* mmc_select_timing() assumes timing has not changed if
|
||||
* it is a switch error.
|
||||
*/
|
||||
if (err == -EBADMSG)
|
||||
mmc_set_timing(host, old_timing);
|
||||
}
|
||||
err:
|
||||
if (err) {
|
||||
@@ -1310,7 +1402,7 @@ err:
|
||||
}
|
||||
|
||||
/*
|
||||
* Activate High Speed or HS200 mode if supported.
|
||||
* Activate High Speed, HS200 or HS400ES mode if supported.
|
||||
*/
|
||||
static int mmc_select_timing(struct mmc_card *card)
|
||||
{
|
||||
@@ -1319,7 +1411,9 @@ static int mmc_select_timing(struct mmc_card *card)
|
||||
if (!mmc_can_ext_csd(card))
|
||||
goto bus_speed;
|
||||
|
||||
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
|
||||
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
|
||||
err = mmc_select_hs400es(card);
|
||||
else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
|
||||
err = mmc_select_hs200(card);
|
||||
else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
|
||||
err = mmc_select_hs(card);
|
||||
@@ -1583,7 +1677,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
} else if (mmc_card_hs(card)) {
|
||||
/* Select the desired bus width optionally */
|
||||
err = mmc_select_bus_width(card);
|
||||
if (err >= 0) {
|
||||
if (err > 0) {
|
||||
err = mmc_select_hs_ddr(card);
|
||||
if (err)
|
||||
goto free_card;
|
||||
@@ -1616,7 +1710,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
* If cache size is higher than 0, this indicates
|
||||
* the existence of cache and it can be turned on.
|
||||
*/
|
||||
if (card->ext_csd.cache_size > 0) {
|
||||
if (!mmc_card_broken_hpi(card) &&
|
||||
card->ext_csd.cache_size > 0) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_CACHE_CTRL, 1,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
|
||||
+17
-10
@@ -480,6 +480,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
u32 status = 0;
|
||||
bool use_r1b_resp = use_busy_signal;
|
||||
bool expired = false;
|
||||
bool busy = false;
|
||||
|
||||
mmc_retune_hold(host);
|
||||
|
||||
@@ -533,21 +534,26 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
timeout_ms = MMC_OPS_TIMEOUT_MS;
|
||||
|
||||
/* Must check status to be sure of no errors. */
|
||||
timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
|
||||
do {
|
||||
/*
|
||||
* Due to the possibility of being preempted after
|
||||
* sending the status command, check the expiration
|
||||
* time first.
|
||||
*/
|
||||
expired = time_after(jiffies, timeout);
|
||||
if (send_status) {
|
||||
/*
|
||||
* Due to the possibility of being preempted after
|
||||
* sending the status command, check the expiration
|
||||
* time first.
|
||||
*/
|
||||
expired = time_after(jiffies, timeout);
|
||||
err = __mmc_send_status(card, &status, ignore_crc);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
|
||||
break;
|
||||
if (host->ops->card_busy) {
|
||||
if (!host->ops->card_busy(host))
|
||||
break;
|
||||
busy = true;
|
||||
}
|
||||
if (mmc_host_is_spi(host))
|
||||
break;
|
||||
|
||||
@@ -556,19 +562,20 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
* does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
|
||||
* rely on waiting for the stated timeout to be sufficient.
|
||||
*/
|
||||
if (!send_status) {
|
||||
if (!send_status && !host->ops->card_busy) {
|
||||
mmc_delay(timeout_ms);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Timeout if the device never leaves the program state. */
|
||||
if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) {
|
||||
if (expired &&
|
||||
(R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) {
|
||||
pr_err("%s: Card stuck in programming state! %s\n",
|
||||
mmc_hostname(host), __func__);
|
||||
err = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
|
||||
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy);
|
||||
|
||||
err = mmc_switch_status_error(host, status);
|
||||
out:
|
||||
|
||||
@@ -72,6 +72,8 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
|
||||
f->cis_vendor == (u16) SDIO_ANY_ID) &&
|
||||
(f->cis_device == card->cis.device ||
|
||||
f->cis_device == (u16) SDIO_ANY_ID) &&
|
||||
(f->ext_csd_rev == EXT_CSD_REV_ANY ||
|
||||
f->ext_csd_rev == card->ext_csd.rev) &&
|
||||
rev >= f->rev_start && rev <= f->rev_end) {
|
||||
dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
|
||||
f->vendor_fixup(card, f->data);
|
||||
|
||||
@@ -675,8 +675,25 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
|
||||
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
|
||||
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
|
||||
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
|
||||
MMC_DEV_ATTR(ocr, "%08x\n", card->ocr);
|
||||
|
||||
|
||||
static ssize_t mmc_dsr_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct mmc_card *card = mmc_dev_to_card(dev);
|
||||
struct mmc_host *host = card->host;
|
||||
|
||||
if (card->csd.dsr_imp && host->dsr_req)
|
||||
return sprintf(buf, "0x%x\n", host->dsr);
|
||||
else
|
||||
/* return default DSR value */
|
||||
return sprintf(buf, "0x%x\n", 0x404);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL);
|
||||
|
||||
static struct attribute *sd_std_attrs[] = {
|
||||
&dev_attr_cid.attr,
|
||||
&dev_attr_csd.attr,
|
||||
@@ -690,6 +707,8 @@ static struct attribute *sd_std_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_oemid.attr,
|
||||
&dev_attr_serial.attr,
|
||||
&dev_attr_ocr.attr,
|
||||
&dev_attr_dsr.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(sd_std);
|
||||
|
||||
+11
-11
@@ -122,6 +122,7 @@ config MMC_SDHCI_OF_ARASAN
|
||||
tristate "SDHCI OF support for the Arasan SDHCI controllers"
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
depends on OF
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
This selects the Arasan Secure Digital Host Controller Interface
|
||||
(SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC.
|
||||
@@ -296,17 +297,6 @@ config MMC_SDHCI_BCM_KONA
|
||||
|
||||
If you have a controller with this interface, say Y or M here.
|
||||
|
||||
config MMC_SDHCI_BCM2835
|
||||
tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
|
||||
depends on ARCH_BCM2835
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
select MMC_SDHCI_IO_ACCESSORS
|
||||
help
|
||||
This selects the BCM2835 SD/MMC controller. If you have a BCM2835
|
||||
platform with SD or MMC devices, say Y or M here.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_SDHCI_F_SDH30
|
||||
tristate "SDHCI support for Fujitsu Semiconductor F_SDH30"
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
@@ -798,3 +788,13 @@ config MMC_SDHCI_MICROCHIP_PIC32
|
||||
If you have a controller with this interface, say Y or M here.
|
||||
|
||||
If unsure, say N.
|
||||
config MMC_SDHCI_BRCMSTB
|
||||
tristate "Broadcom SDIO/SD/MMC support"
|
||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
default y
|
||||
help
|
||||
This selects support for the SDIO/SD/MMC Host Controller on
|
||||
Broadcom STB SoCs.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
@@ -71,11 +71,11 @@ obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
|
||||
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
|
||||
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
|
||||
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
|
||||
obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
|
||||
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
|
||||
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
|
||||
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
|
||||
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
|
||||
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
|
||||
|
||||
ifeq ($(CONFIG_CB710_DEBUG),y)
|
||||
CFLAGS-cb710-mmc += -DDEBUG
|
||||
|
||||
@@ -157,7 +157,7 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
|
||||
* HOLD register should be bypassed in case there is no phase shift
|
||||
* applied on CMD/DATA that is sent to the card.
|
||||
*/
|
||||
if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel))
|
||||
if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->cur_slot)
|
||||
set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user