From a08373de21b46894df366a29f217df9f5ea35211 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 1 Apr 2020 16:55:31 +0200 Subject: [PATCH 001/127] mmc: android-goldfish: Enable MMC_CAP2_NO_SDIO Instead of explicitly checking for SDIO specific requests and then returning an error code, let's set MMC_CAP2_NO_SDIO to tell the mmc core to prevent them altogether. Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200401145531.23247-1-ulf.hansson@linaro.org --- drivers/mmc/host/android-goldfish.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c index 914e17bab3be..ceb4924e02d0 100644 --- a/drivers/mmc/host/android-goldfish.c +++ b/drivers/mmc/host/android-goldfish.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -404,14 +403,6 @@ static void goldfish_mmc_request(struct mmc_host *mmc, struct mmc_request *req) host->mrq = req; goldfish_mmc_prepare_data(host, req); goldfish_mmc_start_command(host, req->cmd); - - /* - * This is to avoid accidentally being detected as an SDIO card - * in mmc_attach_sdio(). - */ - if (req->cmd->opcode == SD_IO_SEND_OP_COND && - req->cmd->flags == (MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR)) - req->cmd->error = -EINVAL; } static void goldfish_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -482,6 +473,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev) mmc->f_max = 24000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps2 = MMC_CAP2_NO_SDIO; /* Use scatterlist DMA to reduce per-transfer costs. * NOTE max_seg_size assumption that small blocks aren't From a049b5aeb7449ab41c3894ea8f37ed015507591c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Apr 2020 13:37:24 +0200 Subject: [PATCH 002/127] mmc: sdhci-sprd: Drop redundant cap flags The MMC_CAP_ERASE and MMC_CAP_CMD23 flags are already being set in the common sdhci_setup_host(). This makes it redundant to set them for sdhci-sprd, so let's drop them. Signed-off-by: Ulf Hansson Reviewed-by: Baolin Wang Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20200406113724.8504-1-ulf.hansson@linaro.org --- drivers/mmc/host/sdhci-sprd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index 2ab42c59e4f8..60c3a4c620f9 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -556,7 +556,8 @@ static int sdhci_sprd_probe(struct platform_device *pdev) sdhci_sprd_voltage_switch; host->mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY; + MMC_CAP_WAIT_WHILE_BUSY; + ret = mmc_of_parse(host->mmc); if (ret) goto pltfm_free; From 4c3965aa995bd31d0454fa5e20314f1eeead8413 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 6 Apr 2020 13:43:37 +0200 Subject: [PATCH 003/127] mmc: au1xmmc: Drop redundant code in au1xmmc_send_command() The in-parameter "wait" is always set to 0 by the caller, hence just drop it and its corresponding code. Signed-off-by: Ulf Hansson Acked-by: Manuel Lauss Link: https://lore.kernel.org/r/20200406114337.8802-1-ulf.hansson@linaro.org --- drivers/mmc/host/au1xmmc.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 8823680ca42c..9bb1910268ca 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -259,7 +259,7 @@ static void au1xmmc_tasklet_finish(unsigned long param) au1xmmc_finish_request(host); } -static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, +static int au1xmmc_send_command(struct au1xmmc_host *host, struct mmc_command *cmd, struct mmc_data *data) { u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); @@ -302,9 +302,6 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, __raw_writel(cmd->arg, HOST_CMDARG(host)); wmb(); /* drain writebuffer */ - if (wait) - IRQ_OFF(host, SD_CONFIG_CR); - __raw_writel((mmccmd | SD_CMD_GO), HOST_CMD(host)); wmb(); /* drain writebuffer */ @@ -312,19 +309,6 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, while (__raw_readl(HOST_CMD(host)) & SD_CMD_GO) /* nop */; - /* Wait for the command to come back */ - if (wait) { - u32 status = __raw_readl(HOST_STATUS(host)); - - while (!(status & SD_STATUS_CR)) - status = __raw_readl(HOST_STATUS(host)); - - /* Clear the CR status */ - __raw_writel(SD_STATUS_CR, HOST_STATUS(host)); - - IRQ_ON(host, SD_CONFIG_CR); - } - return 0; } @@ -711,7 +695,7 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq) } if (!ret) - ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data); + ret = au1xmmc_send_command(host, mrq->cmd, mrq->data); if (ret) { mrq->cmd->error = ret; From f51167c010ea848160c01aa90ed172d8f569c27c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 7 Apr 2020 16:39:03 +0200 Subject: [PATCH 004/127] mmc: s3cmci: Drop redundant code in s3cmci_setup_data() The in-parameter struct mmc_data *data is never NULL, because the caller always provides a valid pointer. Hence drop the corresponding redundant code. Signed-off-by: Ulf Hansson Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20200407143903.22477-1-ulf.hansson@linaro.org --- drivers/mmc/host/s3cmci.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 1e616ae56b13..444b2769ae2c 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -958,13 +958,6 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) { u32 dcon, imsk, stoptries = 3; - /* write DCON register */ - - if (!data) { - writel(0, host->base + S3C2410_SDIDCON); - return 0; - } - if ((data->blksz & 3) != 0) { /* We cannot deal with unaligned blocks with more than * one block being transferred. */ From 2871ec99ee18ab72f5426bf3082bd5775d4e93c2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 9 Apr 2020 14:54:22 +0200 Subject: [PATCH 005/127] mmc: wbsd: Replace hardcoded command numbers with existing defines Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200409125422.21842-1-ulf.hansson@linaro.org --- drivers/mmc/host/wbsd.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 740179f42cf2..67f917d6ecd3 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -770,22 +772,22 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) * interrupts. */ switch (cmd->opcode) { - case 11: - case 17: - case 18: - case 20: - case 24: - case 25: - case 26: - case 27: - case 30: - case 42: - case 56: + case SD_SWITCH_VOLTAGE: + case MMC_READ_SINGLE_BLOCK: + case MMC_READ_MULTIPLE_BLOCK: + case MMC_WRITE_DAT_UNTIL_STOP: + case MMC_WRITE_BLOCK: + case MMC_WRITE_MULTIPLE_BLOCK: + case MMC_PROGRAM_CID: + case MMC_PROGRAM_CSD: + case MMC_SEND_WRITE_PROT: + case MMC_LOCK_UNLOCK: + case MMC_GEN_CMD: break; /* ACMDs. We don't keep track of state, so we just treat them * like any other command. */ - case 51: + case SD_APP_SEND_SCR: break; default: From 1fd7b984f56858e0e4aebbba821c1b1e8693a06c Mon Sep 17 00:00:00 2001 From: Manish Narani Date: Mon, 6 Apr 2020 23:13:30 +0530 Subject: [PATCH 006/127] dt-bindings: mmc: arasan: Document 'xlnx,versal-8.9a' controller Add documentation for 'xlnx,versal-8.9a' SDHCI controller followed by example. Signed-off-by: Manish Narani Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1586195015-128992-2-git-send-email-manish.narani@xilinx.com Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/arasan,sdhci.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt index 428685eb2ded..630fe707f5c4 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt @@ -18,6 +18,9 @@ Required Properties: - "xlnx,zynqmp-8.9a": ZynqMP SDHCI 8.9a PHY For this device it is strongly suggested to include clock-output-names and #clock-cells. + - "xlnx,versal-8.9a": Versal SDHCI 8.9a PHY + For this device it is strongly suggested to include clock-output-names and + #clock-cells. - "ti,am654-sdhci-5.1", "arasan,sdhci-5.1": TI AM654 MMC PHY Note: This binding has been deprecated and moved to [5]. - "intel,lgm-sdhci-5.1-emmc", "arasan,sdhci-5.1": Intel LGM eMMC PHY @@ -104,6 +107,18 @@ Example: clk-phase-sd-hs = <63>, <72>; }; + sdhci: mmc@f1040000 { + compatible = "xlnx,versal-8.9a", "arasan,sdhci-8.9a"; + interrupt-parent = <&gic>; + interrupts = <0 126 4>; + reg = <0x0 0xf1040000 0x0 0x10000>; + clocks = <&clk200>, <&clk200>; + clock-names = "clk_xin", "clk_ahb"; + clock-output-names = "clk_out_sd0", "clk_in_sd0"; + #clock-cells = <1>; + clk-phase-sd-hs = <132>, <60>; + }; + emmc: sdhci@ec700000 { compatible = "intel,lgm-sdhci-5.1-emmc", "arasan,sdhci-5.1"; reg = <0xec700000 0x300>; From 1a470721c8f5a73e272fffb590debda5e65a2eaf Mon Sep 17 00:00:00 2001 From: Manish Narani Date: Mon, 6 Apr 2020 23:13:31 +0530 Subject: [PATCH 007/127] sdhci: arasan: Add support for Versal Tap Delays Add support to set tap delays for Xilinx Versal SD controller. The tap delay registers have moved to SD controller space in Versal. Make the changes accordingly. Signed-off-by: Manish Narani Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1586195015-128992-3-git-send-email-manish.narani@xilinx.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 175 +++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index d4905c106c06..9e2ea3b813b3 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -28,15 +28,26 @@ #include "sdhci-pltfm.h" #define SDHCI_ARASAN_VENDOR_REGISTER 0x78 + +#define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8 +#define SDHCI_ARASAN_OTAPDLY_REGISTER 0xF0FC + #define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 #define VENDOR_ENHANCED_STROBE BIT(0) #define PHY_CLK_TOO_SLOW_HZ 400000 +#define SDHCI_ITAPDLY_CHGWIN 0x200 +#define SDHCI_ITAPDLY_ENABLE 0x100 +#define SDHCI_OTAPDLY_ENABLE 0x40 + /* Default settings for ZynqMP Clock Phases */ #define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0} #define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0} +#define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0} +#define VERSAL_OCLK_PHASE {0, 60, 48, 0, 48, 72, 90, 36, 60, 90, 0} + /* * On some SoCs the syscon area has a feature where the upper 16-bits of * each 32-bit register act as a write mask for the lower 16-bits. This allows @@ -555,6 +566,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = { .compatible = "xlnx,zynqmp-8.9a", .data = &sdhci_arasan_zynqmp_data, }, + { + .compatible = "xlnx,versal-8.9a", + .data = &sdhci_arasan_zynqmp_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); @@ -757,6 +772,152 @@ static const struct clk_ops zynqmp_sampleclk_ops = { .set_phase = sdhci_zynqmp_sampleclk_set_phase, }; +/** + * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays + * + * Set the SD Output Clock Tap Delays for Output path + * + * @hw: Pointer to the hardware clock structure. + * @degrees The clock phase shift between 0 - 359. + * Return: 0 on success and error value on error + */ +static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) +{ + struct sdhci_arasan_clk_data *clk_data = + container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); + struct sdhci_arasan_data *sdhci_arasan = + container_of(clk_data, struct sdhci_arasan_data, clk_data); + struct sdhci_host *host = sdhci_arasan->host; + u8 tap_delay, tap_max = 0; + int ret; + + /* + * This is applicable for SDHCI_SPEC_300 and above + * Versal does not set phase for <=25MHz clock. + * If degrees is zero, no need to do anything. + */ + if (host->version < SDHCI_SPEC_300 || + host->timing == MMC_TIMING_LEGACY || + host->timing == MMC_TIMING_UHS_SDR12 || !degrees) + return 0; + + switch (host->timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR25: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + /* For 50MHz clock, 30 Taps are available */ + tap_max = 30; + break; + case MMC_TIMING_UHS_SDR50: + /* For 100MHz clock, 15 Taps are available */ + tap_max = 15; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* For 200MHz clock, 8 Taps are available */ + tap_max = 8; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + /* Set the Clock Phase */ + if (tap_delay) { + u32 regval; + + regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER); + regval |= SDHCI_OTAPDLY_ENABLE; + sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); + regval |= tap_delay; + sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); + } + + return ret; +} + +static const struct clk_ops versal_sdcardclk_ops = { + .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, + .set_phase = sdhci_versal_sdcardclk_set_phase, +}; + +/** + * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays + * + * Set the SD Input Clock Tap Delays for Input path + * + * @hw: Pointer to the hardware clock structure. + * @degrees The clock phase shift between 0 - 359. + * Return: 0 on success and error value on error + */ +static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) +{ + struct sdhci_arasan_clk_data *clk_data = + container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); + struct sdhci_arasan_data *sdhci_arasan = + container_of(clk_data, struct sdhci_arasan_data, clk_data); + struct sdhci_host *host = sdhci_arasan->host; + u8 tap_delay, tap_max = 0; + int ret; + + /* + * This is applicable for SDHCI_SPEC_300 and above + * Versal does not set phase for <=25MHz clock. + * If degrees is zero, no need to do anything. + */ + if (host->version < SDHCI_SPEC_300 || + host->timing == MMC_TIMING_LEGACY || + host->timing == MMC_TIMING_UHS_SDR12 || !degrees) + return 0; + + switch (host->timing) { + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR25: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + /* For 50MHz clock, 120 Taps are available */ + tap_max = 120; + break; + case MMC_TIMING_UHS_SDR50: + /* For 100MHz clock, 60 Taps are available */ + tap_max = 60; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + /* For 200MHz clock, 30 Taps are available */ + tap_max = 30; + default: + break; + } + + tap_delay = (degrees * tap_max) / 360; + + /* Set the Clock Phase */ + if (tap_delay) { + u32 regval; + + regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval |= SDHCI_ITAPDLY_CHGWIN; + sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval |= SDHCI_ITAPDLY_ENABLE; + sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval |= tap_delay; + sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + regval &= ~SDHCI_ITAPDLY_CHGWIN; + sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); + } + + return ret; +} + +static const struct clk_ops versal_sampleclk_ops = { + .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, + .set_phase = sdhci_versal_sampleclk_set_phase, +}; + static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -954,6 +1115,16 @@ static void arasan_dt_parse_clk_phases(struct device *dev, } } + if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) { + iclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) VERSAL_ICLK_PHASE; + oclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) VERSAL_OCLK_PHASE; + + for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { + clk_data->clk_phase_in[i] = iclk_phase[i]; + clk_data->clk_phase_out[i] = oclk_phase[i]; + } + } + arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, "clk-phase-legacy"); arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, @@ -1014,6 +1185,8 @@ sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, sdcardclk_init.flags = CLK_GET_RATE_NOCACHE; if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) sdcardclk_init.ops = &zynqmp_sdcardclk_ops; + else if (of_device_is_compatible(np, "xlnx,versal-8.9a")) + sdcardclk_init.ops = &versal_sdcardclk_ops; else sdcardclk_init.ops = &arasan_sdcardclk_ops; @@ -1066,6 +1239,8 @@ sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, sampleclk_init.flags = CLK_GET_RATE_NOCACHE; if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) sampleclk_init.ops = &zynqmp_sampleclk_ops; + else if (of_device_is_compatible(np, "xlnx,versal-8.9a")) + sampleclk_init.ops = &versal_sampleclk_ops; else sampleclk_init.ops = &arasan_sampleclk_ops; From 19ee441f2cab760921b15df11cb7ea2fb4751567 Mon Sep 17 00:00:00 2001 From: Manish Narani Date: Mon, 6 Apr 2020 23:13:32 +0530 Subject: [PATCH 008/127] mmc: sdhci-of-arasan: Rename sdhci_arasan_data to avoid confusion There is 'struct sdhci_arasan_data' but also 'struct sdhci_arasan_of_data sdhci_arasan_data'. Rename the latter to avoid confusion with the name of the struct. Reported-by: Adrian Hunter Signed-off-by: Manish Narani Link: https://lore.kernel.org/r/1586195015-128992-4-git-send-email-manish.narani@xilinx.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 9e2ea3b813b3..51e134713631 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -354,7 +354,7 @@ static const struct sdhci_pltfm_data sdhci_arasan_pdata = { SDHCI_QUIRK2_STOP_WITH_TC, }; -static struct sdhci_arasan_of_data sdhci_arasan_data = { +static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { .pdata = &sdhci_arasan_pdata, }; @@ -552,15 +552,15 @@ static const struct of_device_id sdhci_arasan_of_match[] = { /* Generic compatible below here */ { .compatible = "arasan,sdhci-8.9a", - .data = &sdhci_arasan_data, + .data = &sdhci_arasan_generic_data, }, { .compatible = "arasan,sdhci-5.1", - .data = &sdhci_arasan_data, + .data = &sdhci_arasan_generic_data, }, { .compatible = "arasan,sdhci-4.9a", - .data = &sdhci_arasan_data, + .data = &sdhci_arasan_generic_data, }, { .compatible = "xlnx,zynqmp-8.9a", From 37d3ee7c5dc03944bdcb05d5c654dda3abd31795 Mon Sep 17 00:00:00 2001 From: Manish Narani Date: Mon, 6 Apr 2020 23:13:33 +0530 Subject: [PATCH 009/127] mmc: sdhci-of-arasan: Rearrange the platform data structs for modularity Existing driver code has the platform specific structures scattered throughout the driver code. Rearrange the platform specific data structures for more modularity and readability. This will help in adding new static functions with more ease. Signed-off-by: Manish Narani Link: https://lore.kernel.org/r/1586195015-128992-5-git-send-email-manish.narani@xilinx.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 158 +++++++++++++++-------------- 1 file changed, 81 insertions(+), 77 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 51e134713631..f12d20519259 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -346,29 +346,6 @@ static const struct sdhci_ops sdhci_arasan_ops = { .set_power = sdhci_set_power_and_bus_voltage, }; -static const struct sdhci_pltfm_data sdhci_arasan_pdata = { - .ops = &sdhci_arasan_ops, - .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | - SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | - SDHCI_QUIRK2_STOP_WITH_TC, -}; - -static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { - .pdata = &sdhci_arasan_pdata, -}; - -static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = { - .ops = &sdhci_arasan_ops, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | - SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | - SDHCI_QUIRK2_STOP_WITH_TC, -}; - -static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = { - .pdata = &sdhci_arasan_zynqmp_pdata, -}; - static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) { int cmd_error = 0; @@ -425,21 +402,6 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, }; -static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { - .soc_ctl_map = &rk3399_soc_ctl_map, - .pdata = &sdhci_arasan_cqe_pdata, -}; - -static struct sdhci_arasan_of_data intel_lgm_emmc_data = { - .soc_ctl_map = &intel_lgm_emmc_soc_ctl_map, - .pdata = &sdhci_arasan_cqe_pdata, -}; - -static struct sdhci_arasan_of_data intel_lgm_sdxc_data = { - .soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map, - .pdata = &sdhci_arasan_cqe_pdata, -}; - #ifdef CONFIG_PM_SLEEP /** * sdhci_arasan_suspend - Suspend method for the driver @@ -535,45 +497,6 @@ static int sdhci_arasan_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, sdhci_arasan_resume); -static const struct of_device_id sdhci_arasan_of_match[] = { - /* SoC-specific compatible strings w/ soc_ctl_map */ - { - .compatible = "rockchip,rk3399-sdhci-5.1", - .data = &sdhci_arasan_rk3399_data, - }, - { - .compatible = "intel,lgm-sdhci-5.1-emmc", - .data = &intel_lgm_emmc_data, - }, - { - .compatible = "intel,lgm-sdhci-5.1-sdxc", - .data = &intel_lgm_sdxc_data, - }, - /* Generic compatible below here */ - { - .compatible = "arasan,sdhci-8.9a", - .data = &sdhci_arasan_generic_data, - }, - { - .compatible = "arasan,sdhci-5.1", - .data = &sdhci_arasan_generic_data, - }, - { - .compatible = "arasan,sdhci-4.9a", - .data = &sdhci_arasan_generic_data, - }, - { - .compatible = "xlnx,zynqmp-8.9a", - .data = &sdhci_arasan_zynqmp_data, - }, - { - .compatible = "xlnx,versal-8.9a", - .data = &sdhci_arasan_zynqmp_data, - }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); - /** * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate * @@ -1149,6 +1072,87 @@ static void arasan_dt_parse_clk_phases(struct device *dev, "clk-phase-mmc-hs400"); } +static const struct sdhci_pltfm_data sdhci_arasan_pdata = { + .ops = &sdhci_arasan_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_STOP_WITH_TC, +}; + +static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { + .pdata = &sdhci_arasan_pdata, +}; + +static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { + .soc_ctl_map = &rk3399_soc_ctl_map, + .pdata = &sdhci_arasan_cqe_pdata, +}; + +static struct sdhci_arasan_of_data intel_lgm_emmc_data = { + .soc_ctl_map = &intel_lgm_emmc_soc_ctl_map, + .pdata = &sdhci_arasan_cqe_pdata, +}; + +static struct sdhci_arasan_of_data intel_lgm_sdxc_data = { + .soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map, + .pdata = &sdhci_arasan_cqe_pdata, +}; + +static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = { + .ops = &sdhci_arasan_ops, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_STOP_WITH_TC, +}; + +static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = { + .pdata = &sdhci_arasan_zynqmp_pdata, +}; + +static struct sdhci_arasan_of_data sdhci_arasan_versal_data = { + .pdata = &sdhci_arasan_zynqmp_pdata, +}; + +static const struct of_device_id sdhci_arasan_of_match[] = { + /* SoC-specific compatible strings w/ soc_ctl_map */ + { + .compatible = "rockchip,rk3399-sdhci-5.1", + .data = &sdhci_arasan_rk3399_data, + }, + { + .compatible = "intel,lgm-sdhci-5.1-emmc", + .data = &intel_lgm_emmc_data, + }, + { + .compatible = "intel,lgm-sdhci-5.1-sdxc", + .data = &intel_lgm_sdxc_data, + }, + /* Generic compatible below here */ + { + .compatible = "arasan,sdhci-8.9a", + .data = &sdhci_arasan_generic_data, + }, + { + .compatible = "arasan,sdhci-5.1", + .data = &sdhci_arasan_generic_data, + }, + { + .compatible = "arasan,sdhci-4.9a", + .data = &sdhci_arasan_generic_data, + }, + { + .compatible = "xlnx,zynqmp-8.9a", + .data = &sdhci_arasan_zynqmp_data, + }, + { + .compatible = "xlnx,versal-8.9a", + .data = &sdhci_arasan_versal_data, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); + /** * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use * From 16ada730a759d693bfa3724767d2b4d61d645222 Mon Sep 17 00:00:00 2001 From: Manish Narani Date: Mon, 6 Apr 2020 23:13:34 +0530 Subject: [PATCH 010/127] mmc: sdhci-of-arasan: Modify clock operations handling The SDHCI clock operations are platform specific. So it better to define them separately for particular platform. This will prevent multiple if..else conditions and will make it easy for user to add their own clock operations handlers. Signed-off-by: Manish Narani Link: https://lore.kernel.org/r/1586195015-128992-6-git-send-email-manish.narani@xilinx.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 50 +++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index f12d20519259..a9a6346d46dd 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -87,6 +87,17 @@ struct sdhci_arasan_soc_ctl_map { bool hiword_update; }; +/** + * struct sdhci_arasan_clk_ops - Clock Operations for Arasan SD controller + * + * @sdcardclk_ops: The output clock related operations + * @sampleclk_ops: The sample clock related operations + */ +struct sdhci_arasan_clk_ops { + const struct clk_ops *sdcardclk_ops; + const struct clk_ops *sampleclk_ops; +}; + /** * struct sdhci_arasan_clk_data * @sdcardclk_hw: Struct for the clock we might provide to a PHY. @@ -120,6 +131,7 @@ struct sdhci_arasan_zynqmp_clk_data { * @phy: Pointer to the generic phy * @is_phy_on: True if the PHY is on; false if not. * @clk_data: Struct for the Arasan Controller Clock Data. + * @clk_ops: Struct for the Arasan Controller Clock Operations. * @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers. * @soc_ctl_map: Map to get offsets into soc_ctl registers. */ @@ -131,6 +143,7 @@ struct sdhci_arasan_data { bool has_cqe; struct sdhci_arasan_clk_data clk_data; + const struct sdhci_arasan_clk_ops *clk_ops; struct regmap *soc_ctl_base; const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; @@ -146,6 +159,7 @@ struct sdhci_arasan_data { struct sdhci_arasan_of_data { const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; const struct sdhci_pltfm_data *pdata; + const struct sdhci_arasan_clk_ops *clk_ops; }; static const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = { @@ -1080,23 +1094,32 @@ static const struct sdhci_pltfm_data sdhci_arasan_pdata = { SDHCI_QUIRK2_STOP_WITH_TC, }; +static const struct sdhci_arasan_clk_ops arasan_clk_ops = { + .sdcardclk_ops = &arasan_sdcardclk_ops, + .sampleclk_ops = &arasan_sampleclk_ops, +}; + static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { .pdata = &sdhci_arasan_pdata, + .clk_ops = &arasan_clk_ops, }; static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { .soc_ctl_map = &rk3399_soc_ctl_map, .pdata = &sdhci_arasan_cqe_pdata, + .clk_ops = &arasan_clk_ops, }; static struct sdhci_arasan_of_data intel_lgm_emmc_data = { .soc_ctl_map = &intel_lgm_emmc_soc_ctl_map, .pdata = &sdhci_arasan_cqe_pdata, + .clk_ops = &arasan_clk_ops, }; static struct sdhci_arasan_of_data intel_lgm_sdxc_data = { .soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map, .pdata = &sdhci_arasan_cqe_pdata, + .clk_ops = &arasan_clk_ops, }; static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = { @@ -1106,12 +1129,24 @@ static const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = { SDHCI_QUIRK2_STOP_WITH_TC, }; +static const struct sdhci_arasan_clk_ops zynqmp_clk_ops = { + .sdcardclk_ops = &zynqmp_sdcardclk_ops, + .sampleclk_ops = &zynqmp_sampleclk_ops, +}; + static struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = { .pdata = &sdhci_arasan_zynqmp_pdata, + .clk_ops = &zynqmp_clk_ops, +}; + +static const struct sdhci_arasan_clk_ops versal_clk_ops = { + .sdcardclk_ops = &versal_sdcardclk_ops, + .sampleclk_ops = &versal_sampleclk_ops, }; static struct sdhci_arasan_of_data sdhci_arasan_versal_data = { .pdata = &sdhci_arasan_zynqmp_pdata, + .clk_ops = &versal_clk_ops, }; static const struct of_device_id sdhci_arasan_of_match[] = { @@ -1187,12 +1222,7 @@ sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, sdcardclk_init.parent_names = &parent_clk_name; sdcardclk_init.num_parents = 1; sdcardclk_init.flags = CLK_GET_RATE_NOCACHE; - if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) - sdcardclk_init.ops = &zynqmp_sdcardclk_ops; - else if (of_device_is_compatible(np, "xlnx,versal-8.9a")) - sdcardclk_init.ops = &versal_sdcardclk_ops; - else - sdcardclk_init.ops = &arasan_sdcardclk_ops; + sdcardclk_init.ops = sdhci_arasan->clk_ops->sdcardclk_ops; clk_data->sdcardclk_hw.init = &sdcardclk_init; clk_data->sdcardclk = @@ -1241,12 +1271,7 @@ sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, sampleclk_init.parent_names = &parent_clk_name; sampleclk_init.num_parents = 1; sampleclk_init.flags = CLK_GET_RATE_NOCACHE; - if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) - sampleclk_init.ops = &zynqmp_sampleclk_ops; - else if (of_device_is_compatible(np, "xlnx,versal-8.9a")) - sampleclk_init.ops = &versal_sampleclk_ops; - else - sampleclk_init.ops = &arasan_sampleclk_ops; + sampleclk_init.ops = sdhci_arasan->clk_ops->sampleclk_ops; clk_data->sampleclk_hw.init = &sampleclk_init; clk_data->sampleclk = @@ -1394,6 +1419,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev) sdhci_arasan->host = host; sdhci_arasan->soc_ctl_map = data->soc_ctl_map; + sdhci_arasan->clk_ops = data->clk_ops; node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0); if (node) { From 4908460ef16e1a5b7597c2a9871661e827ef8ee7 Mon Sep 17 00:00:00 2001 From: Manish Narani Date: Mon, 6 Apr 2020 23:13:35 +0530 Subject: [PATCH 011/127] mmc: sdhci-of-arasan: Fix kernel-doc warnings Modify code to fix the warnings reported by kernel-doc for better documentation. Signed-off-by: Manish Narani Link: https://lore.kernel.org/r/1586195015-128992-7-git-send-email-manish.narani@xilinx.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 114 ++++++++++++++++------------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index a9a6346d46dd..16e26c217a77 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -73,13 +73,13 @@ struct sdhci_arasan_soc_ctl_field { /** * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers * - * It's up to the licensee of the Arsan IP block to make these available - * somewhere if needed. Presumably these will be scattered somewhere that's - * accessible via the syscon API. - * * @baseclkfreq: Where to find corecfg_baseclkfreq * @clockmultiplier: Where to find corecfg_clockmultiplier * @hiword_update: If true, use HIWORD_UPDATE to access the syscon + * + * It's up to the licensee of the Arsan IP block to make these available + * somewhere if needed. Presumably these will be scattered somewhere that's + * accessible via the syscon API. */ struct sdhci_arasan_soc_ctl_map { struct sdhci_arasan_soc_ctl_field baseclkfreq; @@ -99,7 +99,8 @@ struct sdhci_arasan_clk_ops { }; /** - * struct sdhci_arasan_clk_data + * struct sdhci_arasan_clk_data - Arasan Controller Clock Data. + * * @sdcardclk_hw: Struct for the clock we might provide to a PHY. * @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw. * @sampleclk_hw: Struct for the clock we might provide to a PHY. @@ -125,15 +126,18 @@ struct sdhci_arasan_zynqmp_clk_data { }; /** - * struct sdhci_arasan_data + * struct sdhci_arasan_data - Arasan Controller Data + * * @host: Pointer to the main SDHCI host structure. * @clk_ahb: Pointer to the AHB clock * @phy: Pointer to the generic phy * @is_phy_on: True if the PHY is on; false if not. + * @has_cqe: True if controller has command queuing engine. * @clk_data: Struct for the Arasan Controller Clock Data. * @clk_ops: Struct for the Arasan Controller Clock Operations. * @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers. * @soc_ctl_map: Map to get offsets into soc_ctl registers. + * @quirks: Arasan deviations from spec. */ struct sdhci_arasan_data { struct sdhci_host *host; @@ -147,7 +151,7 @@ struct sdhci_arasan_data { struct regmap *soc_ctl_base; const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; - unsigned int quirks; /* Arasan deviations from spec */ + unsigned int quirks; /* Controller does not have CD wired and will not function normally without */ #define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0) @@ -183,14 +187,16 @@ static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { /** * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers * + * @host: The sdhci_host + * @fld: The field to write to + * @val: The value to write + * * This function allows writing to fields in sdhci_arasan_soc_ctl_map. * Note that if a field is specified as not available (shift < 0) then * this function will silently return an error code. It will be noisy * and print errors for any other (unexpected) errors. * - * @host: The sdhci_host - * @fld: The field to write to - * @val: The value to write + * Return: 0 on success and error value on error */ static int sdhci_arasan_syscon_write(struct sdhci_host *host, const struct sdhci_arasan_soc_ctl_field *fld, @@ -420,9 +426,10 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { /** * sdhci_arasan_suspend - Suspend method for the driver * @dev: Address of the device structure - * Returns 0 on success and error value on error * * Put the device in a low power state. + * + * Return: 0 on success and error value on error */ static int sdhci_arasan_suspend(struct device *dev) { @@ -463,9 +470,10 @@ static int sdhci_arasan_suspend(struct device *dev) /** * sdhci_arasan_resume - Resume method for the driver * @dev: Address of the device structure - * Returns 0 on success and error value on error * * Resume operation after suspend + * + * Return: 0 on success and error value on error */ static int sdhci_arasan_resume(struct device *dev) { @@ -514,16 +522,16 @@ static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, /** * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate * + * @hw: Pointer to the hardware clock structure. + * @parent_rate: The parent rate (should be rate of clk_xin). + * * Return the current actual rate of the SD card clock. This can be used * to communicate with out PHY. * - * @hw: Pointer to the hardware clock structure. - * @parent_rate The parent rate (should be rate of clk_xin). - * Returns the card clock rate. + * Return: The card clock rate. */ static unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) - { struct sdhci_arasan_clk_data *clk_data = container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); @@ -541,16 +549,16 @@ static const struct clk_ops arasan_sdcardclk_ops = { /** * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate * + * @hw: Pointer to the hardware clock structure. + * @parent_rate: The parent rate (should be rate of clk_xin). + * * Return the current actual rate of the sampling clock. This can be used * to communicate with out PHY. * - * @hw: Pointer to the hardware clock structure. - * @parent_rate The parent rate (should be rate of clk_xin). - * Returns the sample clock rate. + * Return: The sample clock rate. */ static unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) - { struct sdhci_arasan_clk_data *clk_data = container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); @@ -568,14 +576,14 @@ static const struct clk_ops arasan_sampleclk_ops = { /** * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays * + * @hw: Pointer to the hardware clock structure. + * @degrees: The clock phase shift between 0 - 359. + * * Set the SD Output Clock Tap Delays for Output path * - * @hw: Pointer to the hardware clock structure. - * @degrees The clock phase shift between 0 - 359. * Return: 0 on success and error value on error */ static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) - { struct sdhci_arasan_clk_data *clk_data = container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); @@ -640,14 +648,14 @@ static const struct clk_ops zynqmp_sdcardclk_ops = { /** * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays * + * @hw: Pointer to the hardware clock structure. + * @degrees: The clock phase shift between 0 - 359. + * * Set the SD Input Clock Tap Delays for Input path * - * @hw: Pointer to the hardware clock structure. - * @degrees The clock phase shift between 0 - 359. * Return: 0 on success and error value on error */ static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees) - { struct sdhci_arasan_clk_data *clk_data = container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); @@ -712,10 +720,11 @@ static const struct clk_ops zynqmp_sampleclk_ops = { /** * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays * + * @hw: Pointer to the hardware clock structure. + * @degrees: The clock phase shift between 0 - 359. + * * Set the SD Output Clock Tap Delays for Output path * - * @hw: Pointer to the hardware clock structure. - * @degrees The clock phase shift between 0 - 359. * Return: 0 on success and error value on error */ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) @@ -783,10 +792,11 @@ static const struct clk_ops versal_sdcardclk_ops = { /** * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays * + * @hw: Pointer to the hardware clock structure. + * @degrees: The clock phase shift between 0 - 359. + * * Set the SD Input Clock Tap Delays for Input path * - * @hw: Pointer to the hardware clock structure. - * @degrees The clock phase shift between 0 - 359. * Return: 0 on success and error value on error */ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) @@ -902,6 +912,9 @@ static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode) /** * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier * + * @host: The sdhci_host + * @value: The value to write + * * The corecfg_clockmultiplier is supposed to contain clock multiplier * value of programmable clock generator. * @@ -913,8 +926,6 @@ static int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode) * - The value of corecfg_clockmultiplier should sync with that of corresponding * value reading from sdhci_capability_register. So this function is called * once at probe time and never called again. - * - * @host: The sdhci_host */ static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host, u32 value) @@ -941,6 +952,8 @@ static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host, /** * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq * + * @host: The sdhci_host + * * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin. This * function can be used to make that happen. * @@ -952,8 +965,6 @@ static void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host, * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider * to achieve lower clock rates. That means that this function is called once * at probe time and never called again. - * - * @host: The sdhci_host */ static void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host) { @@ -1017,10 +1028,10 @@ static void arasan_dt_read_clk_phase(struct device *dev, /** * arasan_dt_parse_clk_phases - Read Clock Delay values from DT * - * Called at initialization to parse the values of Clock Delays. - * * @dev: Pointer to our struct device. * @clk_data: Pointer to the Clock Data structure + * + * Called at initialization to parse the values of Clock Delays. */ static void arasan_dt_parse_clk_phases(struct device *dev, struct sdhci_arasan_clk_data *clk_data) @@ -1191,14 +1202,15 @@ MODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); /** * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use * + * @sdhci_arasan: Our private data structure. + * @clk_xin: Pointer to the functional clock + * @dev: Pointer to our struct device. + * * Some PHY devices need to know what the actual card clock is. In order for * them to find out, we'll provide a clock through the common clock framework * for them to query. * - * @sdhci_arasan: Our private data structure. - * @clk_xin: Pointer to the functional clock - * @dev: Pointer to our struct device. - * Returns 0 on success and error value on error + * Return: 0 on success and error value on error */ static int sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, @@ -1240,14 +1252,15 @@ sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, /** * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use * + * @sdhci_arasan: Our private data structure. + * @clk_xin: Pointer to the functional clock + * @dev: Pointer to our struct device. + * * Some PHY devices need to know what the actual card clock is. In order for * them to find out, we'll provide a clock through the common clock framework * for them to query. * - * @sdhci_arasan: Our private data structure. - * @clk_xin: Pointer to the functional clock - * @dev: Pointer to our struct device. - * Returns 0 on success and error value on error + * Return: 0 on success and error value on error */ static int sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, @@ -1289,10 +1302,10 @@ sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, /** * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk() * + * @dev: Pointer to our struct device. + * * Should be called any time we're exiting and sdhci_arasan_register_sdclk() * returned success. - * - * @dev: Pointer to our struct device. */ static void sdhci_arasan_unregister_sdclk(struct device *dev) { @@ -1307,6 +1320,10 @@ static void sdhci_arasan_unregister_sdclk(struct device *dev) /** * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use * + * @sdhci_arasan: Our private data structure. + * @clk_xin: Pointer to the functional clock + * @dev: Pointer to our struct device. + * * Some PHY devices need to know what the actual card clock is. In order for * them to find out, we'll provide a clock through the common clock framework * for them to query. @@ -1319,10 +1336,7 @@ static void sdhci_arasan_unregister_sdclk(struct device *dev) * to create nice clean device tree bindings and later (if needed) we can try * re-architecting SDHCI if we see some benefit to it. * - * @sdhci_arasan: Our private data structure. - * @clk_xin: Pointer to the functional clock - * @dev: Pointer to our struct device. - * Returns 0 on success and error value on error + * Return: 0 on success and error value on error */ static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, struct clk *clk_xin, From 2941e4ca2057d6ebba1d93ff1930c6e4c18b63fb Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 8 Apr 2020 16:21:04 +0900 Subject: [PATCH 012/127] mmc: sdhci: move SDHCI_CAPABILITIES_1 to a more suitable place In the SDHCI specification, the Capabilities Register (Offset 0x40h) is the 64-bit width register, but in Linux, it is represented as two registers, SDHCI_CAPABILITIES and SDHCI_CAPABILITIES_1 so that drivers can use 32-bit register accessors. The upper 32-bit field is associated with SDHCI_CAPABILITIES_1. Move the definition of SDHCI_CAPABILITIES_1 to the correct place. Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20200408072105.422-1-yamada.masahiro@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 79dffbb731d3..b786b68e0302 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -220,6 +220,7 @@ #define SDHCI_CAN_64BIT_V4 0x08000000 #define SDHCI_CAN_64BIT 0x10000000 +#define SDHCI_CAPABILITIES_1 0x44 #define SDHCI_SUPPORT_SDR50 0x00000001 #define SDHCI_SUPPORT_SDR104 0x00000002 #define SDHCI_SUPPORT_DDR50 0x00000004 @@ -236,8 +237,6 @@ #define SDHCI_CAN_DO_ADMA3 0x08000000 #define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ -#define SDHCI_CAPABILITIES_1 0x44 - #define SDHCI_MAX_CURRENT 0x48 #define SDHCI_MAX_CURRENT_LIMIT 0xFF #define SDHCI_MAX_CURRENT_330_MASK 0x0000FF From a8e809ecaeb49fd53bbbed05a8257d35b9858c31 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 8 Apr 2020 16:21:05 +0900 Subject: [PATCH 013/127] mmc: sdhci: use FIELD_GET/PREP for capabilities bit masks Use FIELD_GET and FIELD_PREP to get access to the register fields. Delete the shift macros and use GENMASK() for the touched macros. Note that, this has the side-effect of changing the constants to 64-bit on 64-bit platforms. Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20200408072105.422-2-yamada.masahiro@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 4 +++- drivers/mmc/host/sdhci-of-at91.c | 5 +++-- drivers/mmc/host/sdhci-pci-core.c | 8 ++------ drivers/mmc/host/sdhci.c | 19 +++++++------------ drivers/mmc/host/sdhci.h | 17 ++++++----------- 5 files changed, 21 insertions(+), 32 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 5ec8e4bf1ac7..38cd83118082 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -8,6 +8,7 @@ * Author: Wolfram Sang */ +#include #include #include #include @@ -399,7 +400,8 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING - | (SDHCI_TUNING_MODE_3 << SDHCI_RETUNING_MODE_SHIFT); + | FIELD_PREP(SDHCI_RETUNING_MODE_MASK, + SDHCI_TUNING_MODE_3); if (imx_data->socdata->flags & ESDHC_FLAG_HS400) val |= SDHCI_SUPPORT_HS400; diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index c79bff5e2280..25f4e0f4f53b 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -6,6 +6,7 @@ * 2015 Ludovic Desroches */ +#include #include #include #include @@ -179,9 +180,9 @@ static int sdhci_at91_set_clks_presets(struct device *dev) clk_mul = gck_rate / clk_base_rate - 1; caps0 &= ~SDHCI_CLOCK_V3_BASE_MASK; - caps0 |= (clk_base << SDHCI_CLOCK_BASE_SHIFT) & SDHCI_CLOCK_V3_BASE_MASK; + caps0 |= FIELD_PREP(SDHCI_CLOCK_V3_BASE_MASK, clk_base); caps1 &= ~SDHCI_CLOCK_MUL_MASK; - caps1 |= (clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK; + caps1 |= FIELD_PREP(SDHCI_CLOCK_MUL_MASK, clk_mul); /* Set capabilities in r/w mode. */ writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR); writel(caps0, host->ioaddr + SDHCI_CAPABILITIES); diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 2527244c2ae1..af736afb4b91 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -249,12 +249,8 @@ static int ricoh_probe(struct sdhci_pci_chip *chip) static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot) { slot->host->caps = - ((0x21 << SDHCI_TIMEOUT_CLK_SHIFT) - & SDHCI_TIMEOUT_CLK_MASK) | - - ((0x21 << SDHCI_CLOCK_BASE_SHIFT) - & SDHCI_CLOCK_BASE_MASK) | - + FIELD_PREP(SDHCI_TIMEOUT_CLK_MASK, 0x21) | + FIELD_PREP(SDHCI_CLOCK_BASE_MASK, 0x21) | SDHCI_TIMEOUT_CLK_UNIT | SDHCI_CAN_VDD_330 | SDHCI_CAN_DO_HISPD | diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3f716466fcfd..344a7e0e33fe 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -4117,11 +4117,9 @@ int sdhci_setup_host(struct sdhci_host *host) } if (host->version >= SDHCI_SPEC_300) - host->max_clk = (host->caps & SDHCI_CLOCK_V3_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; + host->max_clk = FIELD_GET(SDHCI_CLOCK_V3_BASE_MASK, host->caps); else - host->max_clk = (host->caps & SDHCI_CLOCK_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; + host->max_clk = FIELD_GET(SDHCI_CLOCK_BASE_MASK, host->caps); host->max_clk *= 1000000; if (host->max_clk == 0 || host->quirks & @@ -4139,8 +4137,7 @@ int sdhci_setup_host(struct sdhci_host *host) * In case of Host Controller v3.00, find out whether clock * multiplier is supported. */ - host->clk_mul = (host->caps1 & SDHCI_CLOCK_MUL_MASK) >> - SDHCI_CLOCK_MUL_SHIFT; + host->clk_mul = FIELD_GET(SDHCI_CLOCK_MUL_MASK, host->caps1); /* * In case the value in Clock Multiplier is 0, then programmable @@ -4173,8 +4170,7 @@ int sdhci_setup_host(struct sdhci_host *host) mmc->f_max = max_clk; if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { - host->timeout_clk = (host->caps & SDHCI_TIMEOUT_CLK_MASK) >> - SDHCI_TIMEOUT_CLK_SHIFT; + host->timeout_clk = FIELD_GET(SDHCI_TIMEOUT_CLK_MASK, host->caps); if (host->caps & SDHCI_TIMEOUT_CLK_UNIT) host->timeout_clk *= 1000; @@ -4326,8 +4322,8 @@ int sdhci_setup_host(struct sdhci_host *host) mmc->caps |= MMC_CAP_DRIVER_TYPE_D; /* Initial value for re-tuning timer count */ - host->tuning_count = (host->caps1 & SDHCI_RETUNING_TIMER_COUNT_MASK) >> - SDHCI_RETUNING_TIMER_COUNT_SHIFT; + host->tuning_count = FIELD_GET(SDHCI_RETUNING_TIMER_COUNT_MASK, + host->caps1); /* * In case Re-tuning Timer is not disabled, the actual value of @@ -4337,8 +4333,7 @@ int sdhci_setup_host(struct sdhci_host *host) host->tuning_count = 1 << (host->tuning_count - 1); /* Re-tuning mode supported by the Host Controller */ - host->tuning_mode = (host->caps1 & SDHCI_RETUNING_MODE_MASK) >> - SDHCI_RETUNING_MODE_SHIFT; + host->tuning_mode = FIELD_GET(SDHCI_RETUNING_MODE_MASK, host->caps1); ocr_avail = 0; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index b786b68e0302..d7f1441b0fc3 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -200,12 +200,10 @@ #define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 #define SDHCI_CAPABILITIES 0x40 -#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F -#define SDHCI_TIMEOUT_CLK_SHIFT 0 +#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0) #define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 -#define SDHCI_CLOCK_BASE_MASK 0x00003F00 -#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00 -#define SDHCI_CLOCK_BASE_SHIFT 8 +#define SDHCI_CLOCK_BASE_MASK GENMASK(13, 8) +#define SDHCI_CLOCK_V3_BASE_MASK GENMASK(15, 8) #define SDHCI_MAX_BLOCK_MASK 0x00030000 #define SDHCI_MAX_BLOCK_SHIFT 16 #define SDHCI_CAN_DO_8BIT 0x00040000 @@ -227,13 +225,10 @@ #define SDHCI_DRIVER_TYPE_A 0x00000010 #define SDHCI_DRIVER_TYPE_C 0x00000020 #define SDHCI_DRIVER_TYPE_D 0x00000040 -#define SDHCI_RETUNING_TIMER_COUNT_MASK 0x00000F00 -#define SDHCI_RETUNING_TIMER_COUNT_SHIFT 8 +#define SDHCI_RETUNING_TIMER_COUNT_MASK GENMASK(11, 8) #define SDHCI_USE_SDR50_TUNING 0x00002000 -#define SDHCI_RETUNING_MODE_MASK 0x0000C000 -#define SDHCI_RETUNING_MODE_SHIFT 14 -#define SDHCI_CLOCK_MUL_MASK 0x00FF0000 -#define SDHCI_CLOCK_MUL_SHIFT 16 +#define SDHCI_RETUNING_MODE_MASK GENMASK(15, 14) +#define SDHCI_CLOCK_MUL_MASK GENMASK(23, 16) #define SDHCI_CAN_DO_ADMA3 0x08000000 #define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ From 92fa2a567d520ed71bb810a3b24c6b60f8ef329c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 8 Apr 2020 11:46:36 +0200 Subject: [PATCH 014/127] mmc: renesas_sdhi: refactor calculation of best TAP To select the best TAP, we need to find the longest stream of set bits in a bit field. There is now a helper function for bitmaps which iterates over all region of set bits. Using it makes the code much more concise and easier to understand. Double so, because we need to handle two bitmaps in the near future. Remove a superfluous comment while here. Signed-off-by: Wolfram Sang Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20200408094638.10375-2-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 36 +++++++--------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index df826661366f..f5d174d86117 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -427,15 +427,10 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) { struct renesas_sdhi *priv = host_to_priv(host); - unsigned long tap_cnt; /* counter of tuning success */ - unsigned long tap_start;/* start position of tuning success */ - unsigned long tap_end; /* end position of tuning success */ - unsigned long ntap; /* temporary counter of tuning success */ - unsigned long i; + unsigned int tap_start = 0, tap_end = 0, tap_cnt = 0, rs, re, i; + unsigned int taps_size = priv->tap_num * 2; priv->doing_tune = false; - - /* Clear SCC_RVSREQ */ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); /* @@ -443,7 +438,7 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) * result requiring the tap to be good in both runs before * considering it for tuning selection. */ - for (i = 0; i < priv->tap_num * 2; i++) { + for (i = 0; i < taps_size; i++) { int offset = priv->tap_num * (i < priv->tap_num ? 1 : -1); if (!test_bit(i, priv->taps)) @@ -455,29 +450,14 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the * center index as the tap. */ - tap_cnt = 0; - ntap = 0; - tap_start = 0; - tap_end = 0; - for (i = 0; i < priv->tap_num * 2; i++) { - if (test_bit(i, priv->taps)) { - ntap++; - } else { - if (ntap > tap_cnt) { - tap_start = i - ntap; - tap_end = i - 1; - tap_cnt = ntap; - } - ntap = 0; + bitmap_for_each_set_region(priv->taps, rs, re, 0, taps_size) { + if (re - rs > tap_cnt) { + tap_end = re; + tap_start = rs; + tap_cnt = tap_end - tap_start; } } - if (ntap > tap_cnt) { - tap_start = i - ntap; - tap_end = i - 1; - tap_cnt = ntap; - } - if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP) priv->tap_set = (tap_start + tap_end) / 2 % priv->tap_num; else From ec4fc1acf363985882c37278bfe8881c4e0ec121 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 8 Apr 2020 11:46:37 +0200 Subject: [PATCH 015/127] mmc: renesas_sdhi: clarify handling of selecting TAPs The comment and the define about how TAPs are selected were confusing to me because the good TAP was only valid if it was bigger than a *_MAX_* value. Rename the define and adapt the comment to what really happens. Signed-off-by: Wolfram Sang Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20200408094638.10375-3-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index f5d174d86117..0dbee47eafa1 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -422,7 +422,7 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io return 0; } -#define SH_MOBILE_SDHI_MAX_TAP 3 +#define SH_MOBILE_SDHI_MIN_TAP_ROW 3 static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) { @@ -446,9 +446,9 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) } /* - * Find the longest consecutive run of successful probes. If that - * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the - * center index as the tap. + * Find the longest consecutive run of successful probes. If that + * is at least SH_MOBILE_SDHI_MIN_TAP_ROW probes long then use the + * center index as the tap, otherwise bail out. */ bitmap_for_each_set_region(priv->taps, rs, re, 0, taps_size) { if (re - rs > tap_cnt) { @@ -458,7 +458,7 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) } } - if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP) + if (tap_cnt >= SH_MOBILE_SDHI_MIN_TAP_ROW) priv->tap_set = (tap_start + tap_end) / 2 % priv->tap_num; else return -EIO; From 5fb6bf51f6d153c188087c7fef21f6a8cd481951 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 8 Apr 2020 11:46:38 +0200 Subject: [PATCH 016/127] mmc: renesas_sdhi: improve TAP selection if all TAPs are good When tuning HS400, if all TAPS are good, we can utilize the SMPCMP register to select the optimal TAP. For that, we populate a second bitmap with SMPCMP results and query it in case the regular bitmap is full (= all good). Signed-off-by: Masaharu Hayakawa Signed-off-by: Takeshi Saito Signed-off-by: Wolfram Sang Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20200408094638.10375-4-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi.h | 2 ++ drivers/mmc/host/renesas_sdhi_core.c | 26 +++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 2a4c83a5f32e..12d8016672b0 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -61,6 +61,8 @@ struct renesas_sdhi { /* Tuning values: 1 for success, 0 for failure */ DECLARE_BITMAP(taps, BITS_PER_LONG); + /* Sampling data comparison: 1 for match, 0 for mismatch */ + DECLARE_BITMAP(smpcmp, BITS_PER_LONG); unsigned int tap_num; unsigned long tap_set; }; diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 0dbee47eafa1..796b5eb50415 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -428,7 +428,8 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) { struct renesas_sdhi *priv = host_to_priv(host); unsigned int tap_start = 0, tap_end = 0, tap_cnt = 0, rs, re, i; - unsigned int taps_size = priv->tap_num * 2; + unsigned int taps_size = priv->tap_num * 2, min_tap_row; + unsigned long *bitmap; priv->doing_tune = false; sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); @@ -443,6 +444,21 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) if (!test_bit(i, priv->taps)) clear_bit(i + offset, priv->taps); + + if (!test_bit(i, priv->smpcmp)) + clear_bit(i + offset, priv->smpcmp); + } + + /* + * If all TAP are OK, the sampling clock position is selected by + * identifying the change point of data. + */ + if (bitmap_full(priv->taps, taps_size)) { + bitmap = priv->smpcmp; + min_tap_row = 1; + } else { + bitmap = priv->taps; + min_tap_row = SH_MOBILE_SDHI_MIN_TAP_ROW; } /* @@ -450,7 +466,7 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) * is at least SH_MOBILE_SDHI_MIN_TAP_ROW probes long then use the * center index as the tap, otherwise bail out. */ - bitmap_for_each_set_region(priv->taps, rs, re, 0, taps_size) { + bitmap_for_each_set_region(bitmap, rs, re, 0, taps_size) { if (re - rs > tap_cnt) { tap_end = re; tap_start = rs; @@ -458,7 +474,7 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) } } - if (tap_cnt >= SH_MOBILE_SDHI_MIN_TAP_ROW) + if (tap_cnt >= min_tap_row) priv->tap_set = (tap_start + tap_end) / 2 % priv->tap_num; else return -EIO; @@ -491,6 +507,7 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode) priv->doing_tune = true; bitmap_zero(priv->taps, priv->tap_num * 2); + bitmap_zero(priv->smpcmp, priv->tap_num * 2); /* Issue CMD19 twice for each tap */ for (i = 0; i < 2 * priv->tap_num; i++) { @@ -499,6 +516,9 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode) if (mmc_send_tuning(host->mmc, opcode, NULL) == 0) set_bit(i, priv->taps); + + if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) == 0) + set_bit(i, priv->smpcmp); } return renesas_sdhi_select_tuning(host); From bcf89cb8e0467a6183a4a2a70e71d3c09edfb34a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 8 Apr 2020 16:22:52 +0200 Subject: [PATCH 017/127] mmc: renesas_sdhi: simplify summary output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to call platform_get_resource twice when we still have the pointer from before. Also, use '%pa' for a resource_size_t pointer. Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Link: https://lore.kernel.org/r/20200408142252.21958-1-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson Reviewed-by: Geert Uytterhoeven --- drivers/mmc/host/renesas_sdhi_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 796b5eb50415..68432bb0255b 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -933,10 +933,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, goto eirq; } - dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n", - mmc_hostname(host->mmc), (unsigned long) - (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), - host->mmc->f_max / 1000000); + dev_info(&pdev->dev, "%s base at %pa, max clock rate %u MHz\n", + mmc_hostname(host->mmc), &res->start, host->mmc->f_max / 1000000); return ret; From 098c408b040d49158dc6aea52db7493187ac5e09 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 16 Apr 2020 11:24:02 -0700 Subject: [PATCH 018/127] mmc: sdhci-of-arasan: Remove uninitialized ret variables Clang warns: drivers/mmc/host/sdhci-of-arasan.c:784:9: warning: variable 'ret' is uninitialized when used here [-Wuninitialized] return ret; ^~~ drivers/mmc/host/sdhci-of-arasan.c:738:9: note: initialize the variable 'ret' to silence this warning int ret; ^ = 0 drivers/mmc/host/sdhci-of-arasan.c:860:9: warning: variable 'ret' is uninitialized when used here [-Wuninitialized] return ret; ^~~ drivers/mmc/host/sdhci-of-arasan.c:810:9: note: initialize the variable 'ret' to silence this warning int ret; ^ = 0 2 warnings generated. This looks like a copy paste error. Neither function has handling that needs ret so just remove it and return 0 directly. Link: https://github.com/ClangBuiltLinux/linux/issues/996 Reported-by: kernelci.org bot Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Link: https://lore.kernel.org/r/20200416182402.16858-1-natechancellor@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 16e26c217a77..18bf0e76b1eb 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -735,7 +735,6 @@ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) container_of(clk_data, struct sdhci_arasan_data, clk_data); struct sdhci_host *host = sdhci_arasan->host; u8 tap_delay, tap_max = 0; - int ret; /* * This is applicable for SDHCI_SPEC_300 and above @@ -781,7 +780,7 @@ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); } - return ret; + return 0; } static const struct clk_ops versal_sdcardclk_ops = { @@ -807,7 +806,6 @@ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) container_of(clk_data, struct sdhci_arasan_data, clk_data); struct sdhci_host *host = sdhci_arasan->host; u8 tap_delay, tap_max = 0; - int ret; /* * This is applicable for SDHCI_SPEC_300 and above @@ -857,7 +855,7 @@ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); } - return ret; + return 0; } static const struct clk_ops versal_sampleclk_ops = { From 9cbe0fc8cd9c156ff187231dbb38b02ee20fc8c6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 16 Apr 2020 18:36:47 +0200 Subject: [PATCH 019/127] mmc: host: Prepare host drivers for mmc_regulator_set_vqmmc() returning > 0 Patch all drivers which use mmc_regulator_set_vqmmc() and prepare them for the fact that mmc_regulator_set_vqmmc() can return a value > 0, which would happen if the signal voltage switch did NOT happen, because the voltage was already set correctly. Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20200416163649.336967-1-marex@denx.de [Ulf: Re-worked/simplified the code a bit] Signed-off-by: Ulf Hansson --- drivers/mmc/host/dw_mmc-k3.c | 2 +- drivers/mmc/host/dw_mmc.c | 3 +-- drivers/mmc/host/meson-gx-mmc.c | 5 ++++- drivers/mmc/host/mtk-sd.c | 19 ++++++++++--------- drivers/mmc/host/renesas_sdhi_core.c | 2 +- drivers/mmc/host/sdhci-sprd.c | 2 +- drivers/mmc/host/sdhci.c | 6 +++--- drivers/mmc/host/sunxi-mmc.c | 8 ++++++-- 8 files changed, 27 insertions(+), 20 deletions(-) diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index 23b6f65b3785..50977ff18074 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -424,7 +424,7 @@ static int dw_mci_hi3660_switch_voltage(struct mmc_host *mmc, if (!IS_ERR(mmc->supply.vqmmc)) { ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret) { + if (ret < 0) { dev_err(host->dev, "Regulator set error %d\n", ret); return ret; } diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index bc5278ab5707..5d1f8a3ec3a5 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1546,8 +1546,7 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) if (!IS_ERR(mmc->supply.vqmmc)) { ret = mmc_regulator_set_vqmmc(mmc, ios); - - if (ret) { + if (ret < 0) { dev_dbg(&mmc->class_dev, "Regulator set error %d - %s V\n", ret, uhs & v18 ? "1.8" : "3.3"); diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 35400cf2a2e4..7eb38d7482c6 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -1004,6 +1004,8 @@ static int meson_mmc_card_busy(struct mmc_host *mmc) static int meson_mmc_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { + int ret; + /* vqmmc regulator is available */ if (!IS_ERR(mmc->supply.vqmmc)) { /* @@ -1013,7 +1015,8 @@ static int meson_mmc_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) * to 1.8v. Please make sure the regulator framework is aware * of your own regulator constraints */ - return mmc_regulator_set_vqmmc(mmc, ios); + ret = mmc_regulator_set_vqmmc(mmc, ios); + return ret < 0 ? ret : 0; } /* no vqmmc regulator, assume fixed regulator at 3/3.3V */ diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index b221c02cc71f..53819ae9f271 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -1369,7 +1369,7 @@ static void msdc_set_buswidth(struct msdc_host *host, u32 width) static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios) { struct msdc_host *host = mmc_priv(mmc); - int ret = 0; + int ret; if (!IS_ERR(mmc->supply.vqmmc)) { if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_330 && @@ -1379,18 +1379,19 @@ static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios) } ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret) { + if (ret < 0) { dev_dbg(host->dev, "Regulator set error %d (%d)\n", ret, ios->signal_voltage); - } else { - /* Apply different pinctrl settings for different signal voltage */ - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) - pinctrl_select_state(host->pinctrl, host->pins_uhs); - else - pinctrl_select_state(host->pinctrl, host->pins_default); + return ret; } + + /* Apply different pinctrl settings for different signal voltage */ + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) + pinctrl_select_state(host->pinctrl, host->pins_uhs); + else + pinctrl_select_state(host->pinctrl, host->pins_default); } - return ret; + return 0; } static int msdc_card_busy(struct mmc_host *mmc) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 68432bb0255b..1dfe6c32280b 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -237,7 +237,7 @@ static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; ret = mmc_regulator_set_vqmmc(host->mmc, ios); - if (ret) + if (ret < 0) return ret; return pinctrl_select_state(priv->pinctrl, pin_state); diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index 60c3a4c620f9..d10797a8775e 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -434,7 +434,7 @@ static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) if (!IS_ERR(mmc->supply.vqmmc)) { ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret) { + if (ret < 0) { pr_err("%s: Switching signalling voltage failed\n", mmc_hostname(mmc)); return ret; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 344a7e0e33fe..a0cd6c1453b8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2411,7 +2411,7 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, if (!IS_ERR(mmc->supply.vqmmc)) { ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret) { + if (ret < 0) { pr_warn("%s: Switching to 3.3V signalling voltage failed\n", mmc_hostname(mmc)); return -EIO; @@ -2434,7 +2434,7 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return -EINVAL; if (!IS_ERR(mmc->supply.vqmmc)) { ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret) { + if (ret < 0) { pr_warn("%s: Switching to 1.8V signalling voltage failed\n", mmc_hostname(mmc)); return -EIO; @@ -2466,7 +2466,7 @@ int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return -EINVAL; if (!IS_ERR(mmc->supply.vqmmc)) { ret = mmc_regulator_set_vqmmc(mmc, ios); - if (ret) { + if (ret < 0) { pr_warn("%s: Switching to 1.2V signalling voltage failed\n", mmc_hostname(mmc)); return -EIO; diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index f87d7967457f..3bfbd89bd4ab 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -951,9 +951,13 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static int sunxi_mmc_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) { + int ret; + /* vqmmc regulator is available */ - if (!IS_ERR(mmc->supply.vqmmc)) - return mmc_regulator_set_vqmmc(mmc, ios); + if (!IS_ERR(mmc->supply.vqmmc)) { + ret = mmc_regulator_set_vqmmc(mmc, ios); + return ret < 0 ? ret : 0; + } /* no vqmmc regulator, assume fixed regulator at 3/3.3V */ if (mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) From 17a0751e60b123ce1a266155abf72acd936b7ecc Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 16 Apr 2020 18:36:48 +0200 Subject: [PATCH 020/127] mmc: core: Return 1 from mmc_regulator_set_vqmmc() if switch skipped Adjust mmc_regulator_set_vqmmc() to return 1 if the voltage switch was skipped because the regulator voltage was already correct. This allows drivers to detect such condition and possibly skip various voltage switching extras. Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20200416163649.336967-2-marex@denx.de Signed-off-by: Ulf Hansson --- drivers/mmc/core/regulator.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c index b6febbcf8978..96b1d15045d6 100644 --- a/drivers/mmc/core/regulator.c +++ b/drivers/mmc/core/regulator.c @@ -136,6 +136,8 @@ static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator, int min_uV, int target_uV, int max_uV) { + int current_uV; + /* * Check if supported first to avoid errors since we may try several * signal levels during power up and don't want to show errors. @@ -143,6 +145,14 @@ static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator, if (!regulator_is_supported_voltage(regulator, min_uV, max_uV)) return -EINVAL; + /* + * The voltage is already set, no need to switch. + * Return 1 to indicate that no switch happened. + */ + current_uV = regulator_get_voltage(regulator); + if (current_uV == target_uV) + return 1; + return regulator_set_voltage_triplet(regulator, min_uV, target_uV, max_uV); } @@ -198,9 +208,10 @@ int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios) * voltage in two steps and try to stay close to vmmc * with a 0.3V tolerance at first. */ - if (!mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, - min_uV, volt, max_uV)) - return 0; + ret = mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, + min_uV, volt, max_uV); + if (ret >= 0) + return ret; return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc, 2700000, volt, 3600000); From 3e09a81e166c0a5544832459be17561a6b231ac7 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 16 Apr 2020 18:36:49 +0200 Subject: [PATCH 021/127] mmc: mmci: Switch to mmc_regulator_set_vqmmc() Instead of reimplementing the logic in mmc_regulator_set_vqmmc(), use the mmc code function directly. This also allows us to fix a related issue on STM32MP1, when a voltage switch of 1.8V is done for the eMMC, but the current level is already set to 1.8V. More precisely, in this scenario the call to the ->post_sig_volt_switch() hangs, indefinitely waiting for the voltage switch to complete. Fix this problem by checking if mmc_regulator_set_vqmmc() returned 1 and then skip invoking the callback. Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20200416163649.336967-3-marex@denx.de [Ulf: Updated the commit message] Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 647567def612..a69d6a0c2e15 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1861,31 +1861,17 @@ static int mmci_get_cd(struct mmc_host *mmc) static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmci_host *host = mmc_priv(mmc); - int ret = 0; + int ret; - if (!IS_ERR(mmc->supply.vqmmc)) { + ret = mmc_regulator_set_vqmmc(mmc, ios); - switch (ios->signal_voltage) { - case MMC_SIGNAL_VOLTAGE_330: - ret = regulator_set_voltage(mmc->supply.vqmmc, - 2700000, 3600000); - break; - case MMC_SIGNAL_VOLTAGE_180: - ret = regulator_set_voltage(mmc->supply.vqmmc, - 1700000, 1950000); - break; - case MMC_SIGNAL_VOLTAGE_120: - ret = regulator_set_voltage(mmc->supply.vqmmc, - 1100000, 1300000); - break; - } + if (!ret && host->ops && host->ops->post_sig_volt_switch) + ret = host->ops->post_sig_volt_switch(host, ios); + else if (ret) + ret = 0; - if (!ret && host->ops && host->ops->post_sig_volt_switch) - ret = host->ops->post_sig_volt_switch(host, ios); - - if (ret) - dev_warn(mmc_dev(mmc), "Voltage switch failed\n"); - } + if (ret < 0) + dev_warn(mmc_dev(mmc), "Voltage switch failed\n"); return ret; } From 9d624f4f6df5d358b5ab7eb99ef3ae5e2f091f0c Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 10 Apr 2020 14:57:12 +0800 Subject: [PATCH 022/127] mmc: sd: use HIGH_SPEED_BUS_SPEED in mmc_sd_switch_hs() Use the well defined HIGH_SPEED_BUS_SPEED macro in mmc_sd_switch_hs() to make code more readable. Signed-off-by: Jisheng Zhang Link: https://lore.kernel.org/r/20200410145643.630b0731@xhacker.debian Signed-off-by: Ulf Hansson --- drivers/mmc/core/sd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 76c7add367d5..43de3190d718 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -376,11 +376,11 @@ int mmc_sd_switch_hs(struct mmc_card *card) if (!status) return -ENOMEM; - err = mmc_sd_switch(card, 1, 0, 1, status); + err = mmc_sd_switch(card, 1, 0, HIGH_SPEED_BUS_SPEED, status); if (err) goto out; - if ((status[16] & 0xF) != 1) { + if ((status[16] & 0xF) != HIGH_SPEED_BUS_SPEED) { pr_warn("%s: Problem switching card into high-speed mode!\n", mmc_hostname(card->host)); err = 0; From ed6330330276cba39058e8dbdb28ab8d013d926e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 12 Apr 2020 12:03:45 +0300 Subject: [PATCH 023/127] mmc: sdhci: Add helpers for the auto-CMD23 flag Add 2 helper functions to make the use of the auto-CMD23 flag more readable. Signed-off-by: Adrian Hunter Tested-by: Baolin Wang Link: https://lore.kernel.org/r/20200412090349.1607-2-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a0cd6c1453b8..863b23b2c9f8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1350,13 +1350,25 @@ static inline bool sdhci_auto_cmd12(struct sdhci_host *host, !mrq->cap_cmd_during_tfr; } +static inline bool sdhci_auto_cmd23(struct sdhci_host *host, + struct mmc_request *mrq) +{ + return mrq->sbc && (host->flags & SDHCI_AUTO_CMD23); +} + +static inline bool sdhci_manual_cmd23(struct sdhci_host *host, + struct mmc_request *mrq) +{ + return mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23); +} + static inline void sdhci_auto_cmd_select(struct sdhci_host *host, struct mmc_command *cmd, u16 *mode) { bool use_cmd12 = sdhci_auto_cmd12(host, cmd->mrq) && (cmd->opcode != SD_IO_RW_EXTENDED); - bool use_cmd23 = cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23); + bool use_cmd23 = sdhci_auto_cmd23(host, cmd->mrq); u16 ctrl2; /* @@ -1416,7 +1428,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, if (mmc_op_multi(cmd->opcode) || data->blocks > 1) { mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI; sdhci_auto_cmd_select(host, cmd, &mode); - if (cmd->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) + if (sdhci_auto_cmd23(host, cmd->mrq)) sdhci_writel(host, cmd->mrq->sbc->arg, SDHCI_ARGUMENT2); } @@ -2054,7 +2066,7 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) mrq->cmd->error = -ENOMEDIUM; sdhci_finish_mrq(host, mrq); } else { - if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) + if (sdhci_manual_cmd23(host, mrq)) sdhci_send_command(host, mrq->sbc); else sdhci_send_command(host, mrq->cmd); From a374a72baa817388a04825118b7c1ba13064c8c6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 12 Apr 2020 12:03:46 +0300 Subject: [PATCH 024/127] mmc: sdhci: Stop exporting sdhci_send_command() sdhci_send_command() has not been used outside of sdhci.c for many years. Stop exporting it. Signed-off-by: Adrian Hunter Tested-by: Baolin Wang Link: https://lore.kernel.org/r/20200412090349.1607-3-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 5 +++-- drivers/mmc/host/sdhci.h | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 863b23b2c9f8..397dfc4de922 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -52,6 +52,8 @@ static void sdhci_finish_data(struct sdhci_host *); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); +static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); + void sdhci_dumpregs(struct sdhci_host *host) { SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n"); @@ -1558,7 +1560,7 @@ static void sdhci_finish_data(struct sdhci_host *host) } } -void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) +static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) { int flags; u32 mask; @@ -1658,7 +1660,6 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } -EXPORT_SYMBOL_GPL(sdhci_send_command); static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd) { diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index d7f1441b0fc3..1f5a46eaab8f 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -751,7 +751,6 @@ void sdhci_cleanup_host(struct sdhci_host *host); int __sdhci_add_host(struct sdhci_host *host); int sdhci_add_host(struct sdhci_host *host); void sdhci_remove_host(struct sdhci_host *host, int dead); -void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); static inline void sdhci_read_caps(struct sdhci_host *host) { From 98a2642f91a47dcd1215d037c14e0e5de33a247d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 12 Apr 2020 12:03:47 +0300 Subject: [PATCH 025/127] mmc: sdhci: Remove unneeded forward declaration of sdhci_finish_data() sdhci_finish_data() is defined before it is referenced, so forward declaration is not necessary. Signed-off-by: Adrian Hunter Tested-by: Baolin Wang Link: https://lore.kernel.org/r/20200412090349.1607-4-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 397dfc4de922..e77df59ad141 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -48,8 +48,6 @@ static unsigned int debug_quirks = 0; static unsigned int debug_quirks2; -static void sdhci_finish_data(struct sdhci_host *); - static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); From e872f1e22ea5f678ae42812949477387fda6725b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 12 Apr 2020 12:03:48 +0300 Subject: [PATCH 026/127] mmc: sdhci: Tidy sdhci_request() a bit In preparation for further changes, tidy sdhci_request() a bit. Signed-off-by: Adrian Hunter Tested-by: Baolin Wang Link: https://lore.kernel.org/r/20200412090349.1607-5-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index e77df59ad141..896390147453 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1659,6 +1659,17 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); } +static bool sdhci_present_error(struct sdhci_host *host, + struct mmc_command *cmd, bool present) +{ + if (!present || host->flags & SDHCI_DEVICE_DEAD) { + cmd->error = -ENOMEDIUM; + return true; + } + + return false; +} + static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd) { int i, reg; @@ -2048,11 +2059,10 @@ EXPORT_SYMBOL_GPL(sdhci_set_power_and_bus_voltage); void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) { - struct sdhci_host *host; - int present; + struct sdhci_host *host = mmc_priv(mmc); + struct mmc_command *cmd; unsigned long flags; - - host = mmc_priv(mmc); + bool present; /* Firstly check card presence */ present = mmc->ops->get_cd(mmc); @@ -2061,16 +2071,19 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_led_activate(host); - if (!present || host->flags & SDHCI_DEVICE_DEAD) { - mrq->cmd->error = -ENOMEDIUM; - sdhci_finish_mrq(host, mrq); - } else { - if (sdhci_manual_cmd23(host, mrq)) - sdhci_send_command(host, mrq->sbc); - else - sdhci_send_command(host, mrq->cmd); - } + if (sdhci_present_error(host, mrq->cmd, present)) + goto out_finish; + cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd; + + sdhci_send_command(host, cmd); + + spin_unlock_irqrestore(&host->lock, flags); + + return; + +out_finish: + sdhci_finish_mrq(host, mrq); spin_unlock_irqrestore(&host->lock, flags); } EXPORT_SYMBOL_GPL(sdhci_request); From 845c939ee22943786a6eb1d13d03c77b19fcc2c8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 12 Apr 2020 12:03:49 +0300 Subject: [PATCH 027/127] mmc: sdhci: Reduce maximum time under spinlock in sdhci_send_command() Spending time under spinlock increases IRQ latencies and also response times because preemption is disabled. sdhci_send_command() waits up to 10 ms under spinlock for inhibit bits to clear. In general inhibit bits will not be set, but there may be corner cases, especially in the face of errors, where waiting helps. There might also be dysfunctional hardware that needs the waiting. So retain the legacy behaviour but do not wait for inhibit bits while under spinlock. Instead adjust the logic to enable waiting while not under spinlock. That is mostly straight forward, but in the interrupt handler it requires deferring an "inhibited" command to the IRQ thread where sleeping is allowed. Signed-off-by: Adrian Hunter Tested-by: Baolin Wang Link: https://lore.kernel.org/r/20200412090349.1607-6-adrian.hunter@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 126 ++++++++++++++++++++++++++++++--------- drivers/mmc/host/sdhci.h | 1 + 2 files changed, 99 insertions(+), 28 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 896390147453..153c5fda0645 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -50,7 +50,7 @@ static unsigned int debug_quirks2; static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); -static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); +static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); void sdhci_dumpregs(struct sdhci_host *host) { @@ -1478,6 +1478,9 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) if (host->data_cmd && host->data_cmd->mrq == mrq) host->data_cmd = NULL; + if (host->deferred_cmd && host->deferred_cmd->mrq == mrq) + host->deferred_cmd = NULL; + if (host->data && host->data->mrq == mrq) host->data = NULL; @@ -1499,7 +1502,7 @@ static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) queue_work(host->complete_wq, &host->complete_work); } -static void sdhci_finish_data(struct sdhci_host *host) +static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout) { struct mmc_command *data_cmd = host->data_cmd; struct mmc_data *data = host->data; @@ -1551,14 +1554,31 @@ static void sdhci_finish_data(struct sdhci_host *host) } else { /* Avoid triggering warning in sdhci_send_command() */ host->cmd = NULL; - sdhci_send_command(host, data->stop); + if (!sdhci_send_command(host, data->stop)) { + if (sw_data_timeout) { + /* + * This is anyway a sw data timeout, so + * give up now. + */ + data->stop->error = -EIO; + __sdhci_finish_mrq(host, data->mrq); + } else { + WARN_ON(host->deferred_cmd); + host->deferred_cmd = data->stop; + } + } } } else { __sdhci_finish_mrq(host, data->mrq); } } -static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) +static void sdhci_finish_data(struct sdhci_host *host) +{ + __sdhci_finish_data(host, false); +} + +static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) { int flags; u32 mask; @@ -1573,9 +1593,6 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) cmd->opcode == MMC_STOP_TRANSMISSION) cmd->flags |= MMC_RSP_BUSY; - /* Wait max 10 ms */ - timeout = 10; - mask = SDHCI_CMD_INHIBIT; if (sdhci_data_line_cmd(cmd)) mask |= SDHCI_DATA_INHIBIT; @@ -1585,18 +1602,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if (cmd->mrq->data && (cmd == cmd->mrq->data->stop)) mask &= ~SDHCI_DATA_INHIBIT; - while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { - if (timeout == 0) { - pr_err("%s: Controller never released inhibit bit(s).\n", - mmc_hostname(host->mmc)); - sdhci_dumpregs(host); - cmd->error = -EIO; - sdhci_finish_mrq(host, cmd->mrq); - return; - } - timeout--; - mdelay(1); - } + if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) + return false; host->cmd = cmd; host->data_timeout = 0; @@ -1618,11 +1625,13 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) sdhci_set_transfer_mode(host, cmd); if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { - pr_err("%s: Unsupported response type!\n", - mmc_hostname(host->mmc)); - cmd->error = -EINVAL; - sdhci_finish_mrq(host, cmd->mrq); - return; + WARN_ONCE(1, "Unsupported response type!\n"); + /* + * This does not happen in practice because 136-bit response + * commands never have busy waiting, so rather than complicate + * the error path, just remove busy waiting and continue. + */ + cmd->flags &= ~MMC_RSP_BUSY; } if (!(cmd->flags & MMC_RSP_PRESENT)) @@ -1657,6 +1666,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) sdhci_external_dma_pre_transfer(host, cmd); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); + + return true; } static bool sdhci_present_error(struct sdhci_host *host, @@ -1670,6 +1681,47 @@ static bool sdhci_present_error(struct sdhci_host *host, return false; } +static bool sdhci_send_command_retry(struct sdhci_host *host, + struct mmc_command *cmd, + unsigned long flags) + __releases(host->lock) + __acquires(host->lock) +{ + struct mmc_command *deferred_cmd = host->deferred_cmd; + int timeout = 10; /* Approx. 10 ms */ + bool present; + + while (!sdhci_send_command(host, cmd)) { + if (!timeout--) { + pr_err("%s: Controller never released inhibit bit(s).\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + cmd->error = -EIO; + return false; + } + + spin_unlock_irqrestore(&host->lock, flags); + + usleep_range(1000, 1250); + + present = host->mmc->ops->get_cd(host->mmc); + + spin_lock_irqsave(&host->lock, flags); + + /* A deferred command might disappear, handle that */ + if (cmd == deferred_cmd && cmd != host->deferred_cmd) + return true; + + if (sdhci_present_error(host, cmd, present)) + return false; + } + + if (cmd == host->deferred_cmd) + host->deferred_cmd = NULL; + + return true; +} + static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd) { int i, reg; @@ -1729,7 +1781,10 @@ static void sdhci_finish_command(struct sdhci_host *host) /* Finished CMD23, now send actual command. */ if (cmd == cmd->mrq->sbc) { - sdhci_send_command(host, cmd->mrq->cmd); + if (!sdhci_send_command(host, cmd->mrq->cmd)) { + WARN_ON(host->deferred_cmd); + host->deferred_cmd = cmd->mrq->cmd; + } } else { /* Processed actual command. */ @@ -2076,7 +2131,8 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd; - sdhci_send_command(host, cmd); + if (!sdhci_send_command_retry(host, cmd, flags)) + goto out_finish; spin_unlock_irqrestore(&host->lock, flags); @@ -2624,7 +2680,11 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode) */ sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE); - sdhci_send_command(host, &cmd); + if (!sdhci_send_command_retry(host, &cmd, flags)) { + spin_unlock_irqrestore(&host->lock, flags); + host->tuning_done = 0; + return; + } host->cmd = NULL; @@ -3042,7 +3102,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) if (host->data) { host->data->error = -ETIMEDOUT; - sdhci_finish_data(host); + __sdhci_finish_data(host, true); queue_work(host->complete_wq, &host->complete_work); } else if (host->data_cmd) { host->data_cmd->error = -ETIMEDOUT; @@ -3414,6 +3474,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) } } out: + if (host->deferred_cmd) + result = IRQ_WAKE_THREAD; + spin_unlock(&host->lock); /* Process mrqs ready for immediate completion */ @@ -3439,6 +3502,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) { struct sdhci_host *host = dev_id; + struct mmc_command *cmd; unsigned long flags; u32 isr; @@ -3446,8 +3510,14 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) ; spin_lock_irqsave(&host->lock, flags); + isr = host->thread_isr; host->thread_isr = 0; + + cmd = host->deferred_cmd; + if (cmd && !sdhci_send_command_retry(host, cmd, flags)) + sdhci_finish_mrq(host, cmd->mrq); + spin_unlock_irqrestore(&host->lock, flags); if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 1f5a46eaab8f..8483419a937e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -534,6 +534,7 @@ struct sdhci_host { struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */ struct mmc_command *cmd; /* Current command */ struct mmc_command *data_cmd; /* Current data command */ + struct mmc_command *deferred_cmd; /* Deferred command */ struct mmc_data *data; /* Current data request */ unsigned int data_early:1; /* Data finished before cmd */ From 6db96e5810e0a6a345b7d78549de7676ae5b2662 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 13 Apr 2020 10:46:03 +0800 Subject: [PATCH 028/127] mmc: host: Introduce the request_atomic() for the host The SD host controller can process one request in the atomic context if the card is nonremovable, which means we can submit next request in the irq hard handler when using the MMC host software queue to reduce the latency. Thus this patch adds a new API request_atomic() for the host controller, as well as adding support for host software queue to submit a request by the new request_atomic() API. Moreover there is an unusual case that the card is busy when trying to send a command, and we can not polling the card status in interrupt context by using request_atomic() to dispatch requests. Thus we should queue a work to try again in the non-atomic context in case the host releases the busy signal later. Suggested-by: Adrian Hunter Acked-by: Adrian Hunter Signed-off-by: Baolin Wang Link: https://lore.kernel.org/r/a344e27e506cb2329073cbd5cf65e15cc3cbeba9.1586744073.git.baolin.wang7@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmc_hsq.c | 29 ++++++++++++++++++++++++++++- drivers/mmc/host/mmc_hsq.h | 1 + include/linux/mmc/host.h | 3 +++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c index b90b2c97b6cf..a5e05ed0fda3 100644 --- a/drivers/mmc/host/mmc_hsq.c +++ b/drivers/mmc/host/mmc_hsq.c @@ -16,11 +16,20 @@ #define HSQ_NUM_SLOTS 64 #define HSQ_INVALID_TAG HSQ_NUM_SLOTS +static void mmc_hsq_retry_handler(struct work_struct *work) +{ + struct mmc_hsq *hsq = container_of(work, struct mmc_hsq, retry_work); + struct mmc_host *mmc = hsq->mmc; + + mmc->ops->request(mmc, hsq->mrq); +} + static void mmc_hsq_pump_requests(struct mmc_hsq *hsq) { struct mmc_host *mmc = hsq->mmc; struct hsq_slot *slot; unsigned long flags; + int ret = 0; spin_lock_irqsave(&hsq->lock, flags); @@ -42,7 +51,24 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq) spin_unlock_irqrestore(&hsq->lock, flags); - mmc->ops->request(mmc, hsq->mrq); + if (mmc->ops->request_atomic) + ret = mmc->ops->request_atomic(mmc, hsq->mrq); + else + mmc->ops->request(mmc, hsq->mrq); + + /* + * If returning BUSY from request_atomic(), which means the card + * may be busy now, and we should change to non-atomic context to + * try again for this unusual case, to avoid time-consuming operations + * in the atomic context. + * + * Note: we just give a warning for other error cases, since the host + * driver will handle them. + */ + if (ret == -EBUSY) + schedule_work(&hsq->retry_work); + else + WARN_ON_ONCE(ret); } static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains) @@ -325,6 +351,7 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc) hsq->mmc->cqe_private = hsq; mmc->cqe_ops = &mmc_hsq_ops; + INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler); spin_lock_init(&hsq->lock); init_waitqueue_head(&hsq->wait_queue); diff --git a/drivers/mmc/host/mmc_hsq.h b/drivers/mmc/host/mmc_hsq.h index 18b9cf55925f..ffdd9cd172c3 100644 --- a/drivers/mmc/host/mmc_hsq.h +++ b/drivers/mmc/host/mmc_hsq.h @@ -12,6 +12,7 @@ struct mmc_hsq { wait_queue_head_t wait_queue; struct hsq_slot *slot; spinlock_t lock; + struct work_struct retry_work; int next_tag; int num_slots; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index c318fb5b6a94..d4a50e5dc111 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -92,6 +92,9 @@ struct mmc_host_ops { int err); void (*pre_req)(struct mmc_host *host, struct mmc_request *req); void (*request)(struct mmc_host *host, struct mmc_request *req); + /* Submit one request to host in atomic context. */ + int (*request_atomic)(struct mmc_host *host, + struct mmc_request *req); /* * Avoid calling the next three functions too often or in a "fast From 48ef8a2a1e5e6a2a189009e880e341ddb452971d Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 13 Apr 2020 10:46:04 +0800 Subject: [PATCH 029/127] mmc: host: sdhci: Implement the request_atomic() API Implement the request_atomic() ops for the sdhci driver to process one request in the atomic context if the card is nonremovable. Moreover, we should return BUSY flag if controller has not released the inhibit bits to allow HSQ trying to send request again in non-atomic context. Suggested-by: Adrian Hunter Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/9ed34afa9fb42e0c234065cac5401d7826942b55.1586744073.git.baolin.wang7@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 34 ++++++++++++++++++++++++++++++++++ drivers/mmc/host/sdhci.h | 1 + 2 files changed, 35 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 153c5fda0645..6cc72177f853 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2144,6 +2144,40 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) } EXPORT_SYMBOL_GPL(sdhci_request); +int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct mmc_command *cmd; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&host->lock, flags); + + if (sdhci_present_error(host, mrq->cmd, true)) { + sdhci_finish_mrq(host, mrq); + goto out_finish; + } + + cmd = sdhci_manual_cmd23(host, mrq) ? mrq->sbc : mrq->cmd; + + /* + * The HSQ may send a command in interrupt context without polling + * the busy signaling, which means we should return BUSY if controller + * has not released inhibit bits to allow HSQ trying to send request + * again in non-atomic context. So we should not finish this request + * here. + */ + if (!sdhci_send_command(host, cmd)) + ret = -EBUSY; + else + sdhci_led_activate(host); + +out_finish: + spin_unlock_irqrestore(&host->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_request_atomic); + void sdhci_set_bus_width(struct sdhci_host *host, int width) { u8 ctrl; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 8483419a937e..8d2a096fdfb1 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -770,6 +770,7 @@ void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, unsigned short vdd); void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq); +int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq); void sdhci_set_bus_width(struct sdhci_host *host, int width); void sdhci_reset(struct sdhci_host *host, u8 mask); void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); From 61ab64e2f54f4c607428667f83f411cb659843a3 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Mon, 13 Apr 2020 10:46:05 +0800 Subject: [PATCH 030/127] mmc: host: sdhci-sprd: Implement the request_atomic() API Implement the request_atomic() API for nonremovable cards, that means we can submit next request in the irq hard handler context to reduce latency. Moreover factor out the AUTO CMD23 checking into a separate function to reduce duplicate code. Signed-off-by: Baolin Wang Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/60142fe6c6c1dbba2696e775564ae2166786f0bc.1586744073.git.baolin.wang7@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sprd.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index d10797a8775e..a910cb461ed7 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -406,7 +406,8 @@ static struct sdhci_ops sdhci_sprd_ops = { .request_done = sdhci_sprd_request_done, }; -static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq) +static void sdhci_sprd_check_auto_cmd23(struct mmc_host *mmc, + struct mmc_request *mrq) { struct sdhci_host *host = mmc_priv(mmc); struct sdhci_sprd_host *sprd_host = TO_SPRD_HOST(host); @@ -422,10 +423,23 @@ static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq) mrq->sbc && (mrq->sbc->arg & SDHCI_SPRD_ARG2_STUFF) && (host->flags & SDHCI_AUTO_CMD23)) host->flags &= ~SDHCI_AUTO_CMD23; +} + +static void sdhci_sprd_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + sdhci_sprd_check_auto_cmd23(mmc, mrq); sdhci_request(mmc, mrq); } +static int sdhci_sprd_request_atomic(struct mmc_host *mmc, + struct mmc_request *mrq) +{ + sdhci_sprd_check_auto_cmd23(mmc, mrq); + + return sdhci_request_atomic(mmc, mrq); +} + static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { struct sdhci_host *host = mmc_priv(mmc); @@ -562,6 +576,11 @@ static int sdhci_sprd_probe(struct platform_device *pdev) if (ret) goto pltfm_free; + if (!mmc_card_is_removable(host->mmc)) + host->mmc_host_ops.request_atomic = sdhci_sprd_request_atomic; + else + host->always_defer_done = true; + sprd_host = TO_SPRD_HOST(host); sdhci_sprd_phy_param_parse(sprd_host, pdev->dev.of_node); @@ -655,8 +674,6 @@ static int sdhci_sprd_probe(struct platform_device *pdev) if (ret) goto err_cleanup_host; - host->always_defer_done = true; - ret = __sdhci_add_host(host); if (ret) goto err_cleanup_host; From 49769d4d350ddf3a25eb722019964b5e16b3efdc Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Wed, 15 Apr 2020 17:00:55 +0800 Subject: [PATCH 031/127] mmc: sdhci: add spin lock for sdhci_set_default_irqs in sdhci_init When use one SDIO wifi which enable the runtime PM feature on i.MX6SX, we meet system hang. This hang happened during the usdhc runtime resume, in sdhci_init(), when call the sdhci_set_default_irqs. One interrupt (SDHCI_INT_CARD_INT) triggered just after the host->ier update and before the write of register SDHCI_SIGNAL_ENABLE. So in sdhci_irq, it will skip the call of sdio_signal_irq() because current host->ier do not set the SDHCI_INT_CARD_INT. So this SDIO wifi interrupt always keep triggered, let the system stuck in irq handle, can't response any other thread. This patch add spin lock for the sdhci_set_default_irqs to fix this issue. Signed-off-by: Haibo Chen Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1586941255-9237-1-git-send-email-haibo.chen@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6cc72177f853..1bb6b6796318 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -317,6 +317,7 @@ static void sdhci_config_dma(struct sdhci_host *host) static void sdhci_init(struct sdhci_host *host, int soft) { struct mmc_host *mmc = host->mmc; + unsigned long flags; if (soft) sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); @@ -326,7 +327,9 @@ static void sdhci_init(struct sdhci_host *host, int soft) if (host->v4_mode) sdhci_do_enable_v4_mode(host); + spin_lock_irqsave(&host->lock, flags); sdhci_set_default_irqs(host); + spin_unlock_irqrestore(&host->lock, flags); host->cqe_on = false; From d863cb03fb2aac07f017b2a1d923cdbc35021280 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Mon, 20 Apr 2020 11:50:24 +0530 Subject: [PATCH 032/127] mmc: sdhci-msm: Set SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 quirk sdhci-msm can support auto cmd12. So enable SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 quirk. Signed-off-by: Veerabhadrarao Badiganti Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1587363626-20413-3-git-send-email-vbadigan@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index a8bcb3f16aa4..11139d7d394a 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1882,7 +1882,9 @@ static const struct sdhci_ops sdhci_msm_ops = { static const struct sdhci_pltfm_data sdhci_msm_pdata = { .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | SDHCI_QUIRK_SINGLE_POWER_WRITE | - SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .ops = &sdhci_msm_ops, }; From 946932d91da14cfe2a0522c9bc9317c2db60a280 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Mon, 20 Apr 2020 11:50:25 +0530 Subject: [PATCH 033/127] mmc: sdhci-msm: Enable ADMA length mismatch error interrupt ADMA_ERR_SIZE_EN bit of VENDOR_SPECIFIC_FUNC register controls ADMA length mismatch error interrupt. Enable it by default. And update all bit shift defines with BIT macro. Signed-off-by: Veerabhadrarao Badiganti Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1587363626-20413-4-git-send-email-vbadigan@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 11139d7d394a..c2ae599c7133 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -56,19 +56,19 @@ #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) -#define CORE_VENDOR_SPEC_POR_VAL 0xa1c +#define CORE_VENDOR_SPEC_POR_VAL 0xa9c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) -#define CORE_IO_PAD_PWR_SWITCH_EN (1 << 15) -#define CORE_IO_PAD_PWR_SWITCH (1 << 16) +#define CORE_IO_PAD_PWR_SWITCH_EN BIT(15) +#define CORE_IO_PAD_PWR_SWITCH BIT(16) #define CORE_HC_SELECT_IN_EN BIT(18) #define CORE_HC_SELECT_IN_HS400 (6 << 19) #define CORE_HC_SELECT_IN_MASK (7 << 19) -#define CORE_3_0V_SUPPORT (1 << 25) -#define CORE_1_8V_SUPPORT (1 << 26) +#define CORE_3_0V_SUPPORT BIT(25) +#define CORE_1_8V_SUPPORT BIT(26) #define CORE_VOLT_SUPPORT (CORE_3_0V_SUPPORT | CORE_1_8V_SUPPORT) #define CORE_CSR_CDC_CTLR_CFG0 0x130 From 740e6499324dcf71bd4e6d4242ae008135ab8397 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:13:55 +0200 Subject: [PATCH 034/127] mmc: atmel-mci: Keep timer enabled when queuing a next request When atmci_request_end() is about to finish a request for one slot, there is a possibility that there is new request queued for another slot. If this turns out to be the case, the new request is started and the timer is re-programmed for it. Although, a few lines below in atmci_request_end(), this timer becomes deleted, likely corresponding to the other recently completed request. This looks wrong, so let's fix it. Cc: Ludovic Desroches Cc: Nicolas Ferre Signed-off-by: Ulf Hansson Acked-by: Ludovic Desroches Link: https://lore.kernel.org/r/20200414161413.3036-2-ulf.hansson@linaro.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index aeaaa5314924..0472df8391b5 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1557,6 +1557,8 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) WARN_ON(host->cmd || host->data); + del_timer(&host->timer); + /* * Update the MMC clock rate if necessary. This may be * necessary if set_ios() is called when a different slot is @@ -1583,8 +1585,6 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) host->state = STATE_IDLE; } - del_timer(&host->timer); - spin_unlock(&host->lock); mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); From ab5d94f73bcbbcd85959b4db948cc3d37255c23c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:13:56 +0200 Subject: [PATCH 035/127] mmc: atmel-mci: Set the timer per command rather than per request Setting the timer on a per request basis, is rather limiting as the timer really depends on what commands that is to be sent as part of the request. Therefore improve the behaviour by programming the timer per command basis instead. Cc: Ludovic Desroches Cc: Nicolas Ferre Signed-off-by: Ulf Hansson Acked-by: Ludovic Desroches Link: https://lore.kernel.org/r/20200414161413.3036-3-ulf.hansson@linaro.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 0472df8391b5..7292970065b6 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -169,6 +169,7 @@ #define atmci_writel(port, reg, value) \ __raw_writel((value), (port)->regs + reg) +#define ATMCI_CMD_TIMEOUT_MS 2000 #define AUTOSUSPEND_DELAY 50 #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) @@ -817,6 +818,9 @@ static void atmci_send_command(struct atmel_mci *host, atmci_writel(host, ATMCI_ARGR, cmd->arg); atmci_writel(host, ATMCI_CMDR, cmd_flags); + + mod_timer(&host->timer, + jiffies + msecs_to_jiffies(ATMCI_CMD_TIMEOUT_MS)); } static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) @@ -1314,8 +1318,6 @@ static void atmci_start_request(struct atmel_mci *host, * prepared yet.) */ atmci_writel(host, ATMCI_IER, iflags); - - mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); } static void atmci_queue_request(struct atmel_mci *host, From ef5053bdf5b64db714f3e8ee8fc9a6e37116365c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:13:57 +0200 Subject: [PATCH 036/127] mmc: atmel-mci: Respect the cmd->busy_timeout from the mmc core Using a fixed 2s timeout for all commands is a bit problematic. For some commands it means waiting longer than needed for the timer to expire, which may not a big issue, but still. For other commands, like for an erase (CMD38) that uses a R1B response, may require longer timeouts than 2s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully. Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core. Cc: Ludovic Desroches Cc: Nicolas Ferre Signed-off-by: Ulf Hansson Acked-by: Ludovic Desroches Link: https://lore.kernel.org/r/20200414161413.3036-4-ulf.hansson@linaro.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 7292970065b6..5cb692687698 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -809,6 +809,9 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, static void atmci_send_command(struct atmel_mci *host, struct mmc_command *cmd, u32 cmd_flags) { + unsigned int timeout_ms = cmd->busy_timeout ? cmd->busy_timeout : + ATMCI_CMD_TIMEOUT_MS; + WARN_ON(host->cmd); host->cmd = cmd; @@ -819,8 +822,7 @@ static void atmci_send_command(struct atmel_mci *host, atmci_writel(host, ATMCI_ARGR, cmd->arg); atmci_writel(host, ATMCI_CMDR, cmd_flags); - mod_timer(&host->timer, - jiffies + msecs_to_jiffies(ATMCI_CMD_TIMEOUT_MS)); + mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout_ms)); } static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) From 4c2e04d728046d693fa1ef60ca38aedd382bc0e3 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:13:59 +0200 Subject: [PATCH 037/127] mmc: usdhi6rol0: Inform the mmc core about the maximum busy timeout Some commands uses R1B responses, which means the card may assert the DAT0 line to signal busy for a period of time, after it has received the command. The mmc core normally specifies the busy period for the command in the cmd->busy_timeout. Ideally the driver should respect it, but that requires quite some update of the code, so let's defer that to someone with the HW at hand. Instead, let's inform the mmc core about the maximum supported busy timeout in ->max_busy_timeout during ->probe(). This value corresponds to the fixed 4s timeout used by usdhi6rol0. In this way, we let the mmc core validate the needed timeout, which may lead to that it converts from a R1B into a R1 response and then use CMD13 to poll for busy completion. In other words, this change enables support for commands with longer busy periods than 4s, like erase (CMD38) for example. Cc: Jesper Nilsson Cc: Lars Persson Signed-off-by: Ulf Hansson Acked-by: Jesper Nilsson Link: https://lore.kernel.org/r/20200414161413.3036-6-ulf.hansson@linaro.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/usdhi6rol0.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 9a0b1e4e405d..369b8dee2e3d 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -136,6 +136,8 @@ #define USDHI6_MIN_DMA 64 +#define USDHI6_REQ_TIMEOUT_MS 4000 + enum usdhi6_wait_for { USDHI6_WAIT_FOR_REQUEST, USDHI6_WAIT_FOR_CMD, @@ -1763,7 +1765,12 @@ static int usdhi6_probe(struct platform_device *pdev) host = mmc_priv(mmc); host->mmc = mmc; host->wait = USDHI6_WAIT_FOR_REQUEST; - host->timeout = msecs_to_jiffies(4000); + host->timeout = msecs_to_jiffies(USDHI6_REQ_TIMEOUT_MS); + /* + * We use a fixed timeout of 4s, hence inform the core about it. A + * future improvement should instead respect the cmd->busy_timeout. + */ + mmc->max_busy_timeout = USDHI6_REQ_TIMEOUT_MS; host->pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR(host->pinctrl)) { From a389087ee9f195fcf2f31cd771e9ec5f02c16650 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:13 +0200 Subject: [PATCH 038/127] staging: greybus: sdio: Respect the cmd->busy_timeout from the mmc core Using a fixed 1s timeout for all commands is a bit problematic. For some commands it means waiting longer than needed for the timeout to expire, which may not a big issue, but still. For other commands, like for an erase (CMD38) that uses a R1B response, may require longer timeouts than 1s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully. Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core. Cc: Rui Miguel Silva Cc: Johan Hovold Cc: Alex Elder Cc: Greg Kroah-Hartman Cc: greybus-dev@lists.linaro.org Signed-off-by: Ulf Hansson Acked-by: Rui Miguel Silva Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20200414161413.3036-20-ulf.hansson@linaro.org Signed-off-by: Ulf Hansson --- drivers/staging/greybus/sdio.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/staging/greybus/sdio.c b/drivers/staging/greybus/sdio.c index 68c5718be827..c4b16bb5c1a4 100644 --- a/drivers/staging/greybus/sdio.c +++ b/drivers/staging/greybus/sdio.c @@ -411,6 +411,7 @@ static int gb_sdio_command(struct gb_sdio_host *host, struct mmc_command *cmd) struct gb_sdio_command_request request = {0}; struct gb_sdio_command_response response; struct mmc_data *data = host->mrq->data; + unsigned int timeout_ms; u8 cmd_flags; u8 cmd_type; int i; @@ -469,9 +470,12 @@ static int gb_sdio_command(struct gb_sdio_host *host, struct mmc_command *cmd) request.data_blksz = cpu_to_le16(data->blksz); } - ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_COMMAND, - &request, sizeof(request), &response, - sizeof(response)); + timeout_ms = cmd->busy_timeout ? cmd->busy_timeout : + GB_OPERATION_TIMEOUT_DEFAULT; + + ret = gb_operation_sync_timeout(host->connection, GB_SDIO_TYPE_COMMAND, + &request, sizeof(request), &response, + sizeof(response), timeout_ms); if (ret < 0) goto out; From 0472f8d3c054a0ff58122fc9d2dbf84f197a284f Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 17 Apr 2020 19:34:31 +0530 Subject: [PATCH 039/127] mmc: sdhci-msm: Use OPP API to set clk/perf state On some qualcomm SoCs we need to vote on a performance state of a power domain depending on the clock rates. Hence move to using OPP api to set the clock rate and performance state specified in the OPP table. On platforms without an OPP table, dev_pm_opp_set_rate() is eqvivalent to clk_set_rate() Signed-off-by: Rajendra Nayak Link: https://lore.kernel.org/r/1587132279-27659-10-git-send-email-rnayak@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c2ae599c7133..8a055ddfdaff 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -243,6 +244,8 @@ struct sdhci_msm_host { struct clk_bulk_data bulk_clks[4]; /* core, iface, cal, sleep clocks */ unsigned long clk_rate; struct mmc_host *mmc; + struct opp_table *opp; + bool opp_table; bool use_14lpp_dll_reset; bool tuning_done; bool calibration_done; @@ -332,7 +335,7 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, int rc; clock = msm_get_clock_rate_for_bus_mode(host, clock); - rc = clk_set_rate(core_clk, clock); + rc = dev_pm_opp_set_rate(mmc_dev(host->mmc), clock); if (rc) { pr_err("%s: Failed to set clock at rate %u at timing %d\n", mmc_hostname(host->mmc), clock, @@ -1964,8 +1967,18 @@ static int sdhci_msm_probe(struct platform_device *pdev) } msm_host->bulk_clks[0].clk = clk; + msm_host->opp = dev_pm_opp_set_clkname(&pdev->dev, "core"); + if (IS_ERR(msm_host->opp)) { + ret = PTR_ERR(msm_host->opp); + goto bus_clk_disable; + } + + /* OPP table is optional */ + if (!dev_pm_opp_of_add_table(&pdev->dev)) + msm_host->opp_table = true; + /* Vote for maximum clock rate for maximum performance */ - ret = clk_set_rate(clk, INT_MAX); + ret = dev_pm_opp_set_rate(&pdev->dev, INT_MAX); if (ret) dev_warn(&pdev->dev, "core clock boost failed\n"); @@ -1982,7 +1995,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); if (ret) - goto bus_clk_disable; + goto opp_cleanup; /* * xo clock is needed for FLL feature of cm_dll. @@ -2119,6 +2132,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) clk_disable: clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); +opp_cleanup: + if (msm_host->opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(msm_host->opp); bus_clk_disable: if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); @@ -2137,6 +2154,9 @@ static int sdhci_msm_remove(struct platform_device *pdev) sdhci_remove_host(host, dead); + if (msm_host->opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(msm_host->opp); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); @@ -2155,6 +2175,8 @@ static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + /* Drop the performance vote */ + dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); @@ -2177,9 +2199,11 @@ static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev) * restore the SDR DLL settings when the clock is ungated. */ if (msm_host->restore_dll_config && msm_host->clk_rate) - return sdhci_msm_restore_sdr_dll_config(host); + ret = sdhci_msm_restore_sdr_dll_config(host); - return 0; + dev_pm_opp_set_rate(dev, msm_host->clk_rate); + + return ret; } static const struct dev_pm_ops sdhci_msm_pm_ops = { From 33ba6fec0012e47f4e72bfab922b99327373f210 Mon Sep 17 00:00:00 2001 From: Ludovic Barre Date: Mon, 20 Apr 2020 18:18:31 +0200 Subject: [PATCH 040/127] mmc: mmci_sdmmc: fix power on issue due to pwr_reg initialization This patch fix a power-on issue, and avoid to retry the power sequence. In power off sequence: sdmmc must set pwr_reg in "power-cycle" state (value 0x2), to prevent the card from being supplied through the signal lines (all the lines are driven low). In power on sequence: when the power is stable, sdmmc must set pwr_reg in "power-off" state (value 0x0) to drive all signal to high before to set "power-on". To avoid writing the same value to the power register several times, this register is cached by the pwr_reg variable. At probe pwr_reg is initialized to 0 by kzalloc of mmc_alloc_host. Like pwr_reg value is 0 at probing, the power on sequence fail because the "power-off" state is not writes (value 0x0) and the lines remain drive to low. This patch initializes "pwr_reg" variable with power register value. This it done in sdmmc variant init to not disturb default mmci behavior. Signed-off-by: Ludovic Barre Link: https://lore.kernel.org/r/20200420161831.5043-1-ludovic.barre@st.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci_stm32_sdmmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index d33e62bd6153..14f99d8aa3f0 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -519,6 +519,7 @@ void sdmmc_variant_init(struct mmci_host *host) struct sdmmc_dlyb *dlyb; host->ops = &sdmmc_variant_ops; + host->pwr_reg = readl_relaxed(host->base + MMCIPOWER); base_dlyb = devm_of_iomap(mmc_dev(host->mmc), np, 1, NULL); if (IS_ERR(base_dlyb)) From 74f6bdb864f2235effa3af587c6c90c6eb5f21d3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 20 Apr 2020 19:02:30 +0200 Subject: [PATCH 041/127] mmc: renesas_sdhi: shorten types after refactorization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After TAP refactorization, we can use 'unsigned int' for two more variables because all the calculations work on this type now. Signed-off-by: Wolfram Sang Reviewed-by: Niklas Söderlund Link: https://lore.kernel.org/r/20200420170230.9091-1-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi.h | 2 +- drivers/mmc/host/renesas_sdhi_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 12d8016672b0..86efa9d5cd6d 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -64,7 +64,7 @@ struct renesas_sdhi { /* Sampling data comparison: 1 for match, 0 for mismatch */ DECLARE_BITMAP(smpcmp, BITS_PER_LONG); unsigned int tap_num; - unsigned long tap_set; + unsigned int tap_set; }; #define host_to_priv(host) \ diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 1dfe6c32280b..28b0830c4251 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -527,7 +527,7 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode) static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap) { struct renesas_sdhi *priv = host_to_priv(host); - unsigned long new_tap = priv->tap_set; + unsigned int new_tap = priv->tap_set; u32 val; val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ); From ca2d13ec6ee9c3d7edc6563dc753f891521f791b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 23 Apr 2020 00:34:01 +0900 Subject: [PATCH 042/127] mmc: sdhci-of-at91: make MMC_SDHCI_OF_AT91 depend on HAVE_CLK If sdhci-of-at91.c is compiled without CONFIG_HAVE_CLK, the line caps1 |= FIELD_PREP(SDHCI_CLOCK_MUL_MASK, clk_mul); ... emits "FIELD_PREP: value too large for the field" warning. The compiler seems to decide clk_mul is constant (unsigned int)-1, because clk_get_rate() returns 0 when CONFIG_HAVE_CLK is disabled. Add HAVE_CLK to the depenency since this driver does not work without the clock APIs anyway. Reported-by: Randy Dunlap Suggested-by: Adrian Hunter Signed-off-by: Masahiro Yamada Link: https://lore.kernel.org/r/20200422153401.7913-1-yamada.masahiro@socionext.com Signed-off-by: Ulf Hansson Acked-by: Randy Dunlap # build-tested --- drivers/mmc/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 462b5352fea7..2aee844722d6 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -171,7 +171,7 @@ config MMC_SDHCI_OF_ASPEED config MMC_SDHCI_OF_AT91 tristate "SDHCI OF support for the Atmel SDMMC controller" depends on MMC_SDHCI_PLTFM - depends on OF + depends on OF && HAVE_CLK help This selects the Atmel SDMMC driver From 43170255321f83d8e8a3964f70040c49b3d19df0 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Thu, 23 Apr 2020 17:15:19 +0800 Subject: [PATCH 043/127] mmc: core: Use DEFINE_DEBUGFS_ATTRIBUTE instead of DEFINE_SIMPLE_ATTRIBUTE Fixes coccicheck warning: drivers/mmc/core/debugfs.c:222:0-23: WARNING: mmc_clock_fops should be defined with DEFINE_DEBUGFS_ATTRIBUTE Use DEFINE_DEBUGFS_ATTRIBUTE rather than DEFINE_SIMPLE_ATTRIBUTE for debugfs files Fixes: 703aae3d09a4b ("mmc: add a file to debugfs for changing host clock at runtime") Fixes: a04c50aaa916f ("mmc: core: no need to check return value of debugfs_create functions") Reported-by: Hulk Robot Signed-off-by: Zou Wei Link: https://lore.kernel.org/r/1587633319-19835-1-git-send-email-zou_wei@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 09e0c7659469..9ec84c86c46a 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -219,7 +219,7 @@ static int mmc_clock_opt_set(void *data, u64 val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set, +DEFINE_DEBUGFS_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set, "%llu\n"); void mmc_add_host_debugfs(struct mmc_host *host) @@ -232,8 +232,8 @@ void mmc_add_host_debugfs(struct mmc_host *host) debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops); debugfs_create_x32("caps", S_IRUSR, root, &host->caps); debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2); - debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host, - &mmc_clock_fops); + debugfs_create_file_unsafe("clock", S_IRUSR | S_IWUSR, root, host, + &mmc_clock_fops); #ifdef CONFIG_FAIL_MMC_REQUEST if (fail_request) From 580b946ed030e6c148842e1981a75dbf5720efd5 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Thu, 23 Apr 2020 14:43:19 +0800 Subject: [PATCH 044/127] mmc: sdhci-pci-o2micro: Make some symbols static Fix the following sparse warning: drivers/mmc/host/sdhci-pci-o2micro.c:497:6: warning: symbol 'sdhci_pci_o2_set_clock' was not declared. Should it be static? drivers/mmc/host/sdhci-pci-o2micro.c:512:5: warning: symbol 'sdhci_pci_o2_probe_slot' was not declared. Should it be static? drivers/mmc/host/sdhci-pci-o2micro.c:581:5: warning: symbol 'sdhci_pci_o2_probe' was not declared. Should it be static? drivers/mmc/host/sdhci-pci-o2micro.c:786:5: warning: symbol 'sdhci_pci_o2_resume' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: Zou Wei Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1587624199-96926-1-git-send-email-zou_wei@huawei.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-o2micro.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c index fa8105087d68..e2a846885902 100644 --- a/drivers/mmc/host/sdhci-pci-o2micro.c +++ b/drivers/mmc/host/sdhci-pci-o2micro.c @@ -494,7 +494,7 @@ static void sdhci_o2_enable_clk(struct sdhci_host *host, u16 clk) } } -void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) +static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) { u16 clk; @@ -509,7 +509,7 @@ void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) sdhci_o2_enable_clk(host, clk); } -int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) +static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) { struct sdhci_pci_chip *chip; struct sdhci_host *host; @@ -578,7 +578,7 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) return 0; } -int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) +static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) { int ret; u8 scratch; @@ -783,7 +783,7 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) } #ifdef CONFIG_PM_SLEEP -int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) +static int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) { sdhci_pci_o2_probe(chip); return sdhci_pci_resume_host(chip); From d422f8b9ed4e470214477239066ae8f8f3f7fa6d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:13:58 +0200 Subject: [PATCH 045/127] mmc: jz4740: Inform the mmc core about the maximum busy timeout Some commands uses R1B responses, which means the card may assert the DAT0 line to signal busy for a period of time, after it has received the command. The mmc core normally specifies the busy period for the command in the cmd->busy_timeout. Ideally the driver should respect it, but that requires quite some update of the code, so let's defer that to someone with the HW at hand. Instead, let's inform the mmc core about the maximum supported busy timeout in ->max_busy_timeout during ->probe(). This value corresponds to the fixed 5s timeout used by jz4740. In this way, we let the mmc core validate the needed timeout, which may lead to that it converts from a R1B into a R1 response and then use CMD13 to poll for busy completion. In other words, this change enables support for commands with longer busy periods than 5s, like erase (CMD38) for example. Cc: Paul Cercueil Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-5-ulf.hansson@linaro.org --- drivers/mmc/host/jz4740_mmc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index fbae87d1f017..cba7a6fcd178 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -108,6 +108,7 @@ #define JZ_MMC_LPM_LOW_POWER_MODE_EN BIT(0) #define JZ_MMC_CLK_RATE 24000000 +#define JZ_MMC_REQ_TIMEOUT_MS 5000 enum jz4740_mmc_version { JZ_MMC_JZ4740, @@ -440,7 +441,8 @@ static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host, if (timeout == 0) { set_bit(0, &host->waiting); - mod_timer(&host->timeout_timer, jiffies + 5*HZ); + mod_timer(&host->timeout_timer, + jiffies + msecs_to_jiffies(JZ_MMC_REQ_TIMEOUT_MS)); jz4740_mmc_set_irq_enabled(host, irq, true); return true; } @@ -893,7 +895,8 @@ static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req) host->state = JZ4740_MMC_STATE_READ_RESPONSE; set_bit(0, &host->waiting); - mod_timer(&host->timeout_timer, jiffies + 5*HZ); + mod_timer(&host->timeout_timer, + jiffies + msecs_to_jiffies(JZ_MMC_REQ_TIMEOUT_MS)); jz4740_mmc_send_command(host, req->cmd); } @@ -1023,6 +1026,12 @@ static int jz4740_mmc_probe(struct platform_device* pdev) mmc->f_min = mmc->f_max / 128; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + /* + * We use a fixed timeout of 5s, hence inform the core about it. A + * future improvement should instead respect the cmd->busy_timeout. + */ + mmc->max_busy_timeout = JZ_MMC_REQ_TIMEOUT_MS; + mmc->max_blk_size = (1 << 10) - 1; mmc->max_blk_count = (1 << 15) - 1; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; From f37ac1ae3ca93d0995553ad9604a25eadfe9406d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:01 +0200 Subject: [PATCH 046/127] mmc: owl-mmc: Respect the cmd->busy_timeout from the mmc core For commands that doesn't involve to prepare a data transfer, owl-mmc is using a fixed 30s response timeout. This is a bit problematic. For some commands it means waiting longer than needed for the completion to expire, which may not a big issue, but still. For other commands, like for an erase (CMD38) that uses a R1B response, may require longer timeouts than 30s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully. Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core. Cc: Manivannan Sadhasivam Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-8-ulf.hansson@linaro.org --- drivers/mmc/host/owl-mmc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c index 01ffe51f413d..5e20c099fe03 100644 --- a/drivers/mmc/host/owl-mmc.c +++ b/drivers/mmc/host/owl-mmc.c @@ -92,6 +92,8 @@ #define OWL_SD_STATE_RC16ER BIT(1) #define OWL_SD_STATE_CRC7ER BIT(0) +#define OWL_CMD_TIMEOUT_MS 30000 + struct owl_mmc_host { struct device *dev; struct reset_control *reset; @@ -172,6 +174,7 @@ static void owl_mmc_send_cmd(struct owl_mmc_host *owl_host, struct mmc_command *cmd, struct mmc_data *data) { + unsigned long timeout; u32 mode, state, resp[2]; u32 cmd_rsp_mask = 0; @@ -239,7 +242,10 @@ static void owl_mmc_send_cmd(struct owl_mmc_host *owl_host, if (data) return; - if (!wait_for_completion_timeout(&owl_host->sdc_complete, 30 * HZ)) { + timeout = msecs_to_jiffies(cmd->busy_timeout ? cmd->busy_timeout : + OWL_CMD_TIMEOUT_MS); + + if (!wait_for_completion_timeout(&owl_host->sdc_complete, timeout)) { dev_err(owl_host->dev, "CMD interrupt timeout\n"); cmd->error = -ETIMEDOUT; return; From 710c7ff9a6815ca565b6acb08501ad18ca151429 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:02 +0200 Subject: [PATCH 047/127] mmc: sdricoh_cs: Drop unused defines Cc: Sascha Sommer Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-9-ulf.hansson@linaro.org --- drivers/mmc/host/sdricoh_cs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index a38b8b2a4e5c..1fc4db713ef5 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -57,10 +57,8 @@ static unsigned int switchlocked; #define STATUS_BUSY 0x40000000 /* timeouts */ -#define INIT_TIMEOUT 100 #define CMD_TIMEOUT 100000 #define TRANSFER_TIMEOUT 100000 -#define BUSY_TIMEOUT 32767 /* list of supported pcmcia devices */ static const struct pcmcia_device_id pcmcia_ids[] = { From cfa2c1dc7bb43cf3d00f27ec90022f6fb8f0bf42 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:03 +0200 Subject: [PATCH 048/127] mmc: sdricoh_cs: Use MMC_APP_CMD rather than a hardcoded number Cc: Sascha Sommer Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-10-ulf.hansson@linaro.org --- drivers/mmc/host/sdricoh_cs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 1fc4db713ef5..a41c0660abbf 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -22,6 +22,7 @@ #include #include +#include #define DRIVER_NAME "sdricoh_cs" @@ -261,7 +262,7 @@ static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq) if (host->app_cmd) { opcode |= 64; host->app_cmd = 0; - } else if (opcode == 55) + } else if (opcode == MMC_APP_CMD) host->app_cmd = 1; /* read/write commands seem to require this */ From 4b4c7daec4f92327e321d22347076a7e4d8320b0 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:04 +0200 Subject: [PATCH 049/127] mmc: sdricoh_cs: Move MMC_APP_CMD handling to sdricoh_mmc_cmd() Move MMC_APP_CMD specific handling to be managed by sdricoh_mmc_cmd(), as this makes the code a bit cleaner. Cc: Sascha Sommer Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-11-ulf.hansson@linaro.org --- drivers/mmc/host/sdricoh_cs.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index a41c0660abbf..e7d74db95b57 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -149,16 +149,25 @@ static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted, } -static int sdricoh_mmc_cmd(struct sdricoh_host *host, unsigned char opcode, - unsigned int arg) +static int sdricoh_mmc_cmd(struct sdricoh_host *host, struct mmc_command *cmd) { unsigned int status; int result = 0; unsigned int loop = 0; + unsigned char opcode = cmd->opcode; + /* reset status reg? */ sdricoh_writel(host, R21C_STATUS, 0x18); + + /* MMC_APP_CMDs need some special handling */ + if (host->app_cmd) { + opcode |= 64; + host->app_cmd = 0; + } else if (opcode == MMC_APP_CMD) + host->app_cmd = 1; + /* fill parameters */ - sdricoh_writel(host, R204_CMD_ARG, arg); + sdricoh_writel(host, R204_CMD_ARG, cmd->arg); sdricoh_writel(host, R200_CMD, (0x10000 << 8) | opcode); /* wait for command completion */ if (opcode) { @@ -250,28 +259,20 @@ static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq) struct mmc_command *cmd = mrq->cmd; struct mmc_data *data = cmd->data; struct device *dev = host->dev; - unsigned char opcode = cmd->opcode; int i; dev_dbg(dev, "=============================\n"); - dev_dbg(dev, "sdricoh_request opcode=%i\n", opcode); + dev_dbg(dev, "sdricoh_request opcode=%i\n", cmd->opcode); sdricoh_writel(host, R21C_STATUS, 0x18); - /* MMC_APP_CMDs need some special handling */ - if (host->app_cmd) { - opcode |= 64; - host->app_cmd = 0; - } else if (opcode == MMC_APP_CMD) - host->app_cmd = 1; - /* read/write commands seem to require this */ if (data) { sdricoh_writew(host, R226_BLOCKSIZE, data->blksz); sdricoh_writel(host, R208_DATAIO, 0); } - cmd->error = sdricoh_mmc_cmd(host, opcode, cmd->arg); + cmd->error = sdricoh_mmc_cmd(host, cmd); /* read response buffer */ if (cmd->flags & MMC_RSP_PRESENT) { From 6ccff65a29459fbc251f471ae4e20af425b2f0b1 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:05 +0200 Subject: [PATCH 050/127] mmc: sdricoh_cs: Drop redundant in-parameter to sdricoh_query_status() The in-parameter timeout is always set to TRANSFER_TIMEOUT by the callers of sdricoh_query_status(), hence let's drop it. Cc: Sascha Sommer Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-12-ulf.hansson@linaro.org --- drivers/mmc/host/sdricoh_cs.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index e7d74db95b57..97ef7d71375a 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -123,11 +123,13 @@ static inline unsigned int sdricoh_readb(struct sdricoh_host *host, return value; } -static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted, - unsigned int timeout){ +static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted) +{ unsigned int loop; unsigned int status = 0; + unsigned int timeout = TRANSFER_TIMEOUT; struct device *dev = host->dev; + for (loop = 0; loop < timeout; loop++) { status = sdricoh_readl(host, R21C_STATUS); sdricoh_writel(host, R2E4_STATUS_RESP, status); @@ -215,8 +217,7 @@ static int sdricoh_blockio(struct sdricoh_host *host, int read, u32 data = 0; /* wait until the data is available */ if (read) { - if (sdricoh_query_status(host, STATUS_READY_TO_READ, - TRANSFER_TIMEOUT)) + if (sdricoh_query_status(host, STATUS_READY_TO_READ)) return -ETIMEDOUT; sdricoh_writel(host, R21C_STATUS, 0x18); /* read data */ @@ -232,8 +233,7 @@ static int sdricoh_blockio(struct sdricoh_host *host, int read, } } } else { - if (sdricoh_query_status(host, STATUS_READY_TO_WRITE, - TRANSFER_TIMEOUT)) + if (sdricoh_query_status(host, STATUS_READY_TO_WRITE)) return -ETIMEDOUT; sdricoh_writel(host, R21C_STATUS, 0x18); /* write data */ @@ -323,8 +323,7 @@ static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq) sdricoh_writel(host, R208_DATAIO, 1); - if (sdricoh_query_status(host, STATUS_TRANSFER_FINISHED, - TRANSFER_TIMEOUT)) { + if (sdricoh_query_status(host, STATUS_TRANSFER_FINISHED)) { dev_err(dev, "sdricoh_request: transfer end error\n"); cmd->error = -EINVAL; } From 0b05c9770501e949887abfe1c31c571e946eab64 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:09 +0200 Subject: [PATCH 051/127] mmc: tifm_sd: Inform the mmc core about the maximum busy timeout Some commands uses R1B responses, which means the card may assert the DAT0 line to signal busy for a period of time, after it has received the command. The mmc core normally specifies the busy period for the command in the cmd->busy_timeout. Ideally the driver should respect it, but that requires quite some update of the code, so let's defer that to someone with the HW at hand. Instead, let's inform the mmc core about the maximum supported busy timeout in ->max_busy_timeout during ->probe(). This value corresponds to the fixed 1s timeout used by tifm_sd. In this way, we let the mmc core validate the needed timeout, which may lead to that it converts from a R1B into a R1 response and then use CMD13 to poll for busy completion. In other words, this change enables support for commands with longer busy periods than 1s, like erase (CMD38) for example. Cc: Alex Dubov Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-16-ulf.hansson@linaro.org --- drivers/mmc/host/tifm_sd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 54271b92ee59..5987656e0474 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -73,6 +73,8 @@ module_param(fixed_timeout, bool, 0644); #define TIFM_MMCSD_MAX_BLOCK_SIZE 0x0800UL +#define TIFM_MMCSD_REQ_TIMEOUT_MS 1000 + enum { CMD_READY = 0x0001, FIFO_READY = 0x0002, @@ -959,7 +961,12 @@ static int tifm_sd_probe(struct tifm_dev *sock) host = mmc_priv(mmc); tifm_set_drvdata(sock, mmc); host->dev = sock; - host->timeout_jiffies = msecs_to_jiffies(1000); + host->timeout_jiffies = msecs_to_jiffies(TIFM_MMCSD_REQ_TIMEOUT_MS); + /* + * We use a fixed request timeout of 1s, hence inform the core about it. + * A future improvement should instead respect the cmd->busy_timeout. + */ + mmc->max_busy_timeout = TIFM_MMCSD_REQ_TIMEOUT_MS; tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd, (unsigned long)host); From 966244ccd2919e28f25555a77f204cd1c109cad8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:10 +0200 Subject: [PATCH 052/127] mmc: via-sdmmc: Respect the cmd->busy_timeout from the mmc core Using a fixed 1s timeout for all commands (and data transfers) is a bit problematic. For some commands it means waiting longer than needed for the timer to expire, which may not a big issue, but still. For other commands, like for an erase (CMD38) that uses a R1B response, may require longer timeouts than 1s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully. Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core. Cc: Bruce Chang Cc: Harald Welte Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-17-ulf.hansson@linaro.org --- drivers/mmc/host/via-sdmmc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index e48bddd95ce6..ef95bce50889 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -319,6 +319,8 @@ struct via_crdr_mmc_host { /* some devices need a very long delay for power to stabilize */ #define VIA_CRDR_QUIRK_300MS_PWRDELAY 0x0001 +#define VIA_CMD_TIMEOUT_MS 1000 + static const struct pci_device_id via_ids[] = { {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_9530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, @@ -551,14 +553,17 @@ static void via_sdc_send_command(struct via_crdr_mmc_host *host, { void __iomem *addrbase; struct mmc_data *data; + unsigned int timeout_ms; u32 cmdctrl = 0; WARN_ON(host->cmd); data = cmd->data; - mod_timer(&host->timer, jiffies + HZ); host->cmd = cmd; + timeout_ms = cmd->busy_timeout ? cmd->busy_timeout : VIA_CMD_TIMEOUT_MS; + mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout_ms)); + /*Command index*/ cmdctrl = cmd->opcode << 8; From 78a67b9224ade6da7d2d83c23a9858cb4dfcd64a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:11 +0200 Subject: [PATCH 053/127] mmc: mmc_spi: Add/rename defines for timeouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clarify the use of r1b_timeout, by renaming it to MMC_SPI_R1B_TIMEOUT_MS and by dropping the corresponding confusing comment about it. Additionally, let's also add a new define, MMC_SPI_INIT_TIMEOUT_MS and use it during the initialization. Even if these two defines are given the same value, the split makes it easier to understand them. Cc: Jonathan Neuschäfer Cc: Linus Walleij Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-18-ulf.hansson@linaro.org --- drivers/mmc/host/mmc_spi.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 951f76dc1ddd..5768fe9f8f6f 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -77,14 +77,8 @@ #define MMC_SPI_BLOCKSIZE 512 - -/* These fixed timeouts come from the latest SD specs, which say to ignore - * the CSD values. The R1B value is for card erase (e.g. the "I forgot the - * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after - * reads which takes nowhere near that long. Older cards may be able to use - * shorter timeouts ... but why bother? - */ -#define r1b_timeout (HZ * 3) +#define MMC_SPI_R1B_TIMEOUT_MS 3000 +#define MMC_SPI_INIT_TIMEOUT_MS 3000 /* One of the critical speed parameters is the amount of data which may * be transferred in one command. If this value is too low, the SD card @@ -347,7 +341,8 @@ static int mmc_spi_response_get(struct mmc_spi_host *host, while (cp < end && *cp == 0) cp++; if (cp == end) - mmc_spi_wait_unbusy(host, r1b_timeout); + mmc_spi_wait_unbusy(host, + msecs_to_jiffies(MMC_SPI_R1B_TIMEOUT_MS)); break; /* SPI R2 == R1 + second status byte; SEND_STATUS @@ -1118,7 +1113,7 @@ static void mmc_spi_initsequence(struct mmc_spi_host *host) /* Try to be very sure any previous command has completed; * wait till not-busy, skip debris from any old commands. */ - mmc_spi_wait_unbusy(host, r1b_timeout); + mmc_spi_wait_unbusy(host, msecs_to_jiffies(MMC_SPI_INIT_TIMEOUT_MS)); mmc_spi_readbytes(host, 10); /* From 5671ad667ebbe5e2aef77a89c775e9623b6bf4b8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:12 +0200 Subject: [PATCH 054/127] mmc: mmc_spi: Respect the cmd->busy_timeout from the mmc core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using a fixed 3s polling timeout for all commands with R1B responses is a bit problematic. For some commands it means waiting longer than needed for the polling to be aborted, which may not a big issue, but still. For other commands, like for an erase (CMD38), may require longer timeouts than 3s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully. Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core. Cc: Jonathan Neuschäfer Cc: Linus Walleij Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-19-ulf.hansson@linaro.org --- drivers/mmc/host/mmc_spi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 5768fe9f8f6f..39bb1e30c2d7 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -242,6 +242,7 @@ static char *maptype(struct mmc_command *cmd) static int mmc_spi_response_get(struct mmc_spi_host *host, struct mmc_command *cmd, int cs_on) { + unsigned long timeout_ms; u8 *cp = host->data->status; u8 *end = cp + host->t.len; int value = 0; @@ -340,9 +341,11 @@ static int mmc_spi_response_get(struct mmc_spi_host *host, /* maybe we read all the busy tokens already */ while (cp < end && *cp == 0) cp++; - if (cp == end) - mmc_spi_wait_unbusy(host, - msecs_to_jiffies(MMC_SPI_R1B_TIMEOUT_MS)); + if (cp == end) { + timeout_ms = cmd->busy_timeout ? cmd->busy_timeout : + MMC_SPI_R1B_TIMEOUT_MS; + mmc_spi_wait_unbusy(host, msecs_to_jiffies(timeout_ms)); + } break; /* SPI R2 == R1 + second status byte; SEND_STATUS From f583da4013a7e694fb0c3c5916537a72989e82a3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 23 Apr 2020 15:04:31 +0200 Subject: [PATCH 055/127] mmc: renesas_sdhi: handle M3-W ES1.2 and 1.3 revisions For ES1.2, add a comment explaining the situation. For ES1.3 (and later, although unlikely), add a new entry defining it as 4tap. Signed-off-by: Wolfram Sang Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20200423130432.9990-2-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 28b0830c4251..33b51105c788 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -711,11 +711,17 @@ static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = { .hs400_disabled = true, }; +/* + * Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now. + * So, we want to treat them equally and only have a match for ES1.2 to enforce + * this if there ever will be a way to distinguish ES1.2. + */ static const struct soc_device_attribute sdhi_quirks_match[] = { { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 }, { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, + { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_4tap }, { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 }, { /* Sentinel. */ }, }; From a38c078fea0b1393fd2acb50e91057d7e429d9aa Mon Sep 17 00:00:00 2001 From: Takeshi Saito Date: Thu, 23 Apr 2020 15:04:32 +0200 Subject: [PATCH 056/127] mmc: renesas_sdhi: Avoid bad TAP in HS400 With R-Car Gen3, CRC error occue at the following TAPs. H3, M3W 1.3, M3N... TAP=2,3,6,7 M3W 3.0 ... TAP=1,3,5,7 (Note: for 4tap SoCs, the numbers get divided by 2) Do not use these TAPs in HS400, and also don't use auto correction but manual correction. We check for bad taps in two places: 1) After tuning HS400: Then, we select a neighbouring TAP. One of them must be good, because there are never three bad taps in a row. Retuning won't help because we just finished tuning. 2) After a manual correction request: Here, we can't switch to the requested TAP. But we can retune (if the HS200 tuning was good) because the environment might have changed since the last tuning. If not, we stay on the same TAP. Signed-off-by: Takeshi Saito [wsa: refactored to match upstream driver, reworded commit msg] Signed-off-by: Wolfram Sang Reviewed-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20200423130432.9990-3-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/renesas_sdhi.h | 1 + drivers/mmc/host/renesas_sdhi_core.c | 55 ++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 86efa9d5cd6d..14c64caefc64 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -36,6 +36,7 @@ struct renesas_sdhi_of_data { struct renesas_sdhi_quirks { bool hs400_disabled; bool hs400_4taps; + u32 hs400_bad_taps; }; struct tmio_mmc_dma { diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 33b51105c788..ff72b381a6b3 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -325,6 +325,8 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); struct renesas_sdhi *priv = host_to_priv(host); + u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; + bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); @@ -352,10 +354,23 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc) SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | 0x4 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); + /* Avoid bad TAP */ + if (bad_taps & BIT(priv->tap_set)) { + u32 new_tap = (priv->tap_set + 1) % priv->tap_num; - if (priv->quirks && priv->quirks->hs400_4taps) - sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, - priv->tap_set / 2); + if (bad_taps & BIT(new_tap)) + new_tap = (priv->tap_set - 1) % priv->tap_num; + + if (bad_taps & BIT(new_tap)) { + new_tap = priv->tap_set; + dev_dbg(&host->pdev->dev, "Can't handle three bad tap in a row\n"); + } + + priv->tap_set = new_tap; + } + + sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, + priv->tap_set / (use_4tap ? 2 : 1)); sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, SH_MOBILE_SDHI_SCC_CKSEL_DTSEL | @@ -527,7 +542,7 @@ static int renesas_sdhi_execute_tuning(struct tmio_mmc_host *host, u32 opcode) static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap) { struct renesas_sdhi *priv = host_to_priv(host); - unsigned int new_tap = priv->tap_set; + unsigned int new_tap = priv->tap_set, error_tap = priv->tap_set; u32 val; val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ); @@ -539,20 +554,32 @@ static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_ /* Change TAP position according to correction status */ if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC && host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { + u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0; /* * With HS400, the DAT signal is based on DS, not CLK. * Therefore, use only CMD status. */ u32 smpcmp = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) & SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR; - if (!smpcmp) + if (!smpcmp) { return false; /* no error in CMD signal */ - else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP) + } else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP) { new_tap++; - else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN) + error_tap--; + } else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN) { new_tap--; - else + error_tap++; + } else { return true; /* need retune */ + } + + /* + * When new_tap is a bad tap, we cannot change. Then, we compare + * with the HS200 tuning result. When smpcmp[error_tap] is OK, + * we can at least retune. + */ + if (bad_taps & BIT(new_tap % priv->tap_num)) + return test_bit(error_tap % priv->tap_num, priv->smpcmp); } else { if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) return true; /* need retune */ @@ -705,12 +732,21 @@ static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = { static const struct renesas_sdhi_quirks sdhi_quirks_4tap = { .hs400_4taps = true, + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), }; static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = { .hs400_disabled = true, }; +static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps1357 = { + .hs400_bad_taps = BIT(1) | BIT(3) | BIT(5) | BIT(7), +}; + +static const struct renesas_sdhi_quirks sdhi_quirks_bad_taps2367 = { + .hs400_bad_taps = BIT(2) | BIT(3) | BIT(6) | BIT(7), +}; + /* * Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now. * So, we want to treat them equally and only have a match for ES1.2 to enforce @@ -720,8 +756,11 @@ static const struct soc_device_attribute sdhi_quirks_match[] = { { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 }, { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, + { .soc_id = "r8a7795", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps2367 }, { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, { .soc_id = "r8a7796", .revision = "ES1.*", .data = &sdhi_quirks_4tap }, + { .soc_id = "r8a7796", .revision = "ES3.*", .data = &sdhi_quirks_bad_taps1357 }, + { .soc_id = "r8a77965", .data = &sdhi_quirks_bad_taps2367 }, { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 }, { /* Sentinel. */ }, }; From c2b613d03b060993be71b480a3ebb6156604d658 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Tue, 28 Apr 2020 19:02:57 +0530 Subject: [PATCH 057/127] mmc: sdhci-msm: Fix error handling for dev_pm_opp_of_add_table() Even though specifying OPP's in device tree is optional, ignoring all errors reported by dev_pm_opp_of_add_table() means we can't distinguish between a missing OPP table and a wrong/buggy OPP table. While missing OPP table (dev_pm_opp_of_add_table() returns a -ENODEV in such case) can be ignored, a wrong/buggy OPP table in device tree should make the driver error out. while we fix that, lets also fix the variable names for opp/opp_table to avoid confusion and name them opp_table/has_opp_table instead. Suggested-by: Matthias Kaehlcke Signed-off-by: Rajendra Nayak Link: https://lore.kernel.org/r/1588080785-6812-10-git-send-email-rnayak@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 8a055ddfdaff..97758fa62111 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -244,8 +244,8 @@ struct sdhci_msm_host { struct clk_bulk_data bulk_clks[4]; /* core, iface, cal, sleep clocks */ unsigned long clk_rate; struct mmc_host *mmc; - struct opp_table *opp; - bool opp_table; + struct opp_table *opp_table; + bool has_opp_table; bool use_14lpp_dll_reset; bool tuning_done; bool calibration_done; @@ -1967,15 +1967,20 @@ static int sdhci_msm_probe(struct platform_device *pdev) } msm_host->bulk_clks[0].clk = clk; - msm_host->opp = dev_pm_opp_set_clkname(&pdev->dev, "core"); - if (IS_ERR(msm_host->opp)) { - ret = PTR_ERR(msm_host->opp); + msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core"); + if (IS_ERR(msm_host->opp_table)) { + ret = PTR_ERR(msm_host->opp_table); goto bus_clk_disable; } /* OPP table is optional */ - if (!dev_pm_opp_of_add_table(&pdev->dev)) - msm_host->opp_table = true; + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (!ret) { + msm_host->has_opp_table = true; + } else if (ret != -ENODEV) { + dev_err(&pdev->dev, "Invalid OPP table in Device tree\n"); + goto opp_cleanup; + } /* Vote for maximum clock rate for maximum performance */ ret = dev_pm_opp_set_rate(&pdev->dev, INT_MAX); @@ -2133,9 +2138,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); opp_cleanup: - if (msm_host->opp_table) + if (msm_host->has_opp_table) dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_clkname(msm_host->opp); + dev_pm_opp_put_clkname(msm_host->opp_table); bus_clk_disable: if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); @@ -2154,9 +2159,9 @@ static int sdhci_msm_remove(struct platform_device *pdev) sdhci_remove_host(host, dead); - if (msm_host->opp_table) + if (msm_host->has_opp_table) dev_pm_opp_of_remove_table(&pdev->dev); - dev_pm_opp_put_clkname(msm_host->opp); + dev_pm_opp_put_clkname(msm_host->opp_table); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); From f04086c225da11ad16d7f9a2fbca6483ab16dded Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 30 Apr 2020 11:16:37 +0200 Subject: [PATCH 058/127] mmc: sdio: Fix potential NULL pointer error in mmc_sdio_init_card() During some scenarios mmc_sdio_init_card() runs a retry path for the UHS-I specific initialization, which leads to removal of the previously allocated card. A new card is then re-allocated while retrying. However, in one of the corresponding error paths we may end up to remove an already removed card, which likely leads to a NULL pointer exception. So, let's fix this. Fixes: 5fc3d80ef496 ("mmc: sdio: don't use rocr to check if the card could support UHS mode") Cc: Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200430091640.455-2-ulf.hansson@linaro.org --- drivers/mmc/core/sdio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ebb387aa5158..d35679e6e6aa 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -718,9 +718,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, /* Retry init sequence, but without R4_18V_PRESENT. */ retries = 0; goto try_again; - } else { - goto remove; } + return err; } /* From a94a59f43749b4f8cd81b8be87c95f9ef898d19d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 30 Apr 2020 11:16:38 +0200 Subject: [PATCH 059/127] mmc: sdio: Fix several potential memory leaks in mmc_sdio_init_card() Over the years, the code in mmc_sdio_init_card() has grown to become quite messy. Unfortunate this has also lead to that several paths are leaking memory in form of an allocated struct mmc_card, which includes additional data, such as initialized struct device for example. Unfortunate, it's a too complex task find each offending commit. Therefore, this change fixes all memory leaks at once. Cc: Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200430091640.455-3-ulf.hansson@linaro.org --- drivers/mmc/core/sdio.c | 58 +++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index d35679e6e6aa..20eed28ea60d 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -584,7 +584,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, */ err = mmc_send_io_op_cond(host, ocr, &rocr); if (err) - goto err; + return err; /* * For SPI, enable CRC as appropriate. @@ -592,17 +592,15 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (mmc_host_is_spi(host)) { err = mmc_spi_set_crc(host, use_spi_crc); if (err) - goto err; + return err; } /* * Allocate card structure. */ card = mmc_alloc_card(host, NULL); - if (IS_ERR(card)) { - err = PTR_ERR(card); - goto err; - } + if (IS_ERR(card)) + return PTR_ERR(card); if ((rocr & R4_MEMORY_PRESENT) && mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) { @@ -610,19 +608,15 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) { - mmc_remove_card(card); - pr_debug("%s: Perhaps the card was replaced\n", - mmc_hostname(host)); - return -ENOENT; + err = -ENOENT; + goto mismatch; } } else { card->type = MMC_TYPE_SDIO; if (oldcard && oldcard->type != MMC_TYPE_SDIO) { - mmc_remove_card(card); - pr_debug("%s: Perhaps the card was replaced\n", - mmc_hostname(host)); - return -ENOENT; + err = -ENOENT; + goto mismatch; } } @@ -677,7 +671,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (!oldcard && card->type == MMC_TYPE_SD_COMBO) { err = mmc_sd_get_csd(host, card); if (err) - return err; + goto remove; mmc_decode_cid(card); } @@ -704,7 +698,12 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, mmc_set_timing(card->host, MMC_TIMING_SD_HS); } - goto finish; + if (oldcard) + mmc_remove_card(card); + else + host->card = card; + + return 0; } /* @@ -730,16 +729,14 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, goto remove; if (oldcard) { - int same = (card->cis.vendor == oldcard->cis.vendor && - card->cis.device == oldcard->cis.device); - mmc_remove_card(card); - if (!same) { - pr_debug("%s: Perhaps the card was replaced\n", - mmc_hostname(host)); - return -ENOENT; + if (card->cis.vendor == oldcard->cis.vendor && + card->cis.device == oldcard->cis.device) { + mmc_remove_card(card); + card = oldcard; + } else { + err = -ENOENT; + goto mismatch; } - - card = oldcard; } card->ocr = ocr_card; mmc_fixup_device(card, sdio_fixup_methods); @@ -800,16 +797,15 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, err = -EINVAL; goto remove; } -finish: - if (!oldcard) - host->card = card; + + host->card = card; return 0; +mismatch: + pr_debug("%s: Perhaps the card was replaced\n", mmc_hostname(host)); remove: - if (!oldcard) + if (oldcard != card) mmc_remove_card(card); - -err: return err; } From fa1e3191922bb6b59a64a1a03e461cde07ae1e62 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 30 Apr 2020 11:16:39 +0200 Subject: [PATCH 060/127] mmc: sdio: Re-use negotiated OCR mask when re-sending CMD8 While initializing an SDIO card in mmc_sdio_init_card(), we may need to retry the UHS-I specific initialization, in case the first attempt fails. This leads to resending a CMD8, but also to restart from scratch with the so called OCR mask negotiations. This is unnecessary as we already have a negotiated OCR mask, so let's use that instead. In this way, the behaviour also becomes more consistent with other similar paths. Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200430091640.455-4-ulf.hansson@linaro.org --- drivers/mmc/core/sdio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 20eed28ea60d..853ac65f0485 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -543,12 +543,12 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) return err; } -static void mmc_sdio_resend_if_cond(struct mmc_host *host, +static void mmc_sdio_resend_if_cond(struct mmc_host *host, u32 ocr, struct mmc_card *card) { sdio_reset(host); mmc_go_idle(host); - mmc_send_if_cond(host, host->ocr_avail); + mmc_send_if_cond(host, ocr); mmc_remove_card(card); } @@ -640,7 +640,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (rocr & ocr & R4_18V_PRESENT) { err = mmc_set_uhs_voltage(host, ocr_card); if (err == -EAGAIN) { - mmc_sdio_resend_if_cond(host, card); + mmc_sdio_resend_if_cond(host, ocr_card, card); retries--; goto try_again; } else if (err) { @@ -712,7 +712,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, */ err = sdio_read_cccr(card, ocr); if (err) { - mmc_sdio_resend_if_cond(host, card); + mmc_sdio_resend_if_cond(host, ocr_card, card); if (ocr & R4_18V_PRESENT) { /* Retry init sequence, but without R4_18V_PRESENT. */ retries = 0; From 1dc5a61559e73472cd84bc8aa5b297ec0deba4de Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 30 Apr 2020 11:16:40 +0200 Subject: [PATCH 061/127] mmc: sdio: Align the initialization commands in retry path for UHS-I According to the comment in mmc_sdio_reinit_card(), some SDIO cards may require a "[CMD5,5,3,7] init sequence", which isn't always obeyed in mmc_sdio_init_card(). Especially, when we end up retrying the UHS-I specific initialization, there is a missing CMD5. Let's update the code to make the behaviour consistent and let's also take the opportunity to clean up the code a bit, to avoid open coding. Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200430091640.455-5-ulf.hansson@linaro.org --- drivers/mmc/core/sdio.c | 53 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 853ac65f0485..435de47a6ee0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -543,13 +543,33 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) return err; } -static void mmc_sdio_resend_if_cond(struct mmc_host *host, u32 ocr, - struct mmc_card *card) +static int mmc_sdio_pre_init(struct mmc_host *host, u32 ocr, + struct mmc_card *card) { + if (card) + mmc_remove_card(card); + + /* + * Reset the card by performing the same steps that are taken by + * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. + * + * sdio_reset() is technically not needed. Having just powered up the + * hardware, it should already be in reset state. However, some + * platforms (such as SD8686 on OLPC) do not instantly cut power, + * meaning that a reset is required when restoring power soon after + * powering off. It is harmless in other cases. + * + * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec, + * is not necessary for non-removable cards. However, it is required + * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and + * harmless in other situations. + * + */ + sdio_reset(host); mmc_go_idle(host); mmc_send_if_cond(host, ocr); - mmc_remove_card(card); + return mmc_send_io_op_cond(host, 0, NULL); } /* @@ -640,7 +660,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (rocr & ocr & R4_18V_PRESENT) { err = mmc_set_uhs_voltage(host, ocr_card); if (err == -EAGAIN) { - mmc_sdio_resend_if_cond(host, ocr_card, card); + mmc_sdio_pre_init(host, ocr_card, card); retries--; goto try_again; } else if (err) { @@ -712,7 +732,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, */ err = sdio_read_cccr(card, ocr); if (err) { - mmc_sdio_resend_if_cond(host, ocr_card, card); + mmc_sdio_pre_init(host, ocr_card, card); if (ocr & R4_18V_PRESENT) { /* Retry init sequence, but without R4_18V_PRESENT. */ retries = 0; @@ -813,28 +833,7 @@ static int mmc_sdio_reinit_card(struct mmc_host *host) { int ret; - /* - * Reset the card by performing the same steps that are taken by - * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. - * - * sdio_reset() is technically not needed. Having just powered up the - * hardware, it should already be in reset state. However, some - * platforms (such as SD8686 on OLPC) do not instantly cut power, - * meaning that a reset is required when restoring power soon after - * powering off. It is harmless in other cases. - * - * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec, - * is not necessary for non-removable cards. However, it is required - * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and - * harmless in other situations. - * - */ - - sdio_reset(host); - mmc_go_idle(host); - mmc_send_if_cond(host, host->card->ocr); - - ret = mmc_send_io_op_cond(host, 0, NULL); + ret = mmc_sdio_pre_init(host, host->card->ocr, NULL); if (ret) return ret; From 064f7e58ee42372be05ec87fdf57864c7475ba93 Mon Sep 17 00:00:00 2001 From: Krishna Konda Date: Fri, 1 May 2020 19:23:01 +0530 Subject: [PATCH 062/127] mmc: core: expose info about enhanced rpmb support Following eMMC JEDEC JESD84-B51 standard, an enhanced form of rpmb is supported. What this enhanced mode supports is in addition to be able to write one rpmb or two rpmb frames at a time, 32 frames can be written at a time. Expose this information present in ext csd field so that the user space application that wants to make use of this can do so. Signed-off-by: Krishna Konda Signed-off-by: Veerabhadrarao Badiganti Link: https://lore.kernel.org/r/1588341189-4371-1-git-send-email-vbadigan@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/core/mmc.c | 6 ++++++ include/linux/mmc/card.h | 1 + include/linux/mmc/mmc.h | 1 + 3 files changed, 8 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index de94fbe629bd..4203303f946a 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -647,6 +647,9 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_hostname(card->host), card->ext_csd.cmdq_depth); } + card->ext_csd.enhanced_rpmb_supported = + (card->ext_csd.rel_param & + EXT_CSD_WR_REL_PARAM_EN_RPMB_REL_WR); } out: return err; @@ -786,6 +789,8 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", card->ext_csd.enhanced_area_offset); 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(enhanced_rpmb_supported, "%#x\n", + card->ext_csd.enhanced_rpmb_supported); MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); @@ -843,6 +848,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_enhanced_area_offset.attr, &dev_attr_enhanced_area_size.attr, &dev_attr_raw_rpmb_size_mult.attr, + &dev_attr_enhanced_rpmb_supported.attr, &dev_attr_rel_sectors.attr, &dev_attr_ocr.attr, &dev_attr_rca.attr, diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index cf3780a6ccc4..7d46411ffaa2 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -48,6 +48,7 @@ struct mmc_ext_csd { u8 sec_feature_support; u8 rel_sectors; u8 rel_param; + bool enhanced_rpmb_supported; u8 part_config; u8 cache_ctrl; u8 rst_n_function; diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 4b85ef05a906..d9a65c6a8816 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -325,6 +325,7 @@ static inline bool mmc_ready_for_data(u32 status) */ #define EXT_CSD_WR_REL_PARAM_EN (1<<2) +#define EXT_CSD_WR_REL_PARAM_EN_RPMB_REL_WR (1<<4) #define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) #define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) From 30e1028dcef9ac981c20df83983e0e77a4df2dc4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 2 May 2020 16:28:25 +0200 Subject: [PATCH 063/127] mmc: sdhci-esdhc: update contact email The 'pengutronix' address is defunct for years. Use the proper contact address. Signed-off-by: Wolfram Sang Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20200502142840.19418-1-wsa@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc.h | 2 +- include/linux/platform_data/mmc-esdhc-imx.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index 947212f16bc6..a30796e79b1c 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -5,7 +5,7 @@ * Copyright (c) 2007 Freescale Semiconductor, Inc. * Copyright (c) 2009 MontaVista Software, Inc. * Copyright (c) 2010 Pengutronix e.K. - * Author: Wolfram Sang + * Author: Wolfram Sang */ #ifndef _DRIVERS_MMC_SDHCI_ESDHC_H diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h index 0434f68eda86..cba1184b364c 100644 --- a/include/linux/platform_data/mmc-esdhc-imx.h +++ b/include/linux/platform_data/mmc-esdhc-imx.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright 2010 Wolfram Sang + * Copyright 2010 Wolfram Sang */ #ifndef __ASM_ARCH_IMX_ESDHC_H From 194f9b21ad64740eb9675703037fe42113cea65c Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Wed, 6 May 2020 20:51:27 +0100 Subject: [PATCH 064/127] dt-bindings: mmc: renesas,mmcif: Document r8a7742 DT bindings Add support for r8a7742 SoC. Renesas RZ/G1H (R8A7742) MMCIF is identical to the R-Car Gen2 family. Signed-off-by: Lad Prabhakar Reviewed-by: Marian-Cristian Rotariu Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/1588794695-27852-2-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/renesas,mmcif.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt index c064af5838aa..291532ac0446 100644 --- a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt +++ b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt @@ -11,6 +11,7 @@ Required properties: - "renesas,mmcif-r7s72100" for the MMCIF found in r7s72100 SoCs - "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs + - "renesas,mmcif-r8a7742" for the MMCIF found in r8a7742 SoCs - "renesas,mmcif-r8a7743" for the MMCIF found in r8a7743 SoCs - "renesas,mmcif-r8a7744" for the MMCIF found in r8a7744 SoCs - "renesas,mmcif-r8a7745" for the MMCIF found in r8a7745 SoCs @@ -24,8 +25,8 @@ Required properties: - interrupts: Some SoCs have only 1 shared interrupt, while others have either 2 or 3 individual interrupts (error, int, card detect). Below is the number of interrupts for each SoC: - 1: r8a73a4, r8a7743, r8a7744, r8a7745, r8a7778, r8a7790, r8a7791, r8a7793, - r8a7794 + 1: r8a73a4, r8a7742, r8a7743, r8a7744, r8a7745, r8a7778, r8a7790, r8a7791, + r8a7793, r8a7794 2: r8a7740, sh73a0 3: r7s72100 From 91995b904ec2e44b5c159ac6a5d3f154345a4de7 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 4 May 2020 00:28:05 +0200 Subject: [PATCH 065/127] mmc: meson-mx-sdio: trigger a soft reset after a timeout or CRC error The vendor driver (from the 3.10 kernel) triggers a soft reset every time before starting a new command. While this fixes a problem where SDIO cards are not detected at all (because all commands simply timed out) this hurts SD card read performance a bit (in my tests between 10% to 20%). Trigger a soft reset after we got a CRC error or if the previous command timed out (just like the vendor driver from the same 3.10 kernel for the newer SDHC controller IP does). This fixes detection of SDIO cards and doesn't hurt SD card read performance at the same time. With this patch the initialization of an RTL8723BS SDIO card looks like this: req done (CMD52): -110: 00000000 00000000 00000000 00000000 clock 400000Hz busmode 2 powermode 2 cs 1 Vdd 21 width 1 timing 0 starting CMD0 arg 00000000 flags 000000c0 req done (CMD0): 0: 00000000 00000000 00000000 00000000 clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 1 timing 0 starting CMD8 arg 000001aa flags 000002f5 req done (CMD8): -110: 00000000 00000000 00000000 00000000 starting CMD5 arg 00000000 flags 000002e1 req done (CMD5): 0: 90ff0000 00000000 00000000 00000000 starting CMD5 arg 00200000 flags 000002e1 req done (CMD5): 0: 90ff0000 00000000 00000000 00000000 starting CMD3 arg 00000000 flags 00000075 req done (CMD3): 0: 00010000 00000000 00000000 00000000 starting CMD7 arg 00010000 flags 00000015 req done (CMD7): 0: 00001e00 00000000 00000000 00000000 starting CMD52 arg 00000000 flags 00000195 req done (CMD52): 0: 00001032 00000000 00000000 00000000 [... more CMD52 omitted ...] clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 1 timing 2 clock 50000000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 1 timing 2 starting CMD52 arg 00000e00 flags 00000195 req done (CMD52): 0: 00001000 00000000 00000000 00000000 starting CMD52 arg 80000e02 flags 00000195 req done (CMD52): 0: 00001002 00000000 00000000 00000000 clock 50000000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 4 timing 2 starting CMD52 arg 00020000 flags 00000195 req done (CMD52): 0: 00001007 00000000 00000000 00000000 [... more CMD52 omitted ...] new high speed SDIO card at address 0001 Fixes: ed80a13bb4c4c9 ("mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b SoCs") Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20200503222805.2668941-1-martin.blumenstingl@googlemail.com Tested-by: Tobias Baumann <017623705678@o2online.de> Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-mx-sdio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index 2e58743d83bb..3813b544f571 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -246,6 +246,9 @@ static void meson_mx_mmc_request_done(struct meson_mx_mmc_host *host) mrq = host->mrq; + if (host->cmd->error) + meson_mx_mmc_soft_reset(host); + host->mrq = NULL; host->cmd = NULL; From f4f20d6897b1c047c5d38b2cfc50928e83d8fd83 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 7 May 2020 14:22:18 -0500 Subject: [PATCH 066/127] memstick: Replace zero-length array with flexible-array The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] sizeof(flexible-array-member) triggers a warning because flexible array members have incomplete type[1]. There are some instances of code in which the sizeof operator is being incorrectly/erroneously applied to zero-length arrays and the result is zero. Such instances may be hiding some bugs. So, this work (flexible-array member conversions) will also help to get completely rid of those sorts of issues. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20200507192218.GA16315@embeddedor Signed-off-by: Ulf Hansson --- include/linux/memstick.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/memstick.h b/include/linux/memstick.h index 216a713bef7f..da4c65f9435f 100644 --- a/include/linux/memstick.h +++ b/include/linux/memstick.h @@ -288,7 +288,7 @@ struct memstick_host { int (*set_param)(struct memstick_host *host, enum memstick_param param, int value); - unsigned long private[0] ____cacheline_aligned; + unsigned long private[] ____cacheline_aligned; }; struct memstick_driver { From 85a3f77c1be5ee143615e47f98f653d65806b8ae Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 14 Apr 2020 18:14:00 +0200 Subject: [PATCH 067/127] mmc: cb710: Inform the mmc core about the maximum busy timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some commands uses R1B responses, which means the card may assert the DAT0 line to signal busy for a period of time, after it has received the command. The mmc core normally specifies the busy period for the command in the cmd->busy_timeout. Ideally the driver should respect it, but that requires quite some update of the code, so let's defer that to someone with the HW at hand. Instead, let's inform the mmc core about the maximum supported busy timeout in ->max_busy_timeout during ->probe(). This value corresponds to the fixed ~2s timeout of the polling loop, implemented in cb710_wait_for_event(). In this way, we let the mmc core validate the needed timeout, which may lead to that it converts from a R1B into a R1 response and then use CMD13 to poll for busy completion. In other words, this change enables support for commands with longer busy periods than 2s, like erase (CMD38) for example. Cc: Michał Mirosław Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200414161413.3036-7-ulf.hansson@linaro.org --- drivers/mmc/host/cb710-mmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index e33270e40539..e84ed84ea4cc 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -10,6 +10,8 @@ #include #include "cb710-mmc.h" +#define CB710_MMC_REQ_TIMEOUT_MS 2000 + static const u8 cb710_clock_divider_log2[8] = { /* 1, 2, 4, 8, 16, 32, 128, 512 */ 0, 1, 2, 3, 4, 5, 7, 9 @@ -707,6 +709,12 @@ static int cb710_mmc_init(struct platform_device *pdev) mmc->f_min = val >> cb710_clock_divider_log2[CB710_MAX_DIVIDER_IDX]; mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; mmc->caps = MMC_CAP_4_BIT_DATA; + /* + * In cb710_wait_for_event() we use a fixed timeout of ~2s, hence let's + * inform the core about it. A future improvement should instead make + * use of the cmd->busy_timeout. + */ + mmc->max_busy_timeout = CB710_MMC_REQ_TIMEOUT_MS; reader = mmc_priv(mmc); From eadb7897652d5bf9fbab393b3774598a04846aff Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 8 May 2020 11:52:10 +0200 Subject: [PATCH 068/127] mmc: sdricoh_cs: Throttle polling rate for data transfers Rather than to poll in a busy-loop, let's convert into using read_poll_timeout() and insert a small delay between each polling attempts. In particular, this avoids hogging the CPU. Additionally, to convert to read_poll_timeout() we also need to switch from using a specific number of polling attempts, into a specific timeout in us instead. The previous 100000 attempts, is translated into a total timeout of total 1s, as that seemed like reasonable value to pick. Cc: Sascha Sommer Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200508095210.14123-1-ulf.hansson@linaro.org --- drivers/mmc/host/sdricoh_cs.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 97ef7d71375a..8392158e2e9f 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -59,7 +60,7 @@ static unsigned int switchlocked; /* timeouts */ #define CMD_TIMEOUT 100000 -#define TRANSFER_TIMEOUT 100000 +#define SDRICOH_DATA_TIMEOUT_US 1000000 /* list of supported pcmcia devices */ static const struct pcmcia_device_id pcmcia_ids[] = { @@ -123,21 +124,24 @@ static inline unsigned int sdricoh_readb(struct sdricoh_host *host, return value; } +static bool sdricoh_status_ok(struct sdricoh_host *host, unsigned int status, + unsigned int wanted) +{ + sdricoh_writel(host, R2E4_STATUS_RESP, status); + return status & wanted; +} + static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted) { - unsigned int loop; + int ret; unsigned int status = 0; - unsigned int timeout = TRANSFER_TIMEOUT; struct device *dev = host->dev; - for (loop = 0; loop < timeout; loop++) { - status = sdricoh_readl(host, R21C_STATUS); - sdricoh_writel(host, R2E4_STATUS_RESP, status); - if (status & wanted) - break; - } - - if (loop == timeout) { + ret = read_poll_timeout(sdricoh_readl, status, + sdricoh_status_ok(host, status, wanted), + 32, SDRICOH_DATA_TIMEOUT_US, false, + host, R21C_STATUS); + if (ret) { dev_err(dev, "query_status: timeout waiting for %x\n", wanted); return -ETIMEDOUT; } From 3eea697c1da58f169b3abfebaa6d07cff7cb1c8d Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 8 May 2020 11:52:18 +0200 Subject: [PATCH 069/127] mmc: sdricoh_cs: Throttle polling rate for commands Rather than to poll in a busy-loop, let's convert into using read_poll_timeout() and insert a small delay between each polling attempts. In particular, this avoids hogging the CPU. Additionally, to convert to read_poll_timeout() we also need to switch from using a specific number of polling attempts, into a specific timeout in us instead. The previous 100000 attempts, is translated into a total timeout of total 1s, as that seemed like reasonable value to pick. Cc: Sascha Sommer Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200508095218.14177-1-ulf.hansson@linaro.org --- drivers/mmc/host/sdricoh_cs.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 8392158e2e9f..0594b5ffe151 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -59,7 +59,7 @@ static unsigned int switchlocked; #define STATUS_BUSY 0x40000000 /* timeouts */ -#define CMD_TIMEOUT 100000 +#define SDRICOH_CMD_TIMEOUT_US 1000000 #define SDRICOH_DATA_TIMEOUT_US 1000000 /* list of supported pcmcia devices */ @@ -158,8 +158,7 @@ static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted) static int sdricoh_mmc_cmd(struct sdricoh_host *host, struct mmc_command *cmd) { unsigned int status; - int result = 0; - unsigned int loop = 0; + int ret; unsigned char opcode = cmd->opcode; /* reset status reg? */ @@ -175,24 +174,24 @@ static int sdricoh_mmc_cmd(struct sdricoh_host *host, struct mmc_command *cmd) /* fill parameters */ sdricoh_writel(host, R204_CMD_ARG, cmd->arg); sdricoh_writel(host, R200_CMD, (0x10000 << 8) | opcode); + /* wait for command completion */ - if (opcode) { - for (loop = 0; loop < CMD_TIMEOUT; loop++) { - status = sdricoh_readl(host, R21C_STATUS); - sdricoh_writel(host, R2E4_STATUS_RESP, status); - if (status & STATUS_CMD_FINISHED) - break; - } - /* don't check for timeout in the loop it is not always - reset correctly - */ - if (loop == CMD_TIMEOUT || status & STATUS_CMD_TIMEOUT) - result = -ETIMEDOUT; + if (!opcode) + return 0; - } + ret = read_poll_timeout(sdricoh_readl, status, + sdricoh_status_ok(host, status, STATUS_CMD_FINISHED), + 32, SDRICOH_CMD_TIMEOUT_US, false, + host, R21C_STATUS); - return result; + /* + * Don't check for timeout status in the loop, as it's not always reset + * correctly. + */ + if (ret || status & STATUS_CMD_TIMEOUT) + return -ETIMEDOUT; + return 0; } static int sdricoh_reset(struct sdricoh_host *host) From 04f2f45f410f4c1f591482afa1ab6a8c44f0b713 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 8 May 2020 11:52:28 +0200 Subject: [PATCH 070/127] mmc: sdricoh_cs: Respect the cmd->busy_timeout from the mmc core Using a fixed 1s polling timeout for all commands is a bit problematic. For some commands it means waiting longer than needed for the polling to be aborted, which may not a big issue, but still. For other commands, like for an erase (CMD38) that uses a R1B response, may require longer timeouts than 1s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully. Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core. Note that, even if the sdricoh_cs driver may currently not support HW busy detection on DAT0, some comments in the code refer to that the HW may support it. Therefore, it seems better to be proactive in this case. Cc: Sascha Sommer Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200508095228.14230-1-ulf.hansson@linaro.org --- drivers/mmc/host/sdricoh_cs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 0594b5ffe151..76a8cd3a186f 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -157,7 +157,7 @@ static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted) static int sdricoh_mmc_cmd(struct sdricoh_host *host, struct mmc_command *cmd) { - unsigned int status; + unsigned int status, timeout_us; int ret; unsigned char opcode = cmd->opcode; @@ -179,9 +179,12 @@ static int sdricoh_mmc_cmd(struct sdricoh_host *host, struct mmc_command *cmd) if (!opcode) return 0; + timeout_us = cmd->busy_timeout ? cmd->busy_timeout * 1000 : + SDRICOH_CMD_TIMEOUT_US; + ret = read_poll_timeout(sdricoh_readl, status, sdricoh_status_ok(host, status, STATUS_CMD_FINISHED), - 32, SDRICOH_CMD_TIMEOUT_US, false, + 32, timeout_us, false, host, R21C_STATUS); /* From 94fe2580a2f3bb055fdca86a2adf156d01f15764 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 8 May 2020 13:28:53 +0200 Subject: [PATCH 071/127] mmc: core: Enable erase/discard/trim support for all mmc hosts Step by step, mmc host drivers and the mmc core have been improved in regards to support erase/discard/trim operations. We have now reached a point when it no longer seems reasonable to use an opt-in approach to enable the functionality. Therefore, let's switch to make the operations always supported. Signed-off-by: Ulf Hansson Link: https://lore.kernel.org/r/20200508112853.23525-1-ulf.hansson@linaro.org Reviewed-by: Linus Walleij --- drivers/mmc/core/core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 4c5de6d37ac7..8d2b808e9b58 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1815,8 +1815,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, unsigned int rem, to = from + nr; int err; - if (!(card->host->caps & MMC_CAP_ERASE) || - !(card->csd.cmdclass & CCC_ERASE)) + if (!(card->csd.cmdclass & CCC_ERASE)) return -EOPNOTSUPP; if (!card->erase_size) @@ -1872,8 +1871,7 @@ EXPORT_SYMBOL(mmc_erase); int mmc_can_erase(struct mmc_card *card) { - if ((card->host->caps & MMC_CAP_ERASE) && - (card->csd.cmdclass & CCC_ERASE) && card->erase_size) + if (card->csd.cmdclass & CCC_ERASE && card->erase_size) return 1; return 0; } From 1be64c7963f89afbd6f96f27effea20900650dfe Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 8 May 2020 13:29:02 +0200 Subject: [PATCH 072/127] mmc: host: Drop redundant MMC_CAP_ERASE The MMC_CAP_ERASE bit is no longer used by the mmc core as erase, discard and trim operations are now always supported. Therefore, drop the bit and move all mmc hosts away from using it. Signed-off-by: Ulf Hansson Reviewed-by: Rui Miguel Silva Link: https://lore.kernel.org/r/20200508112902.23575-1-ulf.hansson@linaro.org Reviewed-by: Linus Walleij --- drivers/mmc/host/bcm2835.c | 3 +-- drivers/mmc/host/cavium.c | 3 +-- drivers/mmc/host/dw_mmc.c | 6 ------ drivers/mmc/host/meson-mx-sdio.c | 2 +- drivers/mmc/host/mtk-sd.c | 2 +- drivers/mmc/host/mvsdio.c | 2 -- drivers/mmc/host/mxs-mmc.c | 3 +-- drivers/mmc/host/omap.c | 2 +- drivers/mmc/host/omap_hsmmc.c | 2 +- drivers/mmc/host/rtsx_pci_sdmmc.c | 2 +- drivers/mmc/host/rtsx_usb_sdmmc.c | 2 +- drivers/mmc/host/sdhci.c | 2 +- drivers/mmc/host/sunxi-mmc.c | 2 +- drivers/mmc/host/tmio_mmc_core.c | 2 +- drivers/staging/greybus/sdio.c | 1 - include/linux/mmc/host.h | 1 - 16 files changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index c3d949847cbd..a0767790a826 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -1280,8 +1280,7 @@ static int bcm2835_add_host(struct bcm2835_host *host) /* host controller capabilities */ mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE | - MMC_CAP_CMD23; + MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_CMD23; spin_lock_init(&host->lock); mutex_init(&host->mutex); diff --git a/drivers/mmc/host/cavium.c b/drivers/mmc/host/cavium.c index 89deb451e0ac..c5da3aaee334 100644 --- a/drivers/mmc/host/cavium.c +++ b/drivers/mmc/host/cavium.c @@ -1038,8 +1038,7 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host) * Disable bounce buffers for max_segs = 1 */ mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD | - MMC_CAP_3_3V_DDR; + MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD | MMC_CAP_3_3V_DDR; if (host->use_sg) mmc->max_segs = 16; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 5d1f8a3ec3a5..35ae5737c622 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2751,12 +2751,6 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) if (host->pdata->caps) mmc->caps = host->pdata->caps; - /* - * Support MMC_CAP_ERASE by default. - * It needs to use trim/discard/erase commands. - */ - mmc->caps |= MMC_CAP_ERASE; - if (host->pdata->pm_caps) mmc->pm_caps = host->pdata->pm_caps; diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index 3813b544f571..9b2cf7afc246 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -564,7 +564,7 @@ static int meson_mx_mmc_add_host(struct meson_mx_mmc_host *host) mmc->f_max = clk_round_rate(host->cfg_div_clk, clk_get_rate(host->parent_clk)); - mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY; + mmc->caps |= MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY; mmc->ops = &meson_mx_mmc_ops; ret = mmc_of_parse(mmc); diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 53819ae9f271..39e7fc54c438 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -2326,7 +2326,7 @@ static int msdc_drv_probe(struct platform_device *pdev) if (mmc->caps & MMC_CAP_SDIO_IRQ) mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; - mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23; + mmc->caps |= MMC_CAP_CMD23; /* MMC core transfer sizes tunable parameters */ mmc->max_segs = MAX_BD_NUM; if (host->dev_comp->support_64g) diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 203b61712601..cc0752a9df6d 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -752,8 +752,6 @@ static int mvsd_probe(struct platform_device *pdev) if (maxfreq) mmc->f_max = maxfreq; - mmc->caps |= MMC_CAP_ERASE; - spin_lock_init(&host->lock); host->base = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index d82674aed447..b1820def36c0 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -634,8 +634,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) /* set mmc core parameters */ mmc->ops = &mxs_mmc_ops; mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23 | - MMC_CAP_ERASE; + MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL | MMC_CAP_CMD23; host->broken_cd = of_property_read_bool(np, "broken-cd"); diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index d74e73c95fdf..33d7af7c7762 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1244,7 +1244,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) mmc->caps = 0; if (host->pdata->slots[id].wires >= 4) - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_ERASE; + mmc->caps |= MMC_CAP_4_BIT_DATA; mmc->ops = &mmc_omap_ops; mmc->f_min = 400000; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index a379c45b985c..37b8740513f5 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1922,7 +1922,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE | MMC_CAP_CMD23; + MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_CMD23; mmc->caps |= mmc_pdata(host)->caps; if (mmc->caps & MMC_CAP_8_BIT_DATA) diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 11087976ab19..5a71f6678fd3 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1347,7 +1347,7 @@ static void realtek_init_host(struct realtek_pci_sdmmc *host) mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | - MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_ERASE; + MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE; mmc->max_current_330 = 400; mmc->max_current_180 = 800; diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 81d0dfe553a8..a7084c50ad65 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1314,7 +1314,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host) mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | - MMC_CAP_ERASE | MMC_CAP_SYNC_RUNTIME_PM; + MMC_CAP_SYNC_RUNTIME_PM; mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE | MMC_CAP2_NO_SDIO; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 1bb6b6796318..95cc08c1fed9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -4331,7 +4331,7 @@ int sdhci_setup_host(struct sdhci_host *host) !host->ops->get_max_timeout_count) mmc->max_busy_timeout = 0; - mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; + mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23; mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 3bfbd89bd4ab..5e95bbc51644 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1394,7 +1394,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev) mmc->f_min = 400000; mmc->f_max = 52000000; mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | - MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ; + MMC_CAP_SDIO_IRQ; /* * Some H5 devices do not have signal traces precise enough to diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 9520bd94cf43..f31afd1c2671 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1128,7 +1128,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) if (ret == -EPROBE_DEFER) return ret; - mmc->caps |= MMC_CAP_ERASE | MMC_CAP_4_BIT_DATA | pdata->capabilities; + mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities; mmc->caps2 |= pdata->capabilities2; mmc->max_segs = pdata->max_segs ? : 32; mmc->max_blk_size = TMIO_MAX_BLK_SIZE; diff --git a/drivers/staging/greybus/sdio.c b/drivers/staging/greybus/sdio.c index c4b16bb5c1a4..0939f4a4c963 100644 --- a/drivers/staging/greybus/sdio.c +++ b/drivers/staging/greybus/sdio.c @@ -67,7 +67,6 @@ static void _gb_sdio_set_host_caps(struct gb_sdio_host *host, u32 r) ((r & GB_SDIO_CAP_8_BIT_DATA) ? MMC_CAP_8_BIT_DATA : 0) | ((r & GB_SDIO_CAP_MMC_HS) ? MMC_CAP_MMC_HIGHSPEED : 0) | ((r & GB_SDIO_CAP_SD_HS) ? MMC_CAP_SD_HIGHSPEED : 0) | - ((r & GB_SDIO_CAP_ERASE) ? MMC_CAP_ERASE : 0) | ((r & GB_SDIO_CAP_1_2V_DDR) ? MMC_CAP_1_2V_DDR : 0) | ((r & GB_SDIO_CAP_1_8V_DDR) ? MMC_CAP_1_8V_DDR : 0) | ((r & GB_SDIO_CAP_POWER_OFF_CARD) ? MMC_CAP_POWER_OFF_CARD : 0) | diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index d4a50e5dc111..7149bab555d7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -321,7 +321,6 @@ struct mmc_host { #define MMC_CAP_AGGRESSIVE_PM (1 << 7) /* Suspend (e)MMC/SD at idle */ #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ -#define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */ #define MMC_CAP_3_3V_DDR (1 << 11) /* Host supports eMMC DDR 3.3V */ #define MMC_CAP_1_8V_DDR (1 << 12) /* Host supports eMMC DDR 1.8V */ #define MMC_CAP_1_2V_DDR (1 << 13) /* Host supports eMMC DDR 1.2V */ From 1ae1d2d6e555e809945b691eccb1055595845a59 Mon Sep 17 00:00:00 2001 From: Ben Chuang Date: Fri, 8 May 2020 14:41:54 +0800 Subject: [PATCH 073/127] mmc: sdhci-pci-gli: Add Genesys Logic GL9763E support GL9763E supports High Speed SDR, High Speed DDR, HS200, HS400, Enhanced Strobe in HS400 mode, 1/4/8 bits data bus and 3.3/1.8V. Signed-off-by: Ben Chuang Link: https://lore.kernel.org/r/20200508064154.13473-1-benchuanggli@gmail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci-core.c | 1 + drivers/mmc/host/sdhci-pci-gli.c | 106 ++++++++++++++++++++++++++++++ drivers/mmc/host/sdhci-pci.h | 2 + 3 files changed, 109 insertions(+) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index af736afb4b91..bb6802448b2f 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -1745,6 +1745,7 @@ static const struct pci_device_id pci_ids[] = { SDHCI_PCI_DEVICE(SYNOPSYS, DWC_MSHC, snps), SDHCI_PCI_DEVICE(GLI, 9750, gl9750), SDHCI_PCI_DEVICE(GLI, 9755, gl9755), + SDHCI_PCI_DEVICE(GLI, 9763E, gl9763e), SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd), /* Generic SD host controller */ {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)}, diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index fd76aa672e02..ca0166d9bf82 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -63,6 +63,19 @@ #define SDHCI_GLI_9750_TUNING_PARAMETERS_RX_DLY GENMASK(2, 0) #define GLI_9750_TUNING_PARAMETERS_RX_DLY_VALUE 0x1 +#define SDHCI_GLI_9763E_CTRL_HS400 0x7 + +#define SDHCI_GLI_9763E_HS400_ES_REG 0x52C +#define SDHCI_GLI_9763E_HS400_ES_BIT BIT(8) + +#define PCIE_GLI_9763E_VHS 0x884 +#define GLI_9763E_VHS_REV GENMASK(19, 16) +#define GLI_9763E_VHS_REV_R 0x0 +#define GLI_9763E_VHS_REV_M 0x1 +#define GLI_9763E_VHS_REV_W 0x2 +#define PCIE_GLI_9763E_SCR 0x8E0 +#define GLI_9763E_SCR_AXI_REQ BIT(9) + #define GLI_MAX_TUNING_LOOP 40 /* Genesys Logic chipset */ @@ -351,6 +364,81 @@ static int sdhci_pci_gli_resume(struct sdhci_pci_chip *chip) } #endif +static void gl9763e_hs400_enhanced_strobe(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + u32 val; + + val = sdhci_readl(host, SDHCI_GLI_9763E_HS400_ES_REG); + if (ios->enhanced_strobe) + val |= SDHCI_GLI_9763E_HS400_ES_BIT; + else + val &= ~SDHCI_GLI_9763E_HS400_ES_BIT; + + sdhci_writel(host, val, SDHCI_GLI_9763E_HS400_ES_REG); +} + +static void sdhci_set_gl9763e_signaling(struct sdhci_host *host, + unsigned int timing) +{ + u16 ctrl_2; + + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + if (timing == MMC_TIMING_MMC_HS200) + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + else if (timing == MMC_TIMING_MMC_HS) + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + else if (timing == MMC_TIMING_MMC_DDR52) + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + else if (timing == MMC_TIMING_MMC_HS400) + ctrl_2 |= SDHCI_GLI_9763E_CTRL_HS400; + + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +} + +static void gli_set_gl9763e(struct sdhci_pci_slot *slot) +{ + struct pci_dev *pdev = slot->chip->pdev; + u32 value; + + pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); + value &= ~GLI_9763E_VHS_REV; + value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_W); + pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); + + pci_read_config_dword(pdev, PCIE_GLI_9763E_SCR, &value); + value |= GLI_9763E_SCR_AXI_REQ; + pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value); + + pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value); + value &= ~GLI_9763E_VHS_REV; + value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R); + pci_write_config_dword(pdev, PCIE_GLI_9763E_VHS, value); +} + +static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) +{ + struct sdhci_host *host = slot->host; + + host->mmc->caps |= MMC_CAP_8_BIT_DATA | + MMC_CAP_1_8V_DDR | + MMC_CAP_NONREMOVABLE; + host->mmc->caps2 |= MMC_CAP2_HS200_1_8V_SDR | + MMC_CAP2_HS400_1_8V | + MMC_CAP2_HS400_ES | + MMC_CAP2_NO_SDIO | + MMC_CAP2_NO_SD; + gli_pcie_enable_msi(slot); + host->mmc_host_ops.hs400_enhanced_strobe = + gl9763e_hs400_enhanced_strobe; + gli_set_gl9763e(slot); + sdhci_enable_v4_mode(host); + + return 0; +} + static const struct sdhci_ops sdhci_gl9755_ops = { .set_clock = sdhci_set_clock, .enable_dma = sdhci_pci_enable_dma, @@ -390,3 +478,21 @@ const struct sdhci_pci_fixes sdhci_gl9750 = { .resume = sdhci_pci_gli_resume, #endif }; + +static const struct sdhci_ops sdhci_gl9763e_ops = { + .set_clock = sdhci_set_clock, + .enable_dma = sdhci_pci_enable_dma, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_gl9763e_signaling, + .voltage_switch = sdhci_gli_voltage_switch, +}; + +const struct sdhci_pci_fixes sdhci_gl9763e = { + .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .probe_slot = gli_probe_slot_gl9763e, + .ops = &sdhci_gl9763e_ops, +#ifdef CONFIG_PM_SLEEP + .resume = sdhci_pci_gli_resume, +#endif +}; diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 42ccd123b046..d0ed232af0eb 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -72,6 +72,7 @@ #define PCI_DEVICE_ID_GLI_9755 0x9755 #define PCI_DEVICE_ID_GLI_9750 0x9750 +#define PCI_DEVICE_ID_GLI_9763E 0xe763 /* * PCI device class and mask @@ -195,5 +196,6 @@ extern const struct sdhci_pci_fixes sdhci_snps; extern const struct sdhci_pci_fixes sdhci_o2; extern const struct sdhci_pci_fixes sdhci_gl9750; extern const struct sdhci_pci_fixes sdhci_gl9755; +extern const struct sdhci_pci_fixes sdhci_gl9763e; #endif /* __SDHCI_PCI_H */ From 5d1f42e14b135773c0cc1d82e904c5b223783a9d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 11 May 2020 15:21:58 +0900 Subject: [PATCH 074/127] mmc: uniphier-sd: call devm_request_irq() after tmio_mmc_host_probe() Currently, tmio_mmc_irq() handler is registered before the host is fully initialized by tmio_mmc_host_probe(). I did not previously notice this problem. The boot ROM of a new Socionext SoC unmasks interrupts (CTL_IRQ_MASK) somehow. The handler is invoked before tmio_mmc_host_probe(), then emits noisy call trace. Move devm_request_irq() below tmio_mmc_host_probe(). Fixes: 3fd784f745dd ("mmc: uniphier-sd: add UniPhier SD/eMMC controller driver") Signed-off-by: Masahiro Yamada Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200511062158.1790924-1-yamada.masahiro@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/uniphier-sd.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c index a1683c49cb90..f82baf99fd69 100644 --- a/drivers/mmc/host/uniphier-sd.c +++ b/drivers/mmc/host/uniphier-sd.c @@ -610,11 +610,6 @@ static int uniphier_sd_probe(struct platform_device *pdev) } } - ret = devm_request_irq(dev, irq, tmio_mmc_irq, IRQF_SHARED, - dev_name(dev), host); - if (ret) - goto free_host; - if (priv->caps & UNIPHIER_SD_CAP_EXTENDED_IP) host->dma_ops = &uniphier_sd_internal_dma_ops; else @@ -642,8 +637,15 @@ static int uniphier_sd_probe(struct platform_device *pdev) if (ret) goto free_host; + ret = devm_request_irq(dev, irq, tmio_mmc_irq, IRQF_SHARED, + dev_name(dev), host); + if (ret) + goto remove_host; + return 0; +remove_host: + tmio_mmc_host_remove(host); free_host: tmio_mmc_host_free(host); From 804a65b3dfdd6d853364a835698870fb20f7a81a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 11 May 2020 15:28:27 +0900 Subject: [PATCH 075/127] mmc: sdhci: use FIELD_GET/PREP for current capabilities bit masks Use FIELD_GET and FIELD_PREP to get access to the register fields. Delete the shift macros and use GENMASK() for the touched macros. Note that, this has the side-effect of changing the constants to 64-bit on 64-bit platforms. Signed-off-by: Masahiro Yamada Link: https://lore.kernel.org/r/20200511062828.1791484-1-yamada.masahiro@socionext.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 6 +++--- drivers/mmc/host/sdhci.c | 27 ++++++++++++--------------- drivers/mmc/host/sdhci.h | 11 ++++------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 38cd83118082..9896e03fce71 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -419,9 +419,9 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { val = 0; - val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT; - val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT; - val |= 0xFF << SDHCI_MAX_CURRENT_180_SHIFT; + val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF); + val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF); + val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF); } if (unlikely(reg == SDHCI_INT_STATUS)) { diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 95cc08c1fed9..9864e877e105 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -4486,35 +4486,32 @@ int sdhci_setup_host(struct sdhci_host *host) curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT); max_current_caps = - (curr << SDHCI_MAX_CURRENT_330_SHIFT) | - (curr << SDHCI_MAX_CURRENT_300_SHIFT) | - (curr << SDHCI_MAX_CURRENT_180_SHIFT); + FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, curr) | + FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, curr) | + FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, curr); } } if (host->caps & SDHCI_CAN_VDD_330) { ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->max_current_330 = ((max_current_caps & - SDHCI_MAX_CURRENT_330_MASK) >> - SDHCI_MAX_CURRENT_330_SHIFT) * - SDHCI_MAX_CURRENT_MULTIPLIER; + mmc->max_current_330 = FIELD_GET(SDHCI_MAX_CURRENT_330_MASK, + max_current_caps) * + SDHCI_MAX_CURRENT_MULTIPLIER; } if (host->caps & SDHCI_CAN_VDD_300) { ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31; - mmc->max_current_300 = ((max_current_caps & - SDHCI_MAX_CURRENT_300_MASK) >> - SDHCI_MAX_CURRENT_300_SHIFT) * - SDHCI_MAX_CURRENT_MULTIPLIER; + mmc->max_current_300 = FIELD_GET(SDHCI_MAX_CURRENT_300_MASK, + max_current_caps) * + SDHCI_MAX_CURRENT_MULTIPLIER; } if (host->caps & SDHCI_CAN_VDD_180) { ocr_avail |= MMC_VDD_165_195; - mmc->max_current_180 = ((max_current_caps & - SDHCI_MAX_CURRENT_180_MASK) >> - SDHCI_MAX_CURRENT_180_SHIFT) * - SDHCI_MAX_CURRENT_MULTIPLIER; + mmc->max_current_180 = FIELD_GET(SDHCI_MAX_CURRENT_180_MASK, + max_current_caps) * + SDHCI_MAX_CURRENT_MULTIPLIER; } /* If OCR set by host, use it instead. */ diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 8d2a096fdfb1..257213a94d89 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -233,13 +233,10 @@ #define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ #define SDHCI_MAX_CURRENT 0x48 -#define SDHCI_MAX_CURRENT_LIMIT 0xFF -#define SDHCI_MAX_CURRENT_330_MASK 0x0000FF -#define SDHCI_MAX_CURRENT_330_SHIFT 0 -#define SDHCI_MAX_CURRENT_300_MASK 0x00FF00 -#define SDHCI_MAX_CURRENT_300_SHIFT 8 -#define SDHCI_MAX_CURRENT_180_MASK 0xFF0000 -#define SDHCI_MAX_CURRENT_180_SHIFT 16 +#define SDHCI_MAX_CURRENT_LIMIT GENMASK(7, 0) +#define SDHCI_MAX_CURRENT_330_MASK GENMASK(7, 0) +#define SDHCI_MAX_CURRENT_300_MASK GENMASK(15, 8) +#define SDHCI_MAX_CURRENT_180_MASK GENMASK(23, 16) #define SDHCI_MAX_CURRENT_MULTIPLIER 4 /* 4C-4F reserved for more max current */ From 83fc5dd57f86c3ec7d6d22565a6ff6c948853b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Mon, 11 May 2020 18:19:02 +0200 Subject: [PATCH 076/127] mmc: fix compilation of user API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The definitions of MMC_IOC_CMD and of MMC_IOC_MULTI_CMD rely on MMC_BLOCK_MAJOR: #define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd) #define MMC_IOC_MULTI_CMD _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_multi_cmd) However, MMC_BLOCK_MAJOR is defined in linux/major.h and linux/mmc/ioctl.h did not include it. Signed-off-by: Jérôme Pouiller Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200511161902.191405-1-Jerome.Pouiller@silabs.com Signed-off-by: Ulf Hansson --- include/uapi/linux/mmc/ioctl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/mmc/ioctl.h b/include/uapi/linux/mmc/ioctl.h index 00c08120f3ba..27a39847d55c 100644 --- a/include/uapi/linux/mmc/ioctl.h +++ b/include/uapi/linux/mmc/ioctl.h @@ -3,6 +3,7 @@ #define LINUX_MMC_IOCTL_H #include +#include struct mmc_ioc_cmd { /* From e5f31378862e5d0e879809bd50a84790ea14a0bc Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Tue, 12 May 2020 22:41:46 +0200 Subject: [PATCH 077/127] dt-bindings: mmc: Document the Amlogic Meson SDHC MMC host controller This documents the devicetree bindings for the SDHC MMC host controller found in Meson6, Meson8, Meson8b and Meson8m2 SoCs. It can use a bus-width of 1/4/8-bit and it supports eMMC spec 4.4x/4.5x including HS200 mode (up to 100MHz clock). It embeds an internal clock controller which outputs four clocks (mod_clk, sd_clk, tx_clk and rx_clk) and is fed by four external input clocks (clkin[0-3]). "pclk" is the module register clock, it has to be enabled to access the registers. Signed-off-by: Martin Blumenstingl Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20200512204147.504087-2-martin.blumenstingl@googlemail.com Signed-off-by: Ulf Hansson --- .../bindings/mmc/amlogic,meson-mx-sdhc.yaml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.yaml diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.yaml b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.yaml new file mode 100644 index 000000000000..7a386a5b8fcb --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdhc.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mmc/amlogic,meson-mx-sdhc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson SDHC controller Device Tree Bindings + +allOf: + - $ref: "mmc-controller.yaml" + +maintainers: + - Martin Blumenstingl + +description: | + The SDHC MMC host controller on Amlogic SoCs provides an eMMC and MMC + card interface with 1/4/8-bit bus width. + It supports eMMC spec 4.4x/4.5x including HS200 (up to 100MHz clock). + +properties: + compatible: + items: + - enum: + - amlogic,meson8-sdhc + - amlogic,meson8b-sdhc + - amlogic,meson8m2-sdhc + - const: amlogic,meson-mx-sdhc + + reg: + minItems: 1 + + interrupts: + minItems: 1 + + clocks: + minItems: 5 + + clock-names: + items: + - const: clkin0 + - const: clkin1 + - const: clkin2 + - const: clkin3 + - const: pclk + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +examples: + - | + #include + #include + + sdhc: mmc@8e00 { + compatible = "amlogic,meson8-sdhc", "amlogic,meson-mx-sdhc"; + reg = <0x8e00 0x42>; + interrupts = ; + clocks = <&xtal>, + <&fclk_div4>, + <&fclk_div3>, + <&fclk_div5>, + <&sdhc_pclk>; + clock-names = "clkin0", "clkin1", "clkin2", "clkin3", "pclk"; + }; From e4bf1b0970ef96135c78c7dcf4e14484ce3b9804 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Tue, 12 May 2020 22:41:47 +0200 Subject: [PATCH 078/127] mmc: host: meson-mx-sdhc: new driver for the Amlogic Meson SDHC host The SDHC MMC host controller on Amlogic SoCs provides an eMMC and MMC card interface with 1/4/8-bit bus width. It supports eMMC spec 4.4x/4.5x including HS200 (up to 100MHz clock). The public S805 datasheet [0] contains a short documentation about the registers. Unfortunately it does not describe how to use the registers to make the hardware work. Thus this driver is based on reading (and understanding) the Amlogic 3.10 GPL kernel code. Some hardware details are not easy to see. Jianxin Pan was kind enough to answer my questions: The hardware has built-in busy timeout support. The maximum timeout is 30 seconds. This is only documented in Amlogic's internal documentation. The controller only works with very specific clock configurations. The details are not part of the public datasheet. In my own words the supported configurations are: - 399.812kHz: clkin = 850MHz div = 2126 sd_rx_phase = 63 - 1MHz: clkin = 850MHz div = 850 sd_rx_phase = 55 - 5.986MHz: clkin = 850MHz div = 142 sd_rx_phase = 24 - 25MHz: clkin = 850MHz div = 34 sd_rx_phase = 15 - 47.222MHz: clkin = 850MHz div = 18 sd_rx_phase = 11/15 (SDR50/HS) - 53.125MHz: clkin = 850MHz div = 16 sd_rx_phase = (tuning) - 70.833MHz: clkin = 850MHz div = 12 sd_rx_phase = (tuning) - 85MHz: clkin = 850MHz div = 10 sd_rx_phase = (tuning) - 94.44MHz: clkin = 850MHz div = 9 sd_rx_phase = (tuning) - 106.25MHz: clkin = 850MHz div = 8 sd_rx_phase = (tuning) - 127.5MHz: clkin = 1275MHz div = 10 sd_rx_phase = (tuning) - 141.667MHz: clkin = 850MHz div = 6 sd_rx_phase = (tuning) - 159.375MHz: clkin = 1275MHz div = 8 sd_rx_phase = (tuning) - 212.5MHz: clkin = 1275MHz div = 6 sd_rx_phase = (tuning) - (sd_tx_phase is always 1, 94.44MHz is not listed in the datasheet but this is what the 3.10 BSP kernel on Odroid-C1 actually uses) NOTE: CMD23 support is disabled for now because it results in command timeouts and thus decreases read performance. Tested-by: Wei Wang Tested-by: Xin Yin Reviewed-by: Xin Yin Tested-by: Anand Moon Signed-off-by: Martin Blumenstingl Reviewed-by: Jerome Brunet Link: https://lore.kernel.org/r/20200512204147.504087-3-martin.blumenstingl@googlemail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 14 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/meson-mx-sdhc-clkc.c | 158 +++++ drivers/mmc/host/meson-mx-sdhc.c | 907 ++++++++++++++++++++++++++ drivers/mmc/host/meson-mx-sdhc.h | 141 ++++ 5 files changed, 1221 insertions(+) create mode 100644 drivers/mmc/host/meson-mx-sdhc-clkc.c create mode 100644 drivers/mmc/host/meson-mx-sdhc.c create mode 100644 drivers/mmc/host/meson-mx-sdhc.h diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 2aee844722d6..ee12451ba708 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -405,6 +405,20 @@ config MMC_MESON_GX If you have a controller with this interface, say Y here. +config MMC_MESON_MX_SDHC + tristate "Amlogic Meson SDHC Host Controller support" + depends on (ARM && ARCH_MESON) || COMPILE_TEST + depends on COMMON_CLK + depends on OF + help + This selects support for the SDHC Host Controller on + Amlogic Meson6, Meson8, Meson8b and Meson8m2 SoCs. + The controller supports the SD/SDIO Spec 3.x and eMMC Spec 4.5x + with 1, 4, and 8 bit bus widths. + + If you have a controller with this interface, say Y or M here. + If unsure, say N. + config MMC_MESON_MX_SDIO tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index b929ef941208..8bcb420e071c 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_MMC_VUB300) += vub300.o obj-$(CONFIG_MMC_USHC) += ushc.o obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_MESON_GX) += meson-gx-mmc.o +obj-$(CONFIG_MMC_MESON_MX_SDHC) += meson-mx-sdhc-clkc.o meson-mx-sdhc.o obj-$(CONFIG_MMC_MESON_MX_SDIO) += meson-mx-sdio.o obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o diff --git a/drivers/mmc/host/meson-mx-sdhc-clkc.c b/drivers/mmc/host/meson-mx-sdhc-clkc.c new file mode 100644 index 000000000000..ab0d6c68a078 --- /dev/null +++ b/drivers/mmc/host/meson-mx-sdhc-clkc.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson SDHC clock controller + * + * Copyright (C) 2020 Martin Blumenstingl + */ + +#include +#include +#include +#include + +#include "meson-mx-sdhc.h" + +#define MESON_SDHC_NUM_BUILTIN_CLKS 6 + +struct meson_mx_sdhc_clkc { + struct clk_mux src_sel; + struct clk_divider div; + struct clk_gate mod_clk_en; + struct clk_gate tx_clk_en; + struct clk_gate rx_clk_en; + struct clk_gate sd_clk_en; +}; + +static const struct clk_parent_data meson_mx_sdhc_src_sel_parents[4] = { + { .fw_name = "clkin0" }, + { .fw_name = "clkin1" }, + { .fw_name = "clkin2" }, + { .fw_name = "clkin3" }, +}; + +static const struct clk_div_table meson_mx_sdhc_div_table[] = { + { .div = 6, .val = 5, }, + { .div = 8, .val = 7, }, + { .div = 9, .val = 8, }, + { .div = 10, .val = 9, }, + { .div = 12, .val = 11, }, + { .div = 16, .val = 15, }, + { .div = 18, .val = 17, }, + { .div = 34, .val = 33, }, + { .div = 142, .val = 141, }, + { .div = 850, .val = 849, }, + { .div = 2126, .val = 2125, }, + { .div = 4096, .val = 4095, }, + { /* sentinel */ } +}; + +static int meson_mx_sdhc_clk_hw_register(struct device *dev, + const char *name_suffix, + const struct clk_parent_data *parents, + unsigned int num_parents, + const struct clk_ops *ops, + struct clk_hw *hw) +{ + struct clk_init_data init = { 0 }; + char clk_name[32]; + + snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dev), + name_suffix); + + init.name = clk_name; + init.ops = ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_data = parents; + init.num_parents = num_parents; + + hw->init = &init; + + return devm_clk_hw_register(dev, hw); +} + +static int meson_mx_sdhc_gate_clk_hw_register(struct device *dev, + const char *name_suffix, + struct clk_hw *parent, + struct clk_hw *hw) +{ + struct clk_parent_data parent_data = { .hw = parent }; + + return meson_mx_sdhc_clk_hw_register(dev, name_suffix, &parent_data, 1, + &clk_gate_ops, hw); +} + +int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base, + struct clk_bulk_data *clk_bulk_data) +{ + struct clk_parent_data div_parent = { 0 }; + struct meson_mx_sdhc_clkc *clkc_data; + int ret; + + clkc_data = devm_kzalloc(dev, sizeof(*clkc_data), GFP_KERNEL); + if (!clkc_data) + return -ENOMEM; + + clkc_data->src_sel.reg = base + MESON_SDHC_CLKC; + clkc_data->src_sel.mask = 0x3; + clkc_data->src_sel.shift = 16; + ret = meson_mx_sdhc_clk_hw_register(dev, "src_sel", + meson_mx_sdhc_src_sel_parents, 4, + &clk_mux_ops, + &clkc_data->src_sel.hw); + if (ret) + return ret; + + clkc_data->div.reg = base + MESON_SDHC_CLKC; + clkc_data->div.shift = 0; + clkc_data->div.width = 12; + clkc_data->div.table = meson_mx_sdhc_div_table; + div_parent.hw = &clkc_data->src_sel.hw; + ret = meson_mx_sdhc_clk_hw_register(dev, "div", &div_parent, 1, + &clk_divider_ops, + &clkc_data->div.hw); + if (ret) + return ret; + + clkc_data->mod_clk_en.reg = base + MESON_SDHC_CLKC; + clkc_data->mod_clk_en.bit_idx = 15; + ret = meson_mx_sdhc_gate_clk_hw_register(dev, "mod_clk_on", + &clkc_data->div.hw, + &clkc_data->mod_clk_en.hw); + if (ret) + return ret; + + clkc_data->tx_clk_en.reg = base + MESON_SDHC_CLKC; + clkc_data->tx_clk_en.bit_idx = 14; + ret = meson_mx_sdhc_gate_clk_hw_register(dev, "tx_clk_on", + &clkc_data->div.hw, + &clkc_data->tx_clk_en.hw); + if (ret) + return ret; + + clkc_data->rx_clk_en.reg = base + MESON_SDHC_CLKC; + clkc_data->rx_clk_en.bit_idx = 13; + ret = meson_mx_sdhc_gate_clk_hw_register(dev, "rx_clk_on", + &clkc_data->div.hw, + &clkc_data->rx_clk_en.hw); + if (ret) + return ret; + + clkc_data->sd_clk_en.reg = base + MESON_SDHC_CLKC; + clkc_data->sd_clk_en.bit_idx = 12; + ret = meson_mx_sdhc_gate_clk_hw_register(dev, "sd_clk_on", + &clkc_data->div.hw, + &clkc_data->sd_clk_en.hw); + if (ret) + return ret; + + /* + * TODO: Replace clk_hw.clk with devm_clk_hw_get_clk() once that is + * available. + */ + clk_bulk_data[0].clk = clkc_data->mod_clk_en.hw.clk; + clk_bulk_data[1].clk = clkc_data->sd_clk_en.hw.clk; + clk_bulk_data[2].clk = clkc_data->tx_clk_en.hw.clk; + clk_bulk_data[3].clk = clkc_data->rx_clk_en.hw.clk; + + return 0; +} diff --git a/drivers/mmc/host/meson-mx-sdhc.c b/drivers/mmc/host/meson-mx-sdhc.c new file mode 100644 index 000000000000..5c00958d7754 --- /dev/null +++ b/drivers/mmc/host/meson-mx-sdhc.c @@ -0,0 +1,907 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson6/Meson8/Meson8b/Meson8m2 SDHC MMC host controller driver. + * + * Copyright (C) 2020 Martin Blumenstingl + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "meson-mx-sdhc.h" + +#define MESON_SDHC_NUM_BULK_CLKS 4 +#define MESON_SDHC_MAX_BLK_SIZE 512 +#define MESON_SDHC_NUM_TUNING_TRIES 10 + +#define MESON_SDHC_WAIT_CMD_READY_SLEEP_US 1 +#define MESON_SDHC_WAIT_CMD_READY_TIMEOUT_US 100000 +#define MESON_SDHC_WAIT_BEFORE_SEND_SLEEP_US 1 +#define MESON_SDHC_WAIT_BEFORE_SEND_TIMEOUT_US 200 + +struct meson_mx_sdhc_data { + void (*init_hw)(struct mmc_host *mmc); + void (*set_pdma)(struct mmc_host *mmc); + void (*wait_before_send)(struct mmc_host *mmc); + bool hardware_flush_all_cmds; +}; + +struct meson_mx_sdhc_host { + struct mmc_host *mmc; + + struct mmc_request *mrq; + struct mmc_command *cmd; + int error; + + struct regmap *regmap; + + struct clk *pclk; + struct clk *sd_clk; + struct clk_bulk_data bulk_clks[MESON_SDHC_NUM_BULK_CLKS]; + bool bulk_clks_enabled; + + const struct meson_mx_sdhc_data *platform; +}; + +static const struct regmap_config meson_mx_sdhc_regmap_config = { + .reg_bits = 8, + .val_bits = 32, + .reg_stride = 4, + .max_register = MESON_SDHC_CLK2, +}; + +static void meson_mx_sdhc_hw_reset(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + + regmap_write(host->regmap, MESON_SDHC_SRST, MESON_SDHC_SRST_MAIN_CTRL | + MESON_SDHC_SRST_RXFIFO | MESON_SDHC_SRST_TXFIFO | + MESON_SDHC_SRST_DPHY_RX | MESON_SDHC_SRST_DPHY_TX | + MESON_SDHC_SRST_DMA_IF); + usleep_range(10, 100); + + regmap_write(host->regmap, MESON_SDHC_SRST, 0); + usleep_range(10, 100); +} + +static void meson_mx_sdhc_clear_fifo(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + u32 stat; + + regmap_read(host->regmap, MESON_SDHC_STAT, &stat); + if (!FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat) && + !FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat)) + return; + + regmap_write(host->regmap, MESON_SDHC_SRST, MESON_SDHC_SRST_RXFIFO | + MESON_SDHC_SRST_TXFIFO | MESON_SDHC_SRST_MAIN_CTRL); + udelay(5); + + regmap_read(host->regmap, MESON_SDHC_STAT, &stat); + if (FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat) || + FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat)) + dev_warn(mmc_dev(host->mmc), + "Failed to clear FIFOs, RX: %lu, TX: %lu\n", + FIELD_GET(MESON_SDHC_STAT_RXFIFO_CNT, stat), + FIELD_GET(MESON_SDHC_STAT_TXFIFO_CNT, stat)); +} + +static void meson_mx_sdhc_wait_cmd_ready(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + u32 stat, esta; + int ret; + + ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_STAT, stat, + !(stat & MESON_SDHC_STAT_CMD_BUSY), + MESON_SDHC_WAIT_CMD_READY_SLEEP_US, + MESON_SDHC_WAIT_CMD_READY_TIMEOUT_US); + if (ret) { + dev_warn(mmc_dev(mmc), + "Failed to poll for CMD_BUSY while processing CMD%d\n", + host->cmd->opcode); + meson_mx_sdhc_hw_reset(mmc); + } + + ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_ESTA, esta, + !(esta & MESON_SDHC_ESTA_11_13), + MESON_SDHC_WAIT_CMD_READY_SLEEP_US, + MESON_SDHC_WAIT_CMD_READY_TIMEOUT_US); + if (ret) { + dev_warn(mmc_dev(mmc), + "Failed to poll for ESTA[13:11] while processing CMD%d\n", + host->cmd->opcode); + meson_mx_sdhc_hw_reset(mmc); + } +} + +static void meson_mx_sdhc_start_cmd(struct mmc_host *mmc, + struct mmc_command *cmd) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + u32 ictl, send; + int pack_len; + + host->cmd = cmd; + + ictl = MESON_SDHC_ICTL_DATA_TIMEOUT | MESON_SDHC_ICTL_DATA_ERR_CRC | + MESON_SDHC_ICTL_RXFIFO_FULL | MESON_SDHC_ICTL_TXFIFO_EMPTY | + MESON_SDHC_ICTL_RESP_TIMEOUT | MESON_SDHC_ICTL_RESP_ERR_CRC; + + send = FIELD_PREP(MESON_SDHC_SEND_CMD_INDEX, cmd->opcode); + + if (cmd->data) { + send |= MESON_SDHC_SEND_CMD_HAS_DATA; + send |= FIELD_PREP(MESON_SDHC_SEND_TOTAL_PACK, + cmd->data->blocks - 1); + + if (cmd->data->blksz < MESON_SDHC_MAX_BLK_SIZE) + pack_len = cmd->data->blksz; + else + pack_len = 0; + + if (cmd->data->flags & MMC_DATA_WRITE) + send |= MESON_SDHC_SEND_DATA_DIR; + + /* + * If command with no data, just wait response done + * interrupt(int[0]), and if command with data transfer, just + * wait dma done interrupt(int[11]), don't need care about + * dat0 busy or not. + */ + if (host->platform->hardware_flush_all_cmds || + cmd->data->flags & MMC_DATA_WRITE) + /* hardware flush: */ + ictl |= MESON_SDHC_ICTL_DMA_DONE; + else + /* software flush: */ + ictl |= MESON_SDHC_ICTL_DATA_XFER_OK; + } else { + pack_len = 0; + + ictl |= MESON_SDHC_ICTL_RESP_OK; + } + + if (cmd->opcode == MMC_STOP_TRANSMISSION) + send |= MESON_SDHC_SEND_DATA_STOP; + + if (cmd->flags & MMC_RSP_PRESENT) + send |= MESON_SDHC_SEND_CMD_HAS_RESP; + + if (cmd->flags & MMC_RSP_136) { + send |= MESON_SDHC_SEND_RESP_LEN; + send |= MESON_SDHC_SEND_RESP_NO_CRC; + } + + if (!(cmd->flags & MMC_RSP_CRC)) + send |= MESON_SDHC_SEND_RESP_NO_CRC; + + if (cmd->flags & MMC_RSP_BUSY) + send |= MESON_SDHC_SEND_R1B; + + /* enable the new IRQs and mask all pending ones */ + regmap_write(host->regmap, MESON_SDHC_ICTL, ictl); + regmap_write(host->regmap, MESON_SDHC_ISTA, MESON_SDHC_ISTA_ALL_IRQS); + + regmap_write(host->regmap, MESON_SDHC_ARGU, cmd->arg); + + regmap_update_bits(host->regmap, MESON_SDHC_CTRL, + MESON_SDHC_CTRL_PACK_LEN, + FIELD_PREP(MESON_SDHC_CTRL_PACK_LEN, pack_len)); + + if (cmd->data) + regmap_write(host->regmap, MESON_SDHC_ADDR, + sg_dma_address(cmd->data->sg)); + + meson_mx_sdhc_wait_cmd_ready(mmc); + + if (cmd->data) + host->platform->set_pdma(mmc); + + if (host->platform->wait_before_send) + host->platform->wait_before_send(mmc); + + regmap_write(host->regmap, MESON_SDHC_SEND, send); +} + +static void meson_mx_sdhc_disable_clks(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + + if (!host->bulk_clks_enabled) + return; + + clk_bulk_disable_unprepare(MESON_SDHC_NUM_BULK_CLKS, host->bulk_clks); + + host->bulk_clks_enabled = false; +} + +static int meson_mx_sdhc_enable_clks(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + int ret; + + if (host->bulk_clks_enabled) + return 0; + + ret = clk_bulk_prepare_enable(MESON_SDHC_NUM_BULK_CLKS, + host->bulk_clks); + if (ret) + return ret; + + host->bulk_clks_enabled = true; + + return 0; +} + +static int meson_mx_sdhc_set_clk(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + u32 rx_clk_phase; + int ret; + + meson_mx_sdhc_disable_clks(mmc); + + if (ios->clock) { + ret = clk_set_rate(host->sd_clk, ios->clock); + if (ret) { + dev_warn(mmc_dev(mmc), + "Failed to set MMC clock to %uHz: %d\n", + ios->clock, host->error); + return ret; + } + + ret = meson_mx_sdhc_enable_clks(mmc); + if (ret) + return ret; + + mmc->actual_clock = clk_get_rate(host->sd_clk); + + /* + * according to Amlogic the following latching points are + * selected with empirical values, there is no (known) formula + * to calculate these. + */ + if (mmc->actual_clock > 100000000) { + rx_clk_phase = 1; + } else if (mmc->actual_clock > 45000000) { + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) + rx_clk_phase = 15; + else + rx_clk_phase = 11; + } else if (mmc->actual_clock >= 25000000) { + rx_clk_phase = 15; + } else if (mmc->actual_clock > 5000000) { + rx_clk_phase = 23; + } else if (mmc->actual_clock > 1000000) { + rx_clk_phase = 55; + } else { + rx_clk_phase = 1061; + } + + regmap_update_bits(host->regmap, MESON_SDHC_CLK2, + MESON_SDHC_CLK2_RX_CLK_PHASE, + FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE, + rx_clk_phase)); + } else { + mmc->actual_clock = 0; + } + + return 0; +} + +static void meson_mx_sdhc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + unsigned short vdd = ios->vdd; + + switch (ios->power_mode) { + case MMC_POWER_OFF: + vdd = 0; + fallthrough; + + case MMC_POWER_UP: + if (!IS_ERR(mmc->supply.vmmc)) { + host->error = mmc_regulator_set_ocr(mmc, + mmc->supply.vmmc, + vdd); + if (host->error) + return; + } + + break; + + case MMC_POWER_ON: + break; + } + + host->error = meson_mx_sdhc_set_clk(mmc, ios); + if (host->error) + return; + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + regmap_update_bits(host->regmap, MESON_SDHC_CTRL, + MESON_SDHC_CTRL_DAT_TYPE, + FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 0)); + break; + + case MMC_BUS_WIDTH_4: + regmap_update_bits(host->regmap, MESON_SDHC_CTRL, + MESON_SDHC_CTRL_DAT_TYPE, + FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 1)); + break; + + case MMC_BUS_WIDTH_8: + regmap_update_bits(host->regmap, MESON_SDHC_CTRL, + MESON_SDHC_CTRL_DAT_TYPE, + FIELD_PREP(MESON_SDHC_CTRL_DAT_TYPE, 2)); + break; + + default: + dev_err(mmc_dev(mmc), "unsupported bus width: %d\n", + ios->bus_width); + host->error = -EINVAL; + return; + } +} + +static int meson_mx_sdhc_map_dma(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mmc_data *data = mrq->data; + int dma_len; + + if (!data) + return 0; + + dma_len = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, + mmc_get_dma_dir(data)); + if (dma_len <= 0) { + dev_err(mmc_dev(mmc), "dma_map_sg failed\n"); + return -ENOMEM; + } + + return 0; +} + +static void meson_mx_sdhc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + struct mmc_command *cmd = mrq->cmd; + + if (!host->error) + host->error = meson_mx_sdhc_map_dma(mmc, mrq); + + if (host->error) { + cmd->error = host->error; + mmc_request_done(mmc, mrq); + return; + } + + host->mrq = mrq; + + meson_mx_sdhc_start_cmd(mmc, mrq->cmd); +} + +static int meson_mx_sdhc_card_busy(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + u32 stat; + + regmap_read(host->regmap, MESON_SDHC_STAT, &stat); + return FIELD_GET(MESON_SDHC_STAT_DAT3_0, stat) == 0; +} + +static bool meson_mx_sdhc_tuning_point_matches(struct mmc_host *mmc, + u32 opcode) +{ + unsigned int i, num_matches = 0; + int ret; + + for (i = 0; i < MESON_SDHC_NUM_TUNING_TRIES; i++) { + ret = mmc_send_tuning(mmc, opcode, NULL); + if (!ret) + num_matches++; + } + + return num_matches == MESON_SDHC_NUM_TUNING_TRIES; +} + +static int meson_mx_sdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + int div, start, len, best_start, best_len; + int curr_phase, old_phase, new_phase; + u32 val; + + len = 0; + start = 0; + best_len = 0; + + regmap_read(host->regmap, MESON_SDHC_CLK2, &val); + old_phase = FIELD_GET(MESON_SDHC_CLK2_RX_CLK_PHASE, val); + + regmap_read(host->regmap, MESON_SDHC_CLKC, &val); + div = FIELD_GET(MESON_SDHC_CLKC_CLK_DIV, val); + + for (curr_phase = 0; curr_phase <= div; curr_phase++) { + regmap_update_bits(host->regmap, MESON_SDHC_CLK2, + MESON_SDHC_CLK2_RX_CLK_PHASE, + FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE, + curr_phase)); + + if (meson_mx_sdhc_tuning_point_matches(mmc, opcode)) { + if (!len) { + start = curr_phase; + + dev_dbg(mmc_dev(mmc), + "New RX phase window starts at %u\n", + start); + } + + len++; + } else { + if (len > best_len) { + best_start = start; + best_len = len; + + dev_dbg(mmc_dev(mmc), + "New best RX phase window: %u - %u\n", + best_start, best_start + best_len); + } + + /* reset the current window */ + len = 0; + } + } + + if (len > best_len) + /* the last window is the best (or possibly only) window */ + new_phase = start + (len / 2); + else if (best_len) + /* there was a better window than the last */ + new_phase = best_start + (best_len / 2); + else + /* no window was found at all, reset to the original phase */ + new_phase = old_phase; + + regmap_update_bits(host->regmap, MESON_SDHC_CLK2, + MESON_SDHC_CLK2_RX_CLK_PHASE, + FIELD_PREP(MESON_SDHC_CLK2_RX_CLK_PHASE, + new_phase)); + + if (!len && !best_len) + return -EIO; + + dev_dbg(mmc_dev(mmc), "Tuned RX clock phase to %u\n", new_phase); + + return 0; +} + +static const struct mmc_host_ops meson_mx_sdhc_ops = { + .hw_reset = meson_mx_sdhc_hw_reset, + .request = meson_mx_sdhc_request, + .set_ios = meson_mx_sdhc_set_ios, + .card_busy = meson_mx_sdhc_card_busy, + .execute_tuning = meson_mx_sdhc_execute_tuning, + .get_cd = mmc_gpio_get_cd, + .get_ro = mmc_gpio_get_ro, +}; + +static void meson_mx_sdhc_request_done(struct meson_mx_sdhc_host *host) +{ + struct mmc_request *mrq = host->mrq; + struct mmc_host *mmc = host->mmc; + + /* disable interrupts and mask all pending ones */ + regmap_update_bits(host->regmap, MESON_SDHC_ICTL, + MESON_SDHC_ICTL_ALL_IRQS, 0); + regmap_update_bits(host->regmap, MESON_SDHC_ISTA, + MESON_SDHC_ISTA_ALL_IRQS, MESON_SDHC_ISTA_ALL_IRQS); + + host->mrq = NULL; + host->cmd = NULL; + + mmc_request_done(mmc, mrq); +} + +static u32 meson_mx_sdhc_read_response(struct meson_mx_sdhc_host *host, u8 idx) +{ + u32 val; + + regmap_update_bits(host->regmap, MESON_SDHC_PDMA, + MESON_SDHC_PDMA_DMA_MODE, 0); + + regmap_update_bits(host->regmap, MESON_SDHC_PDMA, + MESON_SDHC_PDMA_PIO_RDRESP, + FIELD_PREP(MESON_SDHC_PDMA_PIO_RDRESP, idx)); + + regmap_read(host->regmap, MESON_SDHC_ARGU, &val); + + return val; +} + +static irqreturn_t meson_mx_sdhc_irq(int irq, void *data) +{ + struct meson_mx_sdhc_host *host = data; + struct mmc_command *cmd = host->cmd; + u32 ictl, ista; + + regmap_read(host->regmap, MESON_SDHC_ICTL, &ictl); + regmap_read(host->regmap, MESON_SDHC_ISTA, &ista); + + if (!(ictl & ista)) + return IRQ_NONE; + + if (ista & MESON_SDHC_ISTA_RXFIFO_FULL || + ista & MESON_SDHC_ISTA_TXFIFO_EMPTY) + cmd->error = -EIO; + else if (ista & MESON_SDHC_ISTA_RESP_ERR_CRC) + cmd->error = -EILSEQ; + else if (ista & MESON_SDHC_ISTA_RESP_TIMEOUT) + cmd->error = -ETIMEDOUT; + + if (cmd->data) { + if (ista & MESON_SDHC_ISTA_DATA_ERR_CRC) + cmd->data->error = -EILSEQ; + else if (ista & MESON_SDHC_ISTA_DATA_TIMEOUT) + cmd->data->error = -ETIMEDOUT; + } + + if (cmd->error || (cmd->data && cmd->data->error)) + dev_dbg(mmc_dev(host->mmc), "CMD%d error, ISTA: 0x%08x\n", + cmd->opcode, ista); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t meson_mx_sdhc_irq_thread(int irq, void *irq_data) +{ + struct meson_mx_sdhc_host *host = irq_data; + struct mmc_command *cmd; + u32 val; + + cmd = host->cmd; + if (WARN_ON(!cmd)) + return IRQ_HANDLED; + + if (cmd->data && !cmd->data->error) { + if (!host->platform->hardware_flush_all_cmds && + cmd->data->flags & MMC_DATA_READ) { + meson_mx_sdhc_wait_cmd_ready(host->mmc); + + val = FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH, + 2); + regmap_update_bits(host->regmap, MESON_SDHC_PDMA, + MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH, + val); + } + + dma_unmap_sg(mmc_dev(host->mmc), cmd->data->sg, + cmd->data->sg_len, mmc_get_dma_dir(cmd->data)); + + cmd->data->bytes_xfered = cmd->data->blksz * cmd->data->blocks; + } + + meson_mx_sdhc_wait_cmd_ready(host->mmc); + + if (cmd->flags & MMC_RSP_136) { + cmd->resp[0] = meson_mx_sdhc_read_response(host, 4); + cmd->resp[1] = meson_mx_sdhc_read_response(host, 3); + cmd->resp[2] = meson_mx_sdhc_read_response(host, 2); + cmd->resp[3] = meson_mx_sdhc_read_response(host, 1); + } else { + cmd->resp[0] = meson_mx_sdhc_read_response(host, 0); + } + + if (cmd->error == -EIO || cmd->error == -ETIMEDOUT) + meson_mx_sdhc_hw_reset(host->mmc); + else if (cmd->data) + /* + * Clear the FIFOs after completing data transfers to prevent + * corrupting data on write access. It's not clear why this is + * needed (for reads and writes), but it mimics what the BSP + * kernel did. + */ + meson_mx_sdhc_clear_fifo(host->mmc); + + meson_mx_sdhc_request_done(host); + + return IRQ_HANDLED; +} + +static void meson_mx_sdhc_init_hw_meson8(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + + regmap_write(host->regmap, MESON_SDHC_MISC, + FIELD_PREP(MESON_SDHC_MISC_TXSTART_THRES, 7) | + FIELD_PREP(MESON_SDHC_MISC_WCRC_ERR_PATT, 5) | + FIELD_PREP(MESON_SDHC_MISC_WCRC_OK_PATT, 2)); + + regmap_write(host->regmap, MESON_SDHC_ENHC, + FIELD_PREP(MESON_SDHC_ENHC_RXFIFO_TH, 63) | + MESON_SDHC_ENHC_MESON6_DMA_WR_RESP | + FIELD_PREP(MESON_SDHC_ENHC_MESON6_RX_TIMEOUT, 255) | + FIELD_PREP(MESON_SDHC_ENHC_SDIO_IRQ_PERIOD, 12)); +}; + +static void meson_mx_sdhc_set_pdma_meson8(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + + if (host->cmd->data->flags & MMC_DATA_WRITE) + regmap_update_bits(host->regmap, MESON_SDHC_PDMA, + MESON_SDHC_PDMA_DMA_MODE | + MESON_SDHC_PDMA_RD_BURST | + MESON_SDHC_PDMA_TXFIFO_FILL, + MESON_SDHC_PDMA_DMA_MODE | + FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 31) | + MESON_SDHC_PDMA_TXFIFO_FILL); + else + regmap_update_bits(host->regmap, MESON_SDHC_PDMA, + MESON_SDHC_PDMA_DMA_MODE | + MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH, + MESON_SDHC_PDMA_DMA_MODE | + FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH, + 1)); + + if (host->cmd->data->flags & MMC_DATA_WRITE) + regmap_update_bits(host->regmap, MESON_SDHC_PDMA, + MESON_SDHC_PDMA_RD_BURST, + FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 15)); +} + +static void meson_mx_sdhc_wait_before_send_meson8(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + u32 val; + int ret; + + ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_ESTA, val, + val == 0, + MESON_SDHC_WAIT_BEFORE_SEND_SLEEP_US, + MESON_SDHC_WAIT_BEFORE_SEND_TIMEOUT_US); + if (ret) + dev_warn(mmc_dev(mmc), + "Failed to wait for ESTA to clear: 0x%08x\n", val); + + if (host->cmd->data && host->cmd->data->flags & MMC_DATA_WRITE) { + ret = regmap_read_poll_timeout(host->regmap, MESON_SDHC_STAT, + val, val & MESON_SDHC_STAT_TXFIFO_CNT, + MESON_SDHC_WAIT_BEFORE_SEND_SLEEP_US, + MESON_SDHC_WAIT_BEFORE_SEND_TIMEOUT_US); + if (ret) + dev_warn(mmc_dev(mmc), + "Failed to wait for TX FIFO to fill\n"); + } +} + +static void meson_mx_sdhc_init_hw_meson8m2(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + + regmap_write(host->regmap, MESON_SDHC_MISC, + FIELD_PREP(MESON_SDHC_MISC_TXSTART_THRES, 6) | + FIELD_PREP(MESON_SDHC_MISC_WCRC_ERR_PATT, 5) | + FIELD_PREP(MESON_SDHC_MISC_WCRC_OK_PATT, 2)); + + regmap_write(host->regmap, MESON_SDHC_ENHC, + FIELD_PREP(MESON_SDHC_ENHC_RXFIFO_TH, 64) | + FIELD_PREP(MESON_SDHC_ENHC_MESON8M2_DEBUG, 1) | + MESON_SDHC_ENHC_MESON8M2_WRRSP_MODE | + FIELD_PREP(MESON_SDHC_ENHC_SDIO_IRQ_PERIOD, 12)); +} + +static void meson_mx_sdhc_set_pdma_meson8m2(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + + regmap_update_bits(host->regmap, MESON_SDHC_PDMA, + MESON_SDHC_PDMA_DMA_MODE, MESON_SDHC_PDMA_DMA_MODE); +} + +static void meson_mx_sdhc_init_hw(struct mmc_host *mmc) +{ + struct meson_mx_sdhc_host *host = mmc_priv(mmc); + + meson_mx_sdhc_hw_reset(mmc); + + regmap_write(host->regmap, MESON_SDHC_CTRL, + FIELD_PREP(MESON_SDHC_CTRL_RX_PERIOD, 0xf) | + FIELD_PREP(MESON_SDHC_CTRL_RX_TIMEOUT, 0x7f) | + FIELD_PREP(MESON_SDHC_CTRL_RX_ENDIAN, 0x7) | + FIELD_PREP(MESON_SDHC_CTRL_TX_ENDIAN, 0x7)); + + /* + * start with a valid divider and enable the memory (un-setting + * MESON_SDHC_CLKC_MEM_PWR_OFF). + */ + regmap_write(host->regmap, MESON_SDHC_CLKC, MESON_SDHC_CLKC_CLK_DIV); + + regmap_write(host->regmap, MESON_SDHC_CLK2, + FIELD_PREP(MESON_SDHC_CLK2_SD_CLK_PHASE, 1)); + + regmap_write(host->regmap, MESON_SDHC_PDMA, + MESON_SDHC_PDMA_DMA_URGENT | + FIELD_PREP(MESON_SDHC_PDMA_WR_BURST, 7) | + FIELD_PREP(MESON_SDHC_PDMA_TXFIFO_TH, 49) | + FIELD_PREP(MESON_SDHC_PDMA_RD_BURST, 15) | + FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_TH, 7)); + + /* some initialization bits depend on the SoC: */ + host->platform->init_hw(mmc); + + /* disable and mask all interrupts: */ + regmap_write(host->regmap, MESON_SDHC_ICTL, 0); + regmap_write(host->regmap, MESON_SDHC_ISTA, MESON_SDHC_ISTA_ALL_IRQS); +} + +static int meson_mx_sdhc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct meson_mx_sdhc_host *host; + struct mmc_host *mmc; + void __iomem *base; + int ret, irq; + + mmc = mmc_alloc_host(sizeof(*host), dev); + if (!mmc) + return -ENOMEM; + + ret = devm_add_action_or_reset(dev, (void(*)(void *))mmc_free_host, + mmc); + if (ret) { + dev_err(dev, "Failed to register mmc_free_host action\n"); + return ret; + } + + host = mmc_priv(mmc); + host->mmc = mmc; + + platform_set_drvdata(pdev, host); + + host->platform = device_get_match_data(dev); + if (!host->platform) + return -EINVAL; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + host->regmap = devm_regmap_init_mmio(dev, base, + &meson_mx_sdhc_regmap_config); + if (IS_ERR(host->regmap)) + return PTR_ERR(host->regmap); + + host->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(host->pclk)) + return PTR_ERR(host->pclk); + + /* accessing any register requires the module clock to be enabled: */ + ret = clk_prepare_enable(host->pclk); + if (ret) { + dev_err(dev, "Failed to enable 'pclk' clock\n"); + return ret; + } + + meson_mx_sdhc_init_hw(mmc); + + ret = meson_mx_sdhc_register_clkc(dev, base, host->bulk_clks); + if (ret) + goto err_disable_pclk; + + host->sd_clk = host->bulk_clks[1].clk; + + /* Get regulators and the supported OCR mask */ + ret = mmc_regulator_get_supply(mmc); + if (ret) + goto err_disable_pclk; + + mmc->max_req_size = SZ_128K; + mmc->max_seg_size = mmc->max_req_size; + mmc->max_blk_count = FIELD_GET(MESON_SDHC_SEND_TOTAL_PACK, ~0); + mmc->max_blk_size = MESON_SDHC_MAX_BLK_SIZE; + mmc->max_busy_timeout = 30 * MSEC_PER_SEC; + mmc->f_min = clk_round_rate(host->sd_clk, 1); + mmc->f_max = clk_round_rate(host->sd_clk, ULONG_MAX); + mmc->max_current_180 = 300; + mmc->max_current_330 = 300; + mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_HW_RESET; + mmc->ops = &meson_mx_sdhc_ops; + + ret = mmc_of_parse(mmc); + if (ret) + goto err_disable_pclk; + + irq = platform_get_irq(pdev, 0); + ret = devm_request_threaded_irq(dev, irq, meson_mx_sdhc_irq, + meson_mx_sdhc_irq_thread, IRQF_ONESHOT, + NULL, host); + if (ret) + goto err_disable_pclk; + + ret = mmc_add_host(mmc); + if (ret) + goto err_disable_pclk; + + return 0; + +err_disable_pclk: + clk_disable_unprepare(host->pclk); + return ret; +} + +static int meson_mx_sdhc_remove(struct platform_device *pdev) +{ + struct meson_mx_sdhc_host *host = platform_get_drvdata(pdev); + + mmc_remove_host(host->mmc); + + meson_mx_sdhc_disable_clks(host->mmc); + + clk_disable_unprepare(host->pclk); + + return 0; +} + +static const struct meson_mx_sdhc_data meson_mx_sdhc_data_meson8 = { + .init_hw = meson_mx_sdhc_init_hw_meson8, + .set_pdma = meson_mx_sdhc_set_pdma_meson8, + .wait_before_send = meson_mx_sdhc_wait_before_send_meson8, + .hardware_flush_all_cmds = false, +}; + +static const struct meson_mx_sdhc_data meson_mx_sdhc_data_meson8m2 = { + .init_hw = meson_mx_sdhc_init_hw_meson8m2, + .set_pdma = meson_mx_sdhc_set_pdma_meson8m2, + .hardware_flush_all_cmds = true, +}; + +static const struct of_device_id meson_mx_sdhc_of_match[] = { + { + .compatible = "amlogic,meson8-sdhc", + .data = &meson_mx_sdhc_data_meson8 + }, + { + .compatible = "amlogic,meson8b-sdhc", + .data = &meson_mx_sdhc_data_meson8 + }, + { + .compatible = "amlogic,meson8m2-sdhc", + .data = &meson_mx_sdhc_data_meson8m2 + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, meson_mx_sdhc_of_match); + +static struct platform_driver meson_mx_sdhc_driver = { + .probe = meson_mx_sdhc_probe, + .remove = meson_mx_sdhc_remove, + .driver = { + .name = "meson-mx-sdhc", + .of_match_table = of_match_ptr(meson_mx_sdhc_of_match), + }, +}; + +module_platform_driver(meson_mx_sdhc_driver); + +MODULE_DESCRIPTION("Meson6, Meson8, Meson8b and Meson8m2 SDHC Host Driver"); +MODULE_AUTHOR("Martin Blumenstingl "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/meson-mx-sdhc.h b/drivers/mmc/host/meson-mx-sdhc.h new file mode 100644 index 000000000000..230e8fbe6b3f --- /dev/null +++ b/drivers/mmc/host/meson-mx-sdhc.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2020 Martin Blumenstingl + */ + +#ifndef _MESON_MX_SDHC_H_ +#define _MESON_MX_SDHC_H_ + +#include + +#define MESON_SDHC_ARGU 0x00 + +#define MESON_SDHC_SEND 0x04 + #define MESON_SDHC_SEND_CMD_INDEX GENMASK(5, 0) + #define MESON_SDHC_SEND_CMD_HAS_RESP BIT(6) + #define MESON_SDHC_SEND_CMD_HAS_DATA BIT(7) + #define MESON_SDHC_SEND_RESP_LEN BIT(8) + #define MESON_SDHC_SEND_RESP_NO_CRC BIT(9) + #define MESON_SDHC_SEND_DATA_DIR BIT(10) + #define MESON_SDHC_SEND_DATA_STOP BIT(11) + #define MESON_SDHC_SEND_R1B BIT(12) + #define MESON_SDHC_SEND_TOTAL_PACK GENMASK(31, 16) + +#define MESON_SDHC_CTRL 0x08 + #define MESON_SDHC_CTRL_DAT_TYPE GENMASK(1, 0) + #define MESON_SDHC_CTRL_DDR_MODE BIT(2) + #define MESON_SDHC_CTRL_TX_CRC_NOCHECK BIT(3) + #define MESON_SDHC_CTRL_PACK_LEN GENMASK(12, 4) + #define MESON_SDHC_CTRL_RX_TIMEOUT GENMASK(19, 13) + #define MESON_SDHC_CTRL_RX_PERIOD GENMASK(23, 20) + #define MESON_SDHC_CTRL_RX_ENDIAN GENMASK(26, 24) + #define MESON_SDHC_CTRL_SDIO_IRQ_MODE BIT(27) + #define MESON_SDHC_CTRL_DAT0_IRQ_SEL BIT(28) + #define MESON_SDHC_CTRL_TX_ENDIAN GENMASK(31, 29) + +#define MESON_SDHC_STAT 0x0c + #define MESON_SDHC_STAT_CMD_BUSY BIT(0) + #define MESON_SDHC_STAT_DAT3_0 GENMASK(4, 1) + #define MESON_SDHC_STAT_CMD BIT(5) + #define MESON_SDHC_STAT_RXFIFO_CNT GENMASK(12, 6) + #define MESON_SDHC_STAT_TXFIFO_CNT GENMASK(19, 13) + #define MESON_SDHC_STAT_DAT7_4 GENMASK(23, 20) + +#define MESON_SDHC_CLKC 0x10 + #define MESON_SDHC_CLKC_CLK_DIV GENMASK(11, 0) + #define MESON_SDHC_CLKC_CLK_JIC BIT(24) + #define MESON_SDHC_CLKC_MEM_PWR_OFF GENMASK(26, 25) + +#define MESON_SDHC_ADDR 0x14 + +#define MESON_SDHC_PDMA 0x18 + #define MESON_SDHC_PDMA_DMA_MODE BIT(0) + #define MESON_SDHC_PDMA_PIO_RDRESP GENMASK(3, 1) + #define MESON_SDHC_PDMA_DMA_URGENT BIT(4) + #define MESON_SDHC_PDMA_WR_BURST GENMASK(9, 5) + #define MESON_SDHC_PDMA_RD_BURST GENMASK(14, 10) + #define MESON_SDHC_PDMA_RXFIFO_TH GENMASK(21, 15) + #define MESON_SDHC_PDMA_TXFIFO_TH GENMASK(28, 22) + #define MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH GENMASK(30, 29) + #define MESON_SDHC_PDMA_TXFIFO_FILL BIT(31) + +#define MESON_SDHC_MISC 0x1c + #define MESON_SDHC_MISC_WCRC_ERR_PATT GENMASK(6, 4) + #define MESON_SDHC_MISC_WCRC_OK_PATT GENMASK(9, 7) + #define MESON_SDHC_MISC_BURST_NUM GENMASK(21, 16) + #define MESON_SDHC_MISC_THREAD_ID GENMASK(27, 22) + #define MESON_SDHC_MISC_MANUAL_STOP BIT(28) + #define MESON_SDHC_MISC_TXSTART_THRES GENMASK(31, 29) + +#define MESON_SDHC_DATA 0x20 + +#define MESON_SDHC_ICTL 0x24 + #define MESON_SDHC_ICTL_RESP_OK BIT(0) + #define MESON_SDHC_ICTL_RESP_TIMEOUT BIT(1) + #define MESON_SDHC_ICTL_RESP_ERR_CRC BIT(2) + #define MESON_SDHC_ICTL_RESP_OK_NOCLEAR BIT(3) + #define MESON_SDHC_ICTL_DATA_1PACK_OK BIT(4) + #define MESON_SDHC_ICTL_DATA_TIMEOUT BIT(5) + #define MESON_SDHC_ICTL_DATA_ERR_CRC BIT(6) + #define MESON_SDHC_ICTL_DATA_XFER_OK BIT(7) + #define MESON_SDHC_ICTL_RX_HIGHER BIT(8) + #define MESON_SDHC_ICTL_RX_LOWER BIT(9) + #define MESON_SDHC_ICTL_DAT1_IRQ BIT(10) + #define MESON_SDHC_ICTL_DMA_DONE BIT(11) + #define MESON_SDHC_ICTL_RXFIFO_FULL BIT(12) + #define MESON_SDHC_ICTL_TXFIFO_EMPTY BIT(13) + #define MESON_SDHC_ICTL_ADDI_DAT1_IRQ BIT(14) + #define MESON_SDHC_ICTL_ALL_IRQS GENMASK(14, 0) + #define MESON_SDHC_ICTL_DAT1_IRQ_DELAY GENMASK(17, 16) + +#define MESON_SDHC_ISTA 0x28 + #define MESON_SDHC_ISTA_RESP_OK BIT(0) + #define MESON_SDHC_ISTA_RESP_TIMEOUT BIT(1) + #define MESON_SDHC_ISTA_RESP_ERR_CRC BIT(2) + #define MESON_SDHC_ISTA_RESP_OK_NOCLEAR BIT(3) + #define MESON_SDHC_ISTA_DATA_1PACK_OK BIT(4) + #define MESON_SDHC_ISTA_DATA_TIMEOUT BIT(5) + #define MESON_SDHC_ISTA_DATA_ERR_CRC BIT(6) + #define MESON_SDHC_ISTA_DATA_XFER_OK BIT(7) + #define MESON_SDHC_ISTA_RX_HIGHER BIT(8) + #define MESON_SDHC_ISTA_RX_LOWER BIT(9) + #define MESON_SDHC_ISTA_DAT1_IRQ BIT(10) + #define MESON_SDHC_ISTA_DMA_DONE BIT(11) + #define MESON_SDHC_ISTA_RXFIFO_FULL BIT(12) + #define MESON_SDHC_ISTA_TXFIFO_EMPTY BIT(13) + #define MESON_SDHC_ISTA_ADDI_DAT1_IRQ BIT(14) + #define MESON_SDHC_ISTA_ALL_IRQS GENMASK(14, 0) + +#define MESON_SDHC_SRST 0x2c + #define MESON_SDHC_SRST_MAIN_CTRL BIT(0) + #define MESON_SDHC_SRST_RXFIFO BIT(1) + #define MESON_SDHC_SRST_TXFIFO BIT(2) + #define MESON_SDHC_SRST_DPHY_RX BIT(3) + #define MESON_SDHC_SRST_DPHY_TX BIT(4) + #define MESON_SDHC_SRST_DMA_IF BIT(5) + +#define MESON_SDHC_ESTA 0x30 + #define MESON_SDHC_ESTA_11_13 GENMASK(13, 11) + +#define MESON_SDHC_ENHC 0x34 + #define MESON_SDHC_ENHC_MESON8M2_WRRSP_MODE BIT(0) + #define MESON_SDHC_ENHC_MESON8M2_CHK_WRRSP BIT(1) + #define MESON_SDHC_ENHC_MESON8M2_CHK_DMA BIT(2) + #define MESON_SDHC_ENHC_MESON8M2_DEBUG GENMASK(5, 3) + #define MESON_SDHC_ENHC_MESON6_RX_TIMEOUT GENMASK(7, 0) + #define MESON_SDHC_ENHC_MESON6_DMA_RD_RESP BIT(16) + #define MESON_SDHC_ENHC_MESON6_DMA_WR_RESP BIT(17) + #define MESON_SDHC_ENHC_SDIO_IRQ_PERIOD GENMASK(15, 8) + #define MESON_SDHC_ENHC_RXFIFO_TH GENMASK(24, 18) + #define MESON_SDHC_ENHC_TXFIFO_TH GENMASK(31, 25) + +#define MESON_SDHC_CLK2 0x38 + #define MESON_SDHC_CLK2_RX_CLK_PHASE GENMASK(11, 0) + #define MESON_SDHC_CLK2_SD_CLK_PHASE GENMASK(23, 12) + +struct clk_bulk_data; + +int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base, + struct clk_bulk_data *clk_bulk_data); + +#endif /* _MESON_MX_SDHC_H_ */ From 554232e8d59f3df842fdd9cc68a22e827b286d52 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Wed, 13 May 2020 18:26:02 +0800 Subject: [PATCH 079/127] mmc: sdhci-of-dwcmshc: implement specific set_uhs_signaling We need a different set_uhs_signaling implementation for MMC_TIMING_MMC_HS and MMC_TIMING_MMC_HS400. Signed-off-by: Jisheng Zhang Link: https://lore.kernel.org/r/20200513182602.3636a551@xhacker.debian Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-dwcmshc.c | 31 ++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index a5137845a1c7..a9ed0e006e06 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -16,6 +16,9 @@ #include "sdhci-pltfm.h" +/* DWCMSHC specific Mode Select value */ +#define DWCMSHC_CTRL_HS400 0x7 + #define BOUNDARY_OK(addr, len) \ ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) @@ -46,10 +49,36 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc, sdhci_adma_write_desc(host, desc, addr, len, cmd); } +static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + u16 ctrl_2; + + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + /* Select Bus Speed Mode for host */ + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; + if ((timing == MMC_TIMING_MMC_HS200) || + (timing == MMC_TIMING_UHS_SDR104)) + ctrl_2 |= SDHCI_CTRL_UHS_SDR104; + else if (timing == MMC_TIMING_UHS_SDR12) + ctrl_2 |= SDHCI_CTRL_UHS_SDR12; + else if ((timing == MMC_TIMING_UHS_SDR25) || + (timing == MMC_TIMING_MMC_HS)) + ctrl_2 |= SDHCI_CTRL_UHS_SDR25; + else if (timing == MMC_TIMING_UHS_SDR50) + ctrl_2 |= SDHCI_CTRL_UHS_SDR50; + else if ((timing == MMC_TIMING_UHS_DDR50) || + (timing == MMC_TIMING_MMC_DDR52)) + ctrl_2 |= SDHCI_CTRL_UHS_DDR50; + else if (timing == MMC_TIMING_MMC_HS400) + ctrl_2 |= DWCMSHC_CTRL_HS400; + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +} + static const struct sdhci_ops sdhci_dwcmshc_ops = { .set_clock = sdhci_set_clock, .set_bus_width = sdhci_set_bus_width, - .set_uhs_signaling = sdhci_set_uhs_signaling, + .set_uhs_signaling = dwcmshc_set_uhs_signaling, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .reset = sdhci_reset, .adma_write_desc = dwcmshc_adma_write_desc, From bccce2ec77901c771cd7acd83cb99626ab1edf07 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Fri, 15 May 2020 14:19:26 +0800 Subject: [PATCH 080/127] mmc: sdhci-of-dwcmshc: add suspend/resume support Add dwcmshc specific system-level suspend and resume support. Signed-off-by: Jisheng Zhang Link: https://lore.kernel.org/r/20200515141926.52e088fe@xhacker.debian Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-dwcmshc.c | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index a9ed0e006e06..64ac0dbee95c 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -163,6 +163,48 @@ static int dwcmshc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int dwcmshc_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + int ret; + + ret = sdhci_suspend_host(host); + if (ret) + return ret; + + clk_disable_unprepare(pltfm_host->clk); + if (!IS_ERR(priv->bus_clk)) + clk_disable_unprepare(priv->bus_clk); + + return ret; +} + +static int dwcmshc_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); + int ret; + + ret = clk_prepare_enable(pltfm_host->clk); + if (ret) + return ret; + + if (!IS_ERR(priv->bus_clk)) { + ret = clk_prepare_enable(priv->bus_clk); + if (ret) + return ret; + } + + return sdhci_resume_host(host); +} +#endif + +static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume); + static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { { .compatible = "snps,dwcmshc-sdhci" }, {} @@ -173,6 +215,7 @@ static struct platform_driver sdhci_dwcmshc_driver = { .driver = { .name = "sdhci-dwcmshc", .of_match_table = sdhci_dwcmshc_dt_ids, + .pm = &dwcmshc_pmops, }, .probe = dwcmshc_probe, .remove = dwcmshc_remove, From 67c7daec6981d9b15ba85018b20ff8bcc3bcd193 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 18 May 2020 08:08:11 +0200 Subject: [PATCH 081/127] mmc: meson-mx-sdhc: Fix building with CONFIG_MMC_MESON_MX_SDHC=m For an x86_64 allmodconfig build Stephen reports that building meson-mx-sdhc-clkc.o warns that MODULE_LICENSE is missing and when linking meson_mx_sdhc_register_clkc cannot be found. Compile the MMC controller driver together with the build-in clock controller driver into one module rather than using two separate modules to fix these issues. Reported-by: Stephen Rothwell Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20200518060811.1499962-1-martin.blumenstingl@googlemail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Makefile | 3 ++- drivers/mmc/host/{meson-mx-sdhc.c => meson-mx-sdhc-mmc.c} | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename drivers/mmc/host/{meson-mx-sdhc.c => meson-mx-sdhc-mmc.c} (100%) diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 8bcb420e071c..8f459259181e 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -68,7 +68,8 @@ obj-$(CONFIG_MMC_VUB300) += vub300.o obj-$(CONFIG_MMC_USHC) += ushc.o obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_MESON_GX) += meson-gx-mmc.o -obj-$(CONFIG_MMC_MESON_MX_SDHC) += meson-mx-sdhc-clkc.o meson-mx-sdhc.o +meson-mx-sdhc-objs := meson-mx-sdhc-clkc.o meson-mx-sdhc-mmc.o +obj-$(CONFIG_MMC_MESON_MX_SDHC) += meson-mx-sdhc.o obj-$(CONFIG_MMC_MESON_MX_SDIO) += meson-mx-sdio.o obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o diff --git a/drivers/mmc/host/meson-mx-sdhc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c similarity index 100% rename from drivers/mmc/host/meson-mx-sdhc.c rename to drivers/mmc/host/meson-mx-sdhc-mmc.c From 86b59671deba640d77335ef75f7c3ca388372860 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Fri, 15 May 2020 15:28:23 +0800 Subject: [PATCH 082/127] mmc: sdhci-esdhc-imx: Add HS400 support for i.MX6SLL i.MX6SLL support MMC up to V5.0, which means support HS400 mode. Signed-off-by: Haibo Chen Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1589527703-19108-1-git-send-email-haibo.chen@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 9896e03fce71..5398af4824c3 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -215,6 +215,7 @@ static const struct esdhc_soc_data usdhc_imx6sl_data = { static const struct esdhc_soc_data usdhc_imx6sll_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 + | ESDHC_FLAG_HS400 | ESDHC_FLAG_STATE_LOST_IN_LPMODE, }; From c70805dca13970d18a4a9960bdc1d2f10de59057 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 18 May 2020 00:29:06 +0200 Subject: [PATCH 083/127] mmc: meson-mx-sdhc: Fix manual RX FIFO flushing For Meson8 and Meson8b SoCs the vendor driver follows the following pattern: - for eMMC and SD cards in .set_pdma it sets: pdma->rxfifo_manual_flush = 1; - for SDIO cards in .set_pdma it sets: pdma->rxfifo_manual_flush = 0; - before syncing the DMA read buffer is sets: pdma->rxfifo_manual_flush |= 0x02; Set the second bit of MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH without clearing the first bit before syncing the DMA read buffer. This fixes a problem where Meson8 and Meson8b SoCs would read random garbage from SD cards. It is not clear why it worked for eMMC cards. This manifested in the following errors when plugging in an SD card: unrecognised SCR structure version Cc: Thomas Graichen Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20200517222907.1277787-1-martin.blumenstingl@googlemail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-mx-sdhc-mmc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c index 5c00958d7754..53e3f6a4245a 100644 --- a/drivers/mmc/host/meson-mx-sdhc-mmc.c +++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c @@ -586,10 +586,17 @@ static irqreturn_t meson_mx_sdhc_irq_thread(int irq, void *irq_data) cmd->data->flags & MMC_DATA_READ) { meson_mx_sdhc_wait_cmd_ready(host->mmc); + /* + * If MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH was + * previously 0x1 then it has to be set to 0x3. If it + * was 0x0 before then it has to be set to 0x2. Without + * this reading SD cards sometimes transfers garbage, + * which results in cards not being detected due to: + * unrecognised SCR structure version + */ val = FIELD_PREP(MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH, 2); - regmap_update_bits(host->regmap, MESON_SDHC_PDMA, - MESON_SDHC_PDMA_RXFIFO_MANUAL_FLUSH, + regmap_update_bits(host->regmap, MESON_SDHC_PDMA, val, val); } From 7d79735d56a2f425f8c40054da0042b35c678839 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 18 May 2020 00:29:07 +0200 Subject: [PATCH 084/127] mmc: meson-mx-sdhc: Don't use literal 0 to initialize structs Kbuild test robot reports the following warning in lines 56 and 87 of drivers/mmc/host/meson-mx-sdhc-clkc.c: Using plain integer as NULL pointer Drop the integer value from the struct initialization to fix that warning. This will still ensure that the compiler will zero out the struct so it's in a well-defined state. Reported-by: kbuild test robot Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20200517222907.1277787-2-martin.blumenstingl@googlemail.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/meson-mx-sdhc-clkc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/meson-mx-sdhc-clkc.c b/drivers/mmc/host/meson-mx-sdhc-clkc.c index ab0d6c68a078..e1f29b279123 100644 --- a/drivers/mmc/host/meson-mx-sdhc-clkc.c +++ b/drivers/mmc/host/meson-mx-sdhc-clkc.c @@ -53,7 +53,7 @@ static int meson_mx_sdhc_clk_hw_register(struct device *dev, const struct clk_ops *ops, struct clk_hw *hw) { - struct clk_init_data init = { 0 }; + struct clk_init_data init = { }; char clk_name[32]; snprintf(clk_name, sizeof(clk_name), "%s#%s", dev_name(dev), @@ -84,7 +84,7 @@ static int meson_mx_sdhc_gate_clk_hw_register(struct device *dev, int meson_mx_sdhc_register_clkc(struct device *dev, void __iomem *base, struct clk_bulk_data *clk_bulk_data) { - struct clk_parent_data div_parent = { 0 }; + struct clk_parent_data div_parent = { }; struct meson_mx_sdhc_clkc *clkc_data; int ret; From 1f8153ee031d0d4756daa985788bf0a960e588a6 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 15 May 2020 16:08:44 +0100 Subject: [PATCH 085/127] dt-bindings: mmc: renesas,sdhi: Document r8a7742 support Document SDHI controller for RZ/G1H (R8A7742) SoC, which is compatible with R-Car Gen2 SoC family. Signed-off-by: Lad Prabhakar Reviewed-by: Marian-Cristian Rotariu Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/1589555337-5498-5-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/renesas,sdhi.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/renesas,sdhi.txt b/Documentation/devicetree/bindings/mmc/renesas,sdhi.txt index e6cc47844207..0ca9a622cce0 100644 --- a/Documentation/devicetree/bindings/mmc/renesas,sdhi.txt +++ b/Documentation/devicetree/bindings/mmc/renesas,sdhi.txt @@ -7,6 +7,7 @@ Required properties: "renesas,sdhi-r7s9210" - SDHI IP on R7S9210 SoC "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC + "renesas,sdhi-r8a7742" - SDHI IP on R8A7742 SoC "renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC "renesas,sdhi-r8a7744" - SDHI IP on R8A7744 SoC "renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC From 991f5c4dd2422881c933ec3c7c19f3a2a1858cc4 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Mon, 18 May 2020 21:17:39 +0200 Subject: [PATCH 086/127] m68k: mcf5441x: add support for esdhc mmc controller Add support for sdhci-edshc mmc controller. Signed-off-by: Angelo Dureghello Acked-by: Greg Ungerer Link: https://lore.kernel.org/r/20200518191742.1251440-1-angelo.dureghello@timesys.com Signed-off-by: Ulf Hansson --- arch/m68k/coldfire/clk.c | 15 ++++++++++ arch/m68k/coldfire/device.c | 33 +++++++++++++++++++-- arch/m68k/coldfire/m5441x.c | 12 +++++++- arch/m68k/include/asm/m5441xsim.h | 15 ++++++++++ arch/m68k/include/asm/mcfclk.h | 2 ++ include/linux/platform_data/mmc-esdhc-mcf.h | 17 +++++++++++ 6 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 include/linux/platform_data/mmc-esdhc-mcf.h diff --git a/arch/m68k/coldfire/clk.c b/arch/m68k/coldfire/clk.c index 7bc666e482eb..75a057445472 100644 --- a/arch/m68k/coldfire/clk.c +++ b/arch/m68k/coldfire/clk.c @@ -73,6 +73,21 @@ struct clk_ops clk_ops1 = { #endif /* MCFPM_PPMCR1 */ #endif /* MCFPM_PPMCR0 */ +static void __clk_enable2(struct clk *clk) +{ + __raw_writel(__raw_readl(MCFSDHC_CLK) | (1 << clk->slot), MCFSDHC_CLK); +} + +static void __clk_disable2(struct clk *clk) +{ + __raw_writel(__raw_readl(MCFSDHC_CLK) & ~(1 << clk->slot), MCFSDHC_CLK); +} + +struct clk_ops clk_ops2 = { + .enable = __clk_enable2, + .disable = __clk_disable2, +}; + struct clk *clk_get(struct device *dev, const char *id) { const char *clk_name = dev ? dev_name(dev) : id ? id : NULL; diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c index b4103b6bfdeb..9ef4ec0aea00 100644 --- a/arch/m68k/coldfire/device.c +++ b/arch/m68k/coldfire/device.c @@ -22,6 +22,7 @@ #include #include #include +#include /* * All current ColdFire parts contain from 2, 3, 4 or 10 UARTS. @@ -551,9 +552,35 @@ static struct platform_device mcf_edma = { .platform_data = &mcf_edma_data, } }; - #endif /* IS_ENABLED(CONFIG_MCF_EDMA) */ +#if IS_ENABLED(CONFIG_MMC) +static struct mcf_esdhc_platform_data mcf_esdhc_data = { + .max_bus_width = 4, + .cd_type = ESDHC_CD_NONE, +}; + +static struct resource mcf_esdhc_resources[] = { + { + .start = MCFSDHC_BASE, + .end = MCFSDHC_BASE + MCFSDHC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .start = MCF_IRQ_SDHC, + .end = MCF_IRQ_SDHC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mcf_esdhc = { + .name = "sdhci-esdhc-mcf", + .id = 0, + .num_resources = ARRAY_SIZE(mcf_esdhc_resources), + .resource = mcf_esdhc_resources, + .dev.platform_data = &mcf_esdhc_data, +}; +#endif /* IS_ENABLED(CONFIG_MMC) */ + static struct platform_device *mcf_devices[] __initdata = { &mcf_uart, #if IS_ENABLED(CONFIG_FEC) @@ -586,6 +613,9 @@ static struct platform_device *mcf_devices[] __initdata = { #if IS_ENABLED(CONFIG_MCF_EDMA) &mcf_edma, #endif +#if IS_ENABLED(CONFIG_MMC) + &mcf_esdhc, +#endif }; /* @@ -614,4 +644,3 @@ static int __init mcf_init_devices(void) } arch_initcall(mcf_init_devices); - diff --git a/arch/m68k/coldfire/m5441x.c b/arch/m68k/coldfire/m5441x.c index 5bd24c9b865d..ffa02de1a3fb 100644 --- a/arch/m68k/coldfire/m5441x.c +++ b/arch/m68k/coldfire/m5441x.c @@ -52,7 +52,7 @@ DEFINE_CLK(0, "mcfssi.0", 47, MCF_CLK); DEFINE_CLK(0, "pll.0", 48, MCF_CLK); DEFINE_CLK(0, "mcfrng.0", 49, MCF_CLK); DEFINE_CLK(0, "mcfssi.1", 50, MCF_CLK); -DEFINE_CLK(0, "mcfsdhc.0", 51, MCF_CLK); +DEFINE_CLK(0, "sdhci-esdhc-mcf.0", 51, MCF_CLK); DEFINE_CLK(0, "enet-fec.0", 53, MCF_CLK); DEFINE_CLK(0, "enet-fec.1", 54, MCF_CLK); DEFINE_CLK(0, "switch.0", 55, MCF_CLK); @@ -74,6 +74,10 @@ DEFINE_CLK(1, "mcfpwm.0", 34, MCF_BUSCLK); DEFINE_CLK(1, "sys.0", 36, MCF_BUSCLK); DEFINE_CLK(1, "gpio.0", 37, MCF_BUSCLK); +DEFINE_CLK(2, "ipg.0", 0, MCF_CLK); +DEFINE_CLK(2, "ahb.0", 1, MCF_CLK); +DEFINE_CLK(2, "per.0", 2, MCF_CLK); + struct clk *mcf_clks[] = { &__clk_0_2, &__clk_0_8, @@ -131,6 +135,11 @@ struct clk *mcf_clks[] = { &__clk_1_34, &__clk_1_36, &__clk_1_37, + + &__clk_2_0, + &__clk_2_1, + &__clk_2_2, + NULL, }; @@ -151,6 +160,7 @@ static struct clk * const enable_clks[] __initconst = { &__clk_0_33, /* pit.1 */ &__clk_0_37, /* eport */ &__clk_0_48, /* pll */ + &__clk_0_51, /* esdhc */ &__clk_1_36, /* CCM/reset module/Power management */ &__clk_1_37, /* gpio */ diff --git a/arch/m68k/include/asm/m5441xsim.h b/arch/m68k/include/asm/m5441xsim.h index 4892f314ff38..e091e36d3464 100644 --- a/arch/m68k/include/asm/m5441xsim.h +++ b/arch/m68k/include/asm/m5441xsim.h @@ -278,6 +278,13 @@ #define MCFGPIO_IRQ_VECBASE (MCFINT_VECBASE - MCFGPIO_IRQ_MIN) #define MCFGPIO_PIN_MAX 87 +/* + * Phase Locked Loop (PLL) + */ +#define MCF_PLL_CR 0xFC0C0000 +#define MCF_PLL_DR 0xFC0C0004 +#define MCF_PLL_SR 0xFC0C0008 + /* * DSPI module. */ @@ -298,5 +305,13 @@ #define MCFEDMA_IRQ_INTR16 (MCFINT1_VECBASE + MCFEDMA_EDMA_INTR16) #define MCFEDMA_IRQ_INTR56 (MCFINT2_VECBASE + MCFEDMA_EDMA_INTR56) #define MCFEDMA_IRQ_ERR (MCFINT0_VECBASE + MCFINT0_EDMA_ERR) +/* + * esdhc module. + */ +#define MCFSDHC_BASE 0xfc0cc000 +#define MCFSDHC_SIZE 256 +#define MCFINT2_SDHC 31 +#define MCF_IRQ_SDHC (MCFINT2_VECBASE + MCFINT2_SDHC) +#define MCFSDHC_CLK (MCFSDHC_BASE + 0x2c) #endif /* m5441xsim_h */ diff --git a/arch/m68k/include/asm/mcfclk.h b/arch/m68k/include/asm/mcfclk.h index 0aca504fae31..722627e06d66 100644 --- a/arch/m68k/include/asm/mcfclk.h +++ b/arch/m68k/include/asm/mcfclk.h @@ -30,6 +30,8 @@ extern struct clk_ops clk_ops0; extern struct clk_ops clk_ops1; #endif /* MCFPM_PPMCR1 */ +extern struct clk_ops clk_ops2; + #define DEFINE_CLK(clk_bank, clk_name, clk_slot, clk_rate) \ static struct clk __clk_##clk_bank##_##clk_slot = { \ .name = clk_name, \ diff --git a/include/linux/platform_data/mmc-esdhc-mcf.h b/include/linux/platform_data/mmc-esdhc-mcf.h new file mode 100644 index 000000000000..85cb786a62fe --- /dev/null +++ b/include/linux/platform_data/mmc-esdhc-mcf.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LINUX_PLATFORM_DATA_MCF_ESDHC_H__ +#define __LINUX_PLATFORM_DATA_MCF_ESDHC_H__ + +enum cd_types { + ESDHC_CD_NONE, /* no CD, neither controller nor gpio */ + ESDHC_CD_CONTROLLER, /* mmc controller internal CD */ + ESDHC_CD_PERMANENT, /* no CD, card permanently wired to host */ +}; + +struct mcf_esdhc_platform_data { + int max_bus_width; + int cd_type; +}; + +#endif /* __LINUX_PLATFORM_DATA_MCF_ESDHC_H__ */ From e93577ecde8f3cbd12a2eaa0522d5c85e0dbdd53 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Mon, 18 May 2020 21:17:40 +0200 Subject: [PATCH 087/127] mmc: sdhci: add quirks for be to le byte swapping Some controller as the ColdFire eshdc may require an endianness byte swap, because DMA read endianness is not configurable. Facilitate using the bounce buffer for this by adding ->copy_to_bounce_buffer(). Signed-off-by: Angelo Dureghello Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20200518191742.1251440-2-angelo.dureghello@timesys.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 10 +++++++--- drivers/mmc/host/sdhci.h | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9864e877e105..70bc77dffb34 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -637,9 +637,13 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, } if (mmc_get_dma_dir(data) == DMA_TO_DEVICE) { /* Copy the data to the bounce buffer */ - sg_copy_to_buffer(data->sg, data->sg_len, - host->bounce_buffer, - length); + if (host->ops->copy_to_bounce_buffer) { + host->ops->copy_to_bounce_buffer(host, + data, length); + } else { + sg_copy_to_buffer(data->sg, data->sg_len, + host->bounce_buffer, length); + } } /* Switch ownership to the DMA */ dma_sync_single_for_device(host->mmc->parent, diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 257213a94d89..d628ab6c5a6f 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -645,6 +645,9 @@ struct sdhci_ops { void (*voltage_switch)(struct sdhci_host *host); void (*adma_write_desc)(struct sdhci_host *host, void **desc, dma_addr_t addr, int len, unsigned int cmd); + void (*copy_to_bounce_buffer)(struct sdhci_host *host, + struct mmc_data *data, + unsigned int length); void (*request_done)(struct sdhci_host *host, struct mmc_request *mrq); }; From a5a944d24cbce13f86932f6d9ae4ac4586fe543a Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Mon, 18 May 2020 21:17:41 +0200 Subject: [PATCH 088/127] mmc: host: add Coldfire esdhc support This driver has been developed as a separate module starting from the similar sdhci-esdhc-imx.c. Reasons for a separate sdchi-esdhc-mcf driver: - m68K architecture does not support devicetrees, so modifying sdhci-of-esdhc.c that is devicetree-related adding platform data seems not appropriate, - clock-related part, has to be implemented specifically for mcf5441x family (see esdhc_mcf_pltfm_set_clock()), - this is a big endian cpu accessing a big endian controller, but about sdma, this controller does not support hw swap, which needs to be handled with specific code, - some other minor differences but mainly to avoid risks on tweaking inside largely used imx driver. Adding just a small size ColdFire-specific driver, with benefits in a further less risky maintenance. Signed-off-by: Angelo Dureghello Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20200518191742.1251440-3-angelo.dureghello@timesys.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/Kconfig | 13 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-esdhc-mcf.c | 521 +++++++++++++++++++++++++++++ 3 files changed, 535 insertions(+) create mode 100644 drivers/mmc/host/sdhci-esdhc-mcf.c diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index ee12451ba708..0ce332ad986b 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -235,6 +235,19 @@ config MMC_SDHCI_CNS3XXX If unsure, say N. +config MMC_SDHCI_ESDHC_MCF + tristate "SDHCI support for the Freescale eSDHC ColdFire controller" + depends on M5441x + depends on MMC_SDHCI_PLTFM + select MMC_SDHCI_IO_ACCESSORS + help + This selects the Freescale eSDHC controller support for + ColdFire mcf5441x devices. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_ESDHC_IMX tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" depends on ARCH_MXC diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 8f459259181e..4d5bcb0144a0 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o +obj-$(CONFIG_MMC_SDHCI_ESDHC_MCF) += sdhci-esdhc-mcf.o obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o diff --git a/drivers/mmc/host/sdhci-esdhc-mcf.c b/drivers/mmc/host/sdhci-esdhc-mcf.c new file mode 100644 index 000000000000..71bf086a9812 --- /dev/null +++ b/drivers/mmc/host/sdhci-esdhc-mcf.c @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Freescale eSDHC ColdFire family controller driver, platform bus. + * + * Copyright (c) 2020 Timesys Corporation + * Author: Angelo Dureghello + */ + +#include +#include +#include +#include +#include "sdhci-pltfm.h" +#include "sdhci-esdhc.h" + +#define ESDHC_PROCTL_D3CD 0x08 +#define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f +#define ESDHC_DEFAULT_HOST_CONTROL 0x28 + +/* + * Freescale eSDHC has DMA ERR flag at bit 28, not as std spec says, bit 25. + */ +#define ESDHC_INT_VENDOR_SPEC_DMA_ERR BIT(28) + +struct pltfm_mcf_data { + struct clk *clk_ipg; + struct clk *clk_ahb; + struct clk *clk_per; + int aside; + int current_bus_width; +}; + +static inline void esdhc_mcf_buffer_swap32(u32 *buf, int len) +{ + int i; + u32 temp; + + len = (len + 3) >> 2; + + for (i = 0; i < len; i++) { + temp = swab32(*buf); + *buf++ = temp; + } +} + +static inline void esdhc_clrset_be(struct sdhci_host *host, + u32 mask, u32 val, int reg) +{ + void __iomem *base = host->ioaddr + (reg & ~3); + u8 shift = (reg & 3) << 3; + + mask <<= shift; + val <<= shift; + + if (reg == SDHCI_HOST_CONTROL) + val |= ESDHC_PROCTL_D3CD; + + writel((readl(base) & ~mask) | val, base); +} + +/* + * Note: mcf is big-endian, single bytes need to be accessed at big endian + * offsets. + */ +static void esdhc_mcf_writeb_be(struct sdhci_host *host, u8 val, int reg) +{ + void __iomem *base = host->ioaddr + (reg & ~3); + u8 shift = (reg & 3) << 3; + u32 mask = ~(0xff << shift); + + if (reg == SDHCI_HOST_CONTROL) { + u32 host_ctrl = ESDHC_DEFAULT_HOST_CONTROL; + u8 dma_bits = (val & SDHCI_CTRL_DMA_MASK) >> 3; + u8 tmp = readb(host->ioaddr + SDHCI_HOST_CONTROL + 1); + + tmp &= ~0x03; + tmp |= dma_bits; + + /* + * Recomposition needed, restore always endianness and + * keep D3CD and AI, just setting bus width. + */ + host_ctrl |= val; + host_ctrl |= (dma_bits << 8); + writel(host_ctrl, host->ioaddr + SDHCI_HOST_CONTROL); + + return; + } + + writel((readl(base) & mask) | (val << shift), base); +} + +static void esdhc_mcf_writew_be(struct sdhci_host *host, u16 val, int reg) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(pltfm_host); + void __iomem *base = host->ioaddr + (reg & ~3); + u8 shift = (reg & 3) << 3; + u32 mask = ~(0xffff << shift); + + switch (reg) { + case SDHCI_TRANSFER_MODE: + mcf_data->aside = val; + return; + case SDHCI_COMMAND: + if (host->cmd->opcode == MMC_STOP_TRANSMISSION) + val |= SDHCI_CMD_ABORTCMD; + + /* + * As for the fsl driver, + * we have to set the mode in a single write here. + */ + writel(val << 16 | mcf_data->aside, + host->ioaddr + SDHCI_TRANSFER_MODE); + return; + } + + writel((readl(base) & mask) | (val << shift), base); +} + +static void esdhc_mcf_writel_be(struct sdhci_host *host, u32 val, int reg) +{ + writel(val, host->ioaddr + reg); +} + +static u8 esdhc_mcf_readb_be(struct sdhci_host *host, int reg) +{ + if (reg == SDHCI_HOST_CONTROL) { + u8 __iomem *base = host->ioaddr + (reg & ~3); + u16 val = readw(base + 2); + u8 dma_bits = (val >> 5) & SDHCI_CTRL_DMA_MASK; + u8 host_ctrl = val & 0xff; + + host_ctrl &= ~SDHCI_CTRL_DMA_MASK; + host_ctrl |= dma_bits; + + return host_ctrl; + } + + return readb(host->ioaddr + (reg ^ 0x3)); +} + +static u16 esdhc_mcf_readw_be(struct sdhci_host *host, int reg) +{ + /* + * For SDHCI_HOST_VERSION, sdhci specs defines 0xFE, + * a wrong offset for us, we are at 0xFC. + */ + if (reg == SDHCI_HOST_VERSION) + reg -= 2; + + return readw(host->ioaddr + (reg ^ 0x2)); +} + +static u32 esdhc_mcf_readl_be(struct sdhci_host *host, int reg) +{ + u32 val; + + val = readl(host->ioaddr + reg); + + /* + * RM (25.3.9) sd pin clock must never exceed 25Mhz. + * So forcing legacy mode at 25Mhz. + */ + if (unlikely(reg == SDHCI_CAPABILITIES)) + val &= ~SDHCI_CAN_DO_HISPD; + + if (unlikely(reg == SDHCI_INT_STATUS)) { + if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) { + val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; + val |= SDHCI_INT_ADMA_ERROR; + } + } + + return val; +} + +static unsigned int esdhc_mcf_get_max_timeout_count(struct sdhci_host *host) +{ + return 1 << 27; +} + +static void esdhc_mcf_set_timeout(struct sdhci_host *host, + struct mmc_command *cmd) +{ + /* Use maximum timeout counter */ + esdhc_clrset_be(host, ESDHC_SYS_CTRL_DTOCV_MASK, 0xE, + SDHCI_TIMEOUT_CONTROL); +} + +static void esdhc_mcf_reset(struct sdhci_host *host, u8 mask) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(pltfm_host); + + sdhci_reset(host, mask); + + esdhc_clrset_be(host, ESDHC_CTRL_BUSWIDTH_MASK, + mcf_data->current_bus_width, SDHCI_HOST_CONTROL); + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); +} + +static unsigned int esdhc_mcf_pltfm_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return pltfm_host->clock; +} + +static unsigned int esdhc_mcf_pltfm_get_min_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return pltfm_host->clock / 256 / 16; +} + +static void esdhc_mcf_pltfm_set_clock(struct sdhci_host *host, + unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + unsigned long *pll_dr = (unsigned long *)MCF_PLL_DR; + u32 fvco, fsys, fesdhc, temp; + const int sdclkfs[] = {2, 4, 8, 16, 32, 64, 128, 256}; + int delta, old_delta = clock; + int i, q, ri, rq; + + if (clock == 0) { + host->mmc->actual_clock = 0; + return; + } + + /* + * ColdFire eSDHC clock.s + * + * pll -+-> / outdiv1 --> fsys + * +-> / outdiv3 --> eSDHC clock ---> / SDCCLKFS / DVS + * + * mcf5441x datasheet says: + * (8.1.2) eSDHC should be 40 MHz max + * (25.3.9) eSDHC input is, as example, 96 Mhz ... + * (25.3.9) sd pin clock must never exceed 25Mhz + * + * fvco = fsys * outdvi1 + 1 + * fshdc = fvco / outdiv3 + 1 + */ + temp = readl(pll_dr); + fsys = pltfm_host->clock; + fvco = fsys * ((temp & 0x1f) + 1); + fesdhc = fvco / (((temp >> 10) & 0x1f) + 1); + + for (i = 0; i < 8; ++i) { + int result = fesdhc / sdclkfs[i]; + + for (q = 1; q < 17; ++q) { + int finale = result / q; + + delta = abs(clock - finale); + + if (delta < old_delta) { + old_delta = delta; + ri = i; + rq = q; + } + } + } + + /* + * Apply divisors and re-enable all the clocks + */ + temp = ((sdclkfs[ri] >> 1) << 8) | ((rq - 1) << 4) | + (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN); + esdhc_clrset_be(host, 0x0000fff7, temp, SDHCI_CLOCK_CONTROL); + + host->mmc->actual_clock = clock; + + mdelay(1); +} + +static void esdhc_mcf_pltfm_set_bus_width(struct sdhci_host *host, int width) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(pltfm_host); + + switch (width) { + case MMC_BUS_WIDTH_4: + mcf_data->current_bus_width = ESDHC_CTRL_4BITBUS; + break; + default: + mcf_data->current_bus_width = 0; + break; + } + + esdhc_clrset_be(host, ESDHC_CTRL_BUSWIDTH_MASK, + mcf_data->current_bus_width, SDHCI_HOST_CONTROL); +} + +static void esdhc_mcf_request_done(struct sdhci_host *host, + struct mmc_request *mrq) +{ + struct scatterlist *sg; + u32 *buffer; + int i; + + if (!mrq->data || !mrq->data->bytes_xfered) + goto exit_done; + + if (mmc_get_dma_dir(mrq->data) != DMA_FROM_DEVICE) + goto exit_done; + + /* + * On mcf5441x there is no hw sdma option/flag to select the dma + * transfer endiannes. A swap after the transfer is needed. + */ + for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i) { + buffer = (u32 *)sg_virt(sg); + esdhc_mcf_buffer_swap32(buffer, sg->length); + } + +exit_done: + mmc_request_done(host->mmc, mrq); +} + +static void esdhc_mcf_copy_to_bounce_buffer(struct sdhci_host *host, + struct mmc_data *data, + unsigned int length) +{ + sg_copy_to_buffer(data->sg, data->sg_len, + host->bounce_buffer, length); + + esdhc_mcf_buffer_swap32((u32 *)host->bounce_buffer, + data->blksz * data->blocks); +} + +static struct sdhci_ops sdhci_esdhc_ops = { + .reset = esdhc_mcf_reset, + .set_clock = esdhc_mcf_pltfm_set_clock, + .get_max_clock = esdhc_mcf_pltfm_get_max_clock, + .get_min_clock = esdhc_mcf_pltfm_get_min_clock, + .set_bus_width = esdhc_mcf_pltfm_set_bus_width, + .get_max_timeout_count = esdhc_mcf_get_max_timeout_count, + .set_timeout = esdhc_mcf_set_timeout, + .write_b = esdhc_mcf_writeb_be, + .write_w = esdhc_mcf_writew_be, + .write_l = esdhc_mcf_writel_be, + .read_b = esdhc_mcf_readb_be, + .read_w = esdhc_mcf_readw_be, + .read_l = esdhc_mcf_readl_be, + .copy_to_bounce_buffer = esdhc_mcf_copy_to_bounce_buffer, + .request_done = esdhc_mcf_request_done, +}; + +static const struct sdhci_pltfm_data sdhci_esdhc_mcf_pdata = { + .ops = &sdhci_esdhc_ops, + .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_FORCE_DMA, + /* + * Mandatory quirk, + * controller does not support cmd23, + * without, on > 8G cards cmd23 is used, and + * driver times out. + */ + SDHCI_QUIRK2_HOST_NO_CMD23, +}; + +static int esdhc_mcf_plat_init(struct sdhci_host *host, + struct pltfm_mcf_data *mcf_data) +{ + struct mcf_esdhc_platform_data *plat_data; + + if (!host->mmc->parent->platform_data) { + dev_err(mmc_dev(host->mmc), "no platform data!\n"); + return -EINVAL; + } + + plat_data = (struct mcf_esdhc_platform_data *) + host->mmc->parent->platform_data; + + /* Card_detect */ + switch (plat_data->cd_type) { + default: + case ESDHC_CD_CONTROLLER: + /* We have a working card_detect back */ + host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; + break; + case ESDHC_CD_PERMANENT: + host->mmc->caps |= MMC_CAP_NONREMOVABLE; + break; + case ESDHC_CD_NONE: + break; + } + + switch (plat_data->max_bus_width) { + case 4: + host->mmc->caps |= MMC_CAP_4_BIT_DATA; + break; + case 1: + default: + host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; + break; + } + + return 0; +} + +static int sdhci_esdhc_mcf_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct pltfm_mcf_data *mcf_data; + int err; + + host = sdhci_pltfm_init(pdev, &sdhci_esdhc_mcf_pdata, + sizeof(*mcf_data)); + + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + mcf_data = sdhci_pltfm_priv(pltfm_host); + + host->sdma_boundary = 0; + + host->flags |= SDHCI_AUTO_CMD12; + + mcf_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(mcf_data->clk_ipg)) { + err = PTR_ERR(mcf_data->clk_ipg); + goto err_exit; + } + + mcf_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(mcf_data->clk_ahb)) { + err = PTR_ERR(mcf_data->clk_ahb); + goto err_exit; + } + + mcf_data->clk_per = devm_clk_get(&pdev->dev, "per"); + if (IS_ERR(mcf_data->clk_per)) { + err = PTR_ERR(mcf_data->clk_per); + goto err_exit; + } + + pltfm_host->clk = mcf_data->clk_per; + pltfm_host->clock = clk_get_rate(pltfm_host->clk); + err = clk_prepare_enable(mcf_data->clk_per); + if (err) + goto err_exit; + + err = clk_prepare_enable(mcf_data->clk_ipg); + if (err) + goto unprep_per; + + err = clk_prepare_enable(mcf_data->clk_ahb); + if (err) + goto unprep_ipg; + + err = esdhc_mcf_plat_init(host, mcf_data); + if (err) + goto unprep_ahb; + + err = sdhci_setup_host(host); + if (err) + goto unprep_ahb; + + if (!host->bounce_buffer) { + dev_err(&pdev->dev, "bounce buffer not allocated"); + err = -ENOMEM; + goto cleanup; + } + + err = __sdhci_add_host(host); + if (err) + goto cleanup; + + return 0; + +cleanup: + sdhci_cleanup_host(host); +unprep_ahb: + clk_disable_unprepare(mcf_data->clk_ahb); +unprep_ipg: + clk_disable_unprepare(mcf_data->clk_ipg); +unprep_per: + clk_disable_unprepare(mcf_data->clk_per); +err_exit: + sdhci_pltfm_free(pdev); + + return err; +} + +static int sdhci_esdhc_mcf_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(pltfm_host); + + sdhci_remove_host(host, 0); + + clk_disable_unprepare(mcf_data->clk_ipg); + clk_disable_unprepare(mcf_data->clk_ahb); + clk_disable_unprepare(mcf_data->clk_per); + + sdhci_pltfm_free(pdev); + + return 0; +} + +static struct platform_driver sdhci_esdhc_mcf_driver = { + .driver = { + .name = "sdhci-esdhc-mcf", + }, + .probe = sdhci_esdhc_mcf_probe, + .remove = sdhci_esdhc_mcf_remove, +}; + +module_platform_driver(sdhci_esdhc_mcf_driver); + +MODULE_DESCRIPTION("SDHCI driver for Freescale ColdFire eSDHC"); +MODULE_AUTHOR("Angelo Dureghello "); +MODULE_LICENSE("GPL v2"); From c5dce4f52d7918c5ce3ab2a63ab5978c24405a05 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Mon, 18 May 2020 21:17:42 +0200 Subject: [PATCH 089/127] MAINTAINERS: add myself to maintain M5441X mmc host driver Since actively working on Freescale ColdFire M5441X, adding myself as a maintainer of this driver. Signed-off-by: Angelo Dureghello Link: https://lore.kernel.org/r/20200518191742.1251440-4-angelo.dureghello@timesys.com Signed-off-by: Ulf Hansson --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 50659d76976b..6fee4e339e74 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6713,6 +6713,13 @@ S: Maintained F: Documentation/devicetree/bindings/crypto/fsl-sec4.txt F: drivers/crypto/caam/ +FREESCALE COLDFIRE M5441X MMC DRIVER +M: Angelo Dureghello +L: linux-mmc@vger.kernel.org +S: Maintained +F: drivers/mmc/host/sdhci-esdhc-mcf.c +F: include/linux/platform_data/mmc-esdhc-mcf.h + FREESCALE DIU FRAMEBUFFER DRIVER M: Timur Tabi L: linux-fbdev@vger.kernel.org From 4bd784411aca022622e484eb262f5a0540ae732c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 19 May 2020 17:24:34 +0200 Subject: [PATCH 090/127] mmc: tmio: Further fixup runtime PM management at remove Before calling tmio_mmc_host_probe(), the caller is required to enable clocks for its device, as to make it accessible when reading/writing registers during probe. Therefore, the responsibility to disable these clocks, in the error path of ->probe() and during ->remove(), is better managed outside tmio_mmc_host_remove(). As a matter of fact, callers of tmio_mmc_host_remove() already expects this to be the behaviour. However, there's a problem with tmio_mmc_host_remove() when the Kconfig option, CONFIG_PM, is set. More precisely, tmio_mmc_host_remove() may then disable the clock via runtime PM, which leads to clock enable/disable imbalance problems, when the caller of tmio_mmc_host_remove() also tries to disable the same clocks. To solve the problem, let's make sure tmio_mmc_host_remove() leaves the device with clocks enabled, but also make sure to disable the IRQs, as we normally do at ->runtime_suspend(). Reported-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Signed-off-by: Ulf Hansson Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200519152434.6867-1-ulf.hansson@linaro.org Tested-by: Geert Uytterhoeven --- drivers/mmc/host/tmio_mmc_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index f31afd1c2671..ba301fb7656b 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -1231,12 +1231,14 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) cancel_work_sync(&host->done); cancel_delayed_work_sync(&host->delayed_reset_work); tmio_mmc_release_dma(host); + tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL); - pm_runtime_dont_use_autosuspend(&pdev->dev); if (host->native_hotplug) pm_runtime_put_noidle(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); } EXPORT_SYMBOL_GPL(tmio_mmc_host_remove); From 63fd8ef3947c1f61897841748d196b8687b03cdd Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 19 May 2020 17:24:45 +0200 Subject: [PATCH 091/127] mmc: tmio: Make sure the PM domain is 'started' while probing If the tmio device is attached to a genpd (PM domain), that genpd may have ->start|stop() callback assigned to it. To make sure the device is accessible during ->probe(), genpd's ->start() callback must be invoked, which is currently managed by tmio_mmc_host_probe(). However, it's likely that may be too late for some cases, as registers may be read and written way before that point. To fix the behaviour, let's move the call to dev_pm_domain_start() from tmio_mmc_host_probe() into those clients that needs it. From discussions at linux-mmc mailing list, it turned out that it should be sufficient to do this for the SDHI renesas variants, hence the call is move to renesas_sdhi_probe(). Signed-off-by: Ulf Hansson Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Link: https://lore.kernel.org/r/20200519152445.6922-1-ulf.hansson@linaro.org Tested-by: Geert Uytterhoeven --- drivers/mmc/host/renesas_sdhi_core.c | 3 +++ drivers/mmc/host/tmio_mmc_core.c | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index ff72b381a6b3..dcba9ad35dd1 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -905,6 +906,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, /* All SDHI have SDIO status bits which must be 1 */ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS; + dev_pm_domain_start(&pdev->dev); + ret = renesas_sdhi_clk_enable(host); if (ret) goto efree; diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index ba301fb7656b..d7fde57c78c1 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -1192,7 +1191,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) /* See if we also get DMA */ tmio_mmc_request_dma(_host, pdata); - dev_pm_domain_start(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 50); From d42c9fff1ecbec635f068cb1fc5baaeb6fd9a943 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 May 2020 18:42:51 +0200 Subject: [PATCH 092/127] mmc: renesas_sdhi: remove manual clk handling The SDHI driver en-/disabled its main clock on its own, e.g. during probe() and remove(). Now, we leave all handling to RPM. clk_summary before: sd0 1 1 0 12480000 0 0 50000 sdif0 2 2 0 12480000 0 0 50000 clk_summary after: sd0 1 1 0 12480000 0 0 50000 sdif0 1 1 0 12480000 0 0 50000 Reported-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20200519164251.5430-1-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson Tested-by: Geert Uytterhoeven --- drivers/mmc/host/renesas_sdhi_core.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index dcba9ad35dd1..15e21894bd44 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -83,16 +83,11 @@ static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host) { struct mmc_host *mmc = host->mmc; struct renesas_sdhi *priv = host_to_priv(host); - int ret = clk_prepare_enable(priv->clk); - - if (ret < 0) - return ret; + int ret; ret = clk_prepare_enable(priv->clk_cd); - if (ret < 0) { - clk_disable_unprepare(priv->clk); + if (ret < 0) return ret; - } /* * The clock driver may not know what maximum frequency @@ -198,7 +193,6 @@ static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host) { struct renesas_sdhi *priv = host_to_priv(host); - clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk_cd); } From aebbf577e5d1b9ea551669400355dcf5c631c60f Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Wed, 20 May 2020 13:08:57 -0700 Subject: [PATCH 093/127] sdhci: tegra: Avoid reading autocal timeout values when not applicable When auto calibration timeouts, calibration is disabled and fail-safe drive strength values are programmed based on the signal voltage. Different fail-safe drive strength values based on voltage are applicable only for SoCs supporting 3V3 and 1V8 pad controls. So, this patch avoids reading these properties from the device tree for SoCs not using pad controls and the warning of missing properties will not show up on these SoC platforms. Signed-off-by: Sowjanya Komatineni Tested-by: Dmitry Osipenko Acked-by: Thierry Reding Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1590005337-1087-1-git-send-email-skomatineni@nvidia.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-tegra.c | 57 ++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 3e2c5101291d..3a372ab3d12e 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -604,6 +604,39 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host) if (err) autocal->pull_down_1v8 = 0; + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-up-offset-sdr104", + &autocal->pull_up_sdr104); + if (err) + autocal->pull_up_sdr104 = autocal->pull_up_1v8; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-down-offset-sdr104", + &autocal->pull_down_sdr104); + if (err) + autocal->pull_down_sdr104 = autocal->pull_down_1v8; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-up-offset-hs400", + &autocal->pull_up_hs400); + if (err) + autocal->pull_up_hs400 = autocal->pull_up_1v8; + + err = device_property_read_u32(host->mmc->parent, + "nvidia,pad-autocal-pull-down-offset-hs400", + &autocal->pull_down_hs400); + if (err) + autocal->pull_down_hs400 = autocal->pull_down_1v8; + + /* + * Different fail-safe drive strength values based on the signaling + * voltage are applicable for SoCs supporting 3V3 and 1V8 pad controls. + * So, avoid reading below device tree properties for SoCs that don't + * have NVQUIRK_NEEDS_PAD_CONTROL. + */ + if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL)) + return; + err = device_property_read_u32(host->mmc->parent, "nvidia,pad-autocal-pull-up-offset-3v3-timeout", &autocal->pull_up_3v3_timeout); @@ -647,30 +680,6 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host) mmc_hostname(host->mmc)); autocal->pull_down_1v8_timeout = 0; } - - err = device_property_read_u32(host->mmc->parent, - "nvidia,pad-autocal-pull-up-offset-sdr104", - &autocal->pull_up_sdr104); - if (err) - autocal->pull_up_sdr104 = autocal->pull_up_1v8; - - err = device_property_read_u32(host->mmc->parent, - "nvidia,pad-autocal-pull-down-offset-sdr104", - &autocal->pull_down_sdr104); - if (err) - autocal->pull_down_sdr104 = autocal->pull_down_1v8; - - err = device_property_read_u32(host->mmc->parent, - "nvidia,pad-autocal-pull-up-offset-hs400", - &autocal->pull_up_hs400); - if (err) - autocal->pull_up_hs400 = autocal->pull_up_1v8; - - err = device_property_read_u32(host->mmc->parent, - "nvidia,pad-autocal-pull-down-offset-hs400", - &autocal->pull_down_hs400); - if (err) - autocal->pull_down_hs400 = autocal->pull_down_1v8; } static void tegra_sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) From b91da9290979fee2fe2a67f9445d957861fadf6a Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 22 May 2020 15:02:23 +0530 Subject: [PATCH 094/127] dt-bindings: mmc: Add new compatible string for sm8250 target Add new compatible string for sm8250 target. Signed-off-by: Sarthak Garg Link: https://lore.kernel.org/r/1590139950-7288-2-git-send-email-sartgarg@codeaurora.org Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 5445931c5ab9..481f692fd502 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -17,6 +17,7 @@ Required properties: "qcom,msm8916-sdhci", "qcom,sdhci-msm-v4" "qcom,msm8992-sdhci", "qcom,sdhci-msm-v4" "qcom,msm8996-sdhci", "qcom,sdhci-msm-v4" + "qcom,sm8250-sdhci", "qcom,sdhci-msm-v5" "qcom,sdm845-sdhci", "qcom,sdhci-msm-v5" "qcom,qcs404-sdhci", "qcom,sdhci-msm-v5" "qcom,sc7180-sdhci", "qcom,sdhci-msm-v5"; From 97306b631d838667204bd6eaa59e72df1aabbd68 Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 22 May 2020 15:02:24 +0530 Subject: [PATCH 095/127] dt-bindings: mmc: Add information for DLL register properties Add information regarding DLL register properties for getting board specific configurations. These DLL register settings may vary from board to board. Signed-off-by: Sarthak Garg Link: https://lore.kernel.org/r/1590139950-7288-3-git-send-email-sartgarg@codeaurora.org Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 481f692fd502..b8e1d2b7aea9 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -47,6 +47,13 @@ Required properties: "cal" - reference clock for RCLK delay calibration (optional) "sleep" - sleep clock for RCLK delay calibration (optional) +- qcom,ddr-config: Certain chipsets and platforms require particular settings + for the DDR_CONFIG register. Use this field to specify the register + value as per the Hardware Programming Guide. + +- qcom,dll-config: Chipset and Platform specific value. Use this field to + specify the DLL_CONFIG register value as per Hardware Programming Guide. + Example: sdhc_1: sdhci@f9824900 { @@ -64,6 +71,9 @@ Example: clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>; clock-names = "core", "iface"; + + qcom,dll-config = <0x000f642c>; + qcom,ddr-config = <0x80040868>; }; sdhc_2: sdhci@f98a4900 { @@ -81,4 +91,7 @@ Example: clocks = <&gcc GCC_SDCC2_APPS_CLK>, <&gcc GCC_SDCC2_AHB_CLK>; clock-names = "core", "iface"; + + qcom,dll-config = <0x0007642c>; + qcom,ddr-config = <0x80040868>; }; From 5c30f340f9e0b8ecebb82e911a89819d349a8d03 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Fri, 22 May 2020 15:02:25 +0530 Subject: [PATCH 096/127] mmc: host: sdhci-msm: Configure dll-user-control in dll init sequence With SDCC v5.1.0, additional setting needed for enabling DLL output. The dll-user-control register need to be configured during dll initialization for getting proper dll output. Without this configuration, we don't get the DLL lock status properly. Also update the DLL register settings according to the SDCC Hardware Programming Guide. Signed-off-by: Veerabhadrarao Badiganti Signed-off-by: Sarthak Garg Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1590139950-7288-4-git-send-email-sartgarg@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 97758fa62111..6588077590dd 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -57,6 +57,11 @@ #define CORE_FLL_CYCLE_CNT BIT(18) #define CORE_DLL_CLOCK_DISABLE BIT(21) +#define DLL_USR_CTL_POR_VAL 0x10800 +#define ENABLE_DLL_LOCK_STATUS BIT(26) +#define FINE_TUNE_MODE_EN BIT(27) +#define BIAS_OK_SIGNAL BIT(29) + #define CORE_VENDOR_SPEC_POR_VAL 0xa9c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) @@ -157,6 +162,7 @@ struct sdhci_msm_offset { u32 core_dll_config_3; u32 core_ddr_config_old; /* Applicable to sdcc minor ver < 0x49 */ u32 core_ddr_config; + u32 core_dll_usr_ctl; /* Present on SDCC5.1 onwards */ }; static const struct sdhci_msm_offset sdhci_msm_v5_offset = { @@ -186,6 +192,7 @@ static const struct sdhci_msm_offset sdhci_msm_v5_offset = { .core_dll_config_2 = 0x254, .core_dll_config_3 = 0x258, .core_ddr_config = 0x25c, + .core_dll_usr_ctl = 0x388, }; static const struct sdhci_msm_offset sdhci_msm_mci_offset = { @@ -231,6 +238,7 @@ struct sdhci_msm_variant_ops { struct sdhci_msm_variant_info { bool mci_removed; bool restore_dll_config; + bool uses_tassadar_dll; const struct sdhci_msm_variant_ops *var_ops; const struct sdhci_msm_offset *offset; }; @@ -263,6 +271,7 @@ struct sdhci_msm_host { bool use_cdr; u32 transfer_mode; bool updated_ddr_cfg; + bool uses_tassadar_dll; }; static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) @@ -677,6 +686,17 @@ static int msm_init_cm_dll(struct sdhci_host *host) msm_offset->core_dll_config_2); } + /* + * Configure DLL user control register to enable DLL status. + * This setting is applicable to SDCC v5.1 onwards only. + */ + if (msm_host->uses_tassadar_dll) { + config = DLL_USR_CTL_POR_VAL | FINE_TUNE_MODE_EN | + ENABLE_DLL_LOCK_STATUS | BIAS_OK_SIGNAL; + writel_relaxed(config, host->ioaddr + + msm_offset->core_dll_usr_ctl); + } + config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config); config |= CORE_DLL_EN; @@ -1861,10 +1881,18 @@ static const struct sdhci_msm_variant_info sdm845_sdhci_var = { .offset = &sdhci_msm_v5_offset, }; +static const struct sdhci_msm_variant_info sm8250_sdhci_var = { + .mci_removed = true, + .uses_tassadar_dll = true, + .var_ops = &v5_var_ops, + .offset = &sdhci_msm_v5_offset, +}; + static const struct of_device_id sdhci_msm_dt_match[] = { {.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var}, {.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var}, {.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var}, + {.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var}, {}, }; @@ -1930,6 +1958,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->restore_dll_config = var_info->restore_dll_config; msm_host->var_ops = var_info->var_ops; msm_host->offset = var_info->offset; + msm_host->uses_tassadar_dll = var_info->uses_tassadar_dll; msm_offset = msm_host->offset; From 04816e672d46a1aabb1a35d73ca5f90d6d252ca3 Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 22 May 2020 15:02:26 +0530 Subject: [PATCH 097/127] mmc: sdhci-msm: Update dll_config_3 as per HSR Update dll_config_3 as per the host clock frequency as specified in the DLL Hardware Reference Guide. Signed-off-by: Sarthak Garg Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1590139950-7288-5-git-send-email-sartgarg@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 6588077590dd..054b1512c446 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -62,6 +62,9 @@ #define FINE_TUNE_MODE_EN BIT(27) #define BIAS_OK_SIGNAL BIT(29) +#define DLL_CONFIG_3_LOW_FREQ_VAL 0x08 +#define DLL_CONFIG_3_HIGH_FREQ_VAL 0x10 + #define CORE_VENDOR_SPEC_POR_VAL 0xa9c #define CORE_CLK_PWRSAVE BIT(1) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) @@ -695,6 +698,16 @@ static int msm_init_cm_dll(struct sdhci_host *host) ENABLE_DLL_LOCK_STATUS | BIAS_OK_SIGNAL; writel_relaxed(config, host->ioaddr + msm_offset->core_dll_usr_ctl); + + config = readl_relaxed(host->ioaddr + + msm_offset->core_dll_config_3); + config &= ~0xFF; + if (msm_host->clk_rate < 150000000) + config |= DLL_CONFIG_3_LOW_FREQ_VAL; + else + config |= DLL_CONFIG_3_HIGH_FREQ_VAL; + writel_relaxed(config, host->ioaddr + + msm_offset->core_dll_config_3); } config = readl_relaxed(host->ioaddr + From 1dfbe3ff81f941bb0b39ea6b9f2e8771ef4cb3ea Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 22 May 2020 15:02:27 +0530 Subject: [PATCH 098/127] mmc: sdhci-msm: Update DDR_CONFIG as per device tree file Certain platforms require different settings in the SDCC_HC_REG_DDR_CONFIG register. This setting can change from platform to platform. So the driver should check whether a particular platform require a different setting by reading the device tree file and use it. Signed-off-by: Bao D. Nguyen Signed-off-by: Sarthak Garg Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1590139950-7288-6-git-send-email-sartgarg@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 054b1512c446..1e406f500ffc 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -275,6 +275,7 @@ struct sdhci_msm_host { u32 transfer_mode; bool updated_ddr_cfg; bool uses_tassadar_dll; + u32 ddr_config; }; static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host) @@ -987,7 +988,7 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host) ddr_cfg_offset = msm_offset->core_ddr_config; else ddr_cfg_offset = msm_offset->core_ddr_config_old; - writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + ddr_cfg_offset); + writel_relaxed(msm_host->ddr_config, host->ioaddr + ddr_cfg_offset); if (mmc->ios.enhanced_strobe) { config = readl_relaxed(host->ioaddr + @@ -1933,6 +1934,19 @@ static const struct sdhci_pltfm_data sdhci_msm_pdata = { .ops = &sdhci_msm_ops, }; +static inline void sdhci_msm_get_of_property(struct platform_device *pdev, + struct sdhci_host *host) +{ + struct device_node *node = pdev->dev.of_node; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + + if (of_property_read_u32(node, "qcom,ddr-config", + &msm_host->ddr_config)) + msm_host->ddr_config = DDR_CONFIG_POR_VAL; +} + + static int sdhci_msm_probe(struct platform_device *pdev) { struct sdhci_host *host; @@ -1976,6 +1990,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_offset = msm_host->offset; sdhci_get_of_property(pdev); + sdhci_msm_get_of_property(pdev, host); msm_host->saved_tuning_phase = INVALID_TUNING_PHASE; From 03591160ca192df258890d411f16fe20ec196940 Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 22 May 2020 15:02:28 +0530 Subject: [PATCH 099/127] mmc: sdhci-msm: Read and use DLL Config property from device tree file Certain platforms require different settings in the SDCC_HC_REG_DLL_CONFIG register. This setting can change from platform to platform. So the driver should check whether a particular platform require a different setting by reading the DT file and use it. Also use msm_cm_dll_set_freq only when DLL not supplied. Signed-off-by: Bao D. Nguyen Signed-off-by: Sarthak Garg Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1590139950-7288-7-git-send-email-sartgarg@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 1e406f500ffc..61cf0f1da85d 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -275,6 +275,7 @@ struct sdhci_msm_host { u32 transfer_mode; bool updated_ddr_cfg; bool uses_tassadar_dll; + u32 dll_config; u32 ddr_config; }; @@ -617,6 +618,9 @@ static int msm_init_cm_dll(struct sdhci_host *host) config &= ~CORE_CLK_PWRSAVE; writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec); + config = msm_host->dll_config; + writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config); + if (msm_host->use_14lpp_dll_reset) { config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config); @@ -642,7 +646,9 @@ static int msm_init_cm_dll(struct sdhci_host *host) config |= CORE_DLL_PDN; writel_relaxed(config, host->ioaddr + msm_offset->core_dll_config); - msm_cm_dll_set_freq(host); + + if (!msm_host->dll_config) + msm_cm_dll_set_freq(host); if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk)) { @@ -682,7 +688,8 @@ static int msm_init_cm_dll(struct sdhci_host *host) msm_offset->core_dll_config); if (msm_host->use_14lpp_dll_reset) { - msm_cm_dll_set_freq(host); + if (!msm_host->dll_config) + msm_cm_dll_set_freq(host); config = readl_relaxed(host->ioaddr + msm_offset->core_dll_config_2); config &= ~CORE_DLL_CLOCK_DISABLE; @@ -1944,6 +1951,8 @@ static inline void sdhci_msm_get_of_property(struct platform_device *pdev, if (of_property_read_u32(node, "qcom,ddr-config", &msm_host->ddr_config)) msm_host->ddr_config = DDR_CONFIG_POR_VAL; + + of_property_read_u32(node, "qcom,dll-config", &msm_host->dll_config); } From d1fe0762f3c6191bd182d20b5d9c287cb46e667b Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 22 May 2020 15:02:29 +0530 Subject: [PATCH 100/127] mmc: sdhci-msm: Introduce new ops to dump vendor specific registers Introduce new sdhci ops to dump vendor specific registers in the sdhci_dumpregs during error. Signed-off-by: Sahitya Tummala Signed-off-by: Sarthak Garg Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1590139950-7288-8-git-send-email-sartgarg@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 3 +++ drivers/mmc/host/sdhci.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 70bc77dffb34..52a492bd0ddd 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -111,6 +111,9 @@ void sdhci_dumpregs(struct sdhci_host *host) } } + if (host->ops->dump_vendor_regs) + host->ops->dump_vendor_regs(host); + SDHCI_DUMP("============================================\n"); } EXPORT_SYMBOL_GPL(sdhci_dumpregs); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index d628ab6c5a6f..0008bbd27127 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -650,6 +650,7 @@ struct sdhci_ops { unsigned int length); void (*request_done)(struct sdhci_host *host, struct mmc_request *mrq); + void (*dump_vendor_regs)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS From 16d18d893c20564cf097099ade0d6505c835dea5 Mon Sep 17 00:00:00 2001 From: Sarthak Garg Date: Fri, 22 May 2020 15:02:30 +0530 Subject: [PATCH 101/127] mmc: sdhci-msm: dump vendor specific registers during error Implement dump_vendor_registers host operation to print the vendor specific registers in addition to standard SDHC register during error conditions. Signed-off-by: Sahitya Tummala Signed-off-by: Sarthak Garg Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1590139950-7288-9-git-send-email-sartgarg@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 61cf0f1da85d..95cd9735e9a3 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1874,6 +1874,36 @@ static void sdhci_msm_reset(struct sdhci_host *host, u8 mask) sdhci_reset(host, mask); } +#define DRIVER_NAME "sdhci_msm" +#define SDHCI_MSM_DUMP(f, x...) \ + pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) + +void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + const struct sdhci_msm_offset *msm_offset = msm_host->offset; + + SDHCI_MSM_DUMP("----------- VENDOR REGISTER DUMP -----------\n"); + + SDHCI_MSM_DUMP( + "DLL sts: 0x%08x | DLL cfg: 0x%08x | DLL cfg2: 0x%08x\n", + readl_relaxed(host->ioaddr + msm_offset->core_dll_status), + readl_relaxed(host->ioaddr + msm_offset->core_dll_config), + readl_relaxed(host->ioaddr + msm_offset->core_dll_config_2)); + SDHCI_MSM_DUMP( + "DLL cfg3: 0x%08x | DLL usr ctl: 0x%08x | DDR cfg: 0x%08x\n", + readl_relaxed(host->ioaddr + msm_offset->core_dll_config_3), + readl_relaxed(host->ioaddr + msm_offset->core_dll_usr_ctl), + readl_relaxed(host->ioaddr + msm_offset->core_ddr_config)); + SDHCI_MSM_DUMP( + "Vndr func: 0x%08x | Vndr func2 : 0x%08x Vndr func3: 0x%08x\n", + readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec), + readl_relaxed(host->ioaddr + + msm_offset->core_vendor_spec_func2), + readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec3)); +} + static const struct sdhci_msm_variant_ops mci_var_ops = { .msm_readl_relaxed = sdhci_msm_mci_variant_readl_relaxed, .msm_writel_relaxed = sdhci_msm_mci_variant_writel_relaxed, @@ -1929,6 +1959,7 @@ static const struct sdhci_ops sdhci_msm_ops = { .write_w = sdhci_msm_writew, .write_b = sdhci_msm_writeb, .irq = sdhci_msm_cqe_irq, + .dump_vendor_regs = sdhci_msm_dump_vendor_regs, }; static const struct sdhci_pltfm_data sdhci_msm_pdata = { From 47e9e107fa31fcdd9eb82b22b7b0ab3c987eb576 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Fri, 22 May 2020 11:12:56 +0800 Subject: [PATCH 102/127] mmc: sdhci-of-esdhc: exit HS400 properly before setting any speed mode The eSDHC HS400 timing requires many specific registers setting, unlike other speed modes which need to set only host controller 2 register. When driver needs to downgrade HS400 mode to other speed mode, the controller have to exit HS400 timing properly first. This patch is to support the procedure of HS400 exiting at the beginning of esdhc_set_uhs_signaling. Signed-off-by: Yangbo Lu Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/20200522031256.856-1-yangbo.lu@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-esdhc.c | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 5d8dd870bd44..7c73d243dc6c 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -1135,6 +1135,40 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) { + u32 val; + + /* + * There are specific registers setting for HS400 mode. + * Clean all of them if controller is in HS400 mode to + * exit HS400 mode before re-setting any speed mode. + */ + val = sdhci_readl(host, ESDHC_TBCTL); + if (val & ESDHC_HS400_MODE) { + val = sdhci_readl(host, ESDHC_SDTIMNGCTL); + val &= ~ESDHC_FLW_CTL_BG; + sdhci_writel(host, val, ESDHC_SDTIMNGCTL); + + val = sdhci_readl(host, ESDHC_SDCLKCTL); + val &= ~ESDHC_CMD_CLK_CTL; + sdhci_writel(host, val, ESDHC_SDCLKCTL); + + esdhc_clock_enable(host, false); + val = sdhci_readl(host, ESDHC_TBCTL); + val &= ~ESDHC_HS400_MODE; + sdhci_writel(host, val, ESDHC_TBCTL); + esdhc_clock_enable(host, true); + + val = sdhci_readl(host, ESDHC_DLLCFG0); + val &= ~(ESDHC_DLL_ENABLE | ESDHC_DLL_FREQ_SEL); + sdhci_writel(host, val, ESDHC_DLLCFG0); + + val = sdhci_readl(host, ESDHC_TBCTL); + val &= ~ESDHC_HS400_WNDW_ADJUST; + sdhci_writel(host, val, ESDHC_TBCTL); + + esdhc_tuning_block_enable(host, false); + } + if (timing == MMC_TIMING_MMC_HS400) esdhc_tuning_block_enable(host, true); else From 91132078a38d9455b3832da1d68329e91b63ba25 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Mon, 25 May 2020 12:23:24 +0200 Subject: [PATCH 103/127] m68k: coldfire/clk.c: move m5441x specific code Moving specific m5441x clk-related code in more appropriate location, since breaking compilation for other targets. Signed-off-by: Angelo Dureghello Link: https://lore.kernel.org/r/20200525102324.2723438-1-angelo.dureghello@timesys.com Signed-off-by: Ulf Hansson --- arch/m68k/coldfire/clk.c | 15 --------------- arch/m68k/coldfire/m5441x.c | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/m68k/coldfire/clk.c b/arch/m68k/coldfire/clk.c index 75a057445472..7bc666e482eb 100644 --- a/arch/m68k/coldfire/clk.c +++ b/arch/m68k/coldfire/clk.c @@ -73,21 +73,6 @@ struct clk_ops clk_ops1 = { #endif /* MCFPM_PPMCR1 */ #endif /* MCFPM_PPMCR0 */ -static void __clk_enable2(struct clk *clk) -{ - __raw_writel(__raw_readl(MCFSDHC_CLK) | (1 << clk->slot), MCFSDHC_CLK); -} - -static void __clk_disable2(struct clk *clk) -{ - __raw_writel(__raw_readl(MCFSDHC_CLK) & ~(1 << clk->slot), MCFSDHC_CLK); -} - -struct clk_ops clk_ops2 = { - .enable = __clk_enable2, - .disable = __clk_disable2, -}; - struct clk *clk_get(struct device *dev, const char *id) { const char *clk_name = dev ? dev_name(dev) : id ? id : NULL; diff --git a/arch/m68k/coldfire/m5441x.c b/arch/m68k/coldfire/m5441x.c index ffa02de1a3fb..1e5259a652d1 100644 --- a/arch/m68k/coldfire/m5441x.c +++ b/arch/m68k/coldfire/m5441x.c @@ -204,6 +204,21 @@ static struct clk * const disable_clks[] __initconst = { &__clk_1_29, /* uart 9 */ }; +static void __clk_enable2(struct clk *clk) +{ + __raw_writel(__raw_readl(MCFSDHC_CLK) | (1 << clk->slot), MCFSDHC_CLK); +} + +static void __clk_disable2(struct clk *clk) +{ + __raw_writel(__raw_readl(MCFSDHC_CLK) & ~(1 << clk->slot), MCFSDHC_CLK); +} + +struct clk_ops clk_ops2 = { + .enable = __clk_enable2, + .disable = __clk_disable2, +}; + static void __init m5441x_clk_init(void) { unsigned i; From 4bc90f492230af6661bc2021dddd501f7c842334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:02 +0200 Subject: [PATCH 104/127] mmc: sdio: Fix macro name for Marvell device with ID 0x9134 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marvell SDIO device ID 0x9134 is used in SDIO Common CIS (Card Information Structure) and not in SDIO wlan function (with ID 1). SDIO Common CIS is accessed by function ID 0. So change this misleading macro name to SDIO_DEVICE_ID_MARVELL_8887_F0 as it does not refer to wlan function. It refers to function 0. Wlan module on this SDIO card is available at function ID 1 and is identified by different SDIO device ID 0x9135. Kernel quirks for SDIO devices are matched against device ID from SDIO Common CIS. Therefore device ID used in quirk is correct, just has misleading name. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20200522144412.19712-2-pali@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/core/quirks.h | 2 +- include/linux/mmc/sdio_ids.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 3dba15bccce2..472fa2fdcf13 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -139,7 +139,7 @@ static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0, add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING), - SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887WLAN, + SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887_F0, add_limit_rate_quirk, 150000000), END_FIXUP diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 2e9a6e4634eb..96f43e0dc78f 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -59,7 +59,7 @@ #define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104 #define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 #define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128 -#define SDIO_DEVICE_ID_MARVELL_8887WLAN 0x9134 +#define SDIO_DEVICE_ID_MARVELL_8887_F0 0x9134 #define SDIO_VENDOR_ID_MEDIATEK 0x037a From 2849beec3343343b293f33267affbdd7c3f42814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:03 +0200 Subject: [PATCH 105/127] mmc: sdio: Change macro names for Marvell 8688 modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add underscore as separator in Marvell 8688 macro names for better readability and consistency. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20200522144412.19712-3-pali@kernel.org Signed-off-by: Ulf Hansson Acked-by: Ganapathi Bhat --- drivers/net/wireless/marvell/libertas/if_sdio.c | 2 +- include/linux/mmc/sdio_ids.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index acf61b93b782..44fbd0acb87a 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -65,7 +65,7 @@ static const struct sdio_device_id if_sdio_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, - SDIO_DEVICE_ID_MARVELL_8688WLAN) }, + SDIO_DEVICE_ID_MARVELL_8688_WLAN) }, { /* end: all zeroes */ }, }; diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 96f43e0dc78f..7e992a0e6cc0 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -56,8 +56,8 @@ #define SDIO_VENDOR_ID_MARVELL 0x02df #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 -#define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104 -#define SDIO_DEVICE_ID_MARVELL_8688BT 0x9105 +#define SDIO_DEVICE_ID_MARVELL_8688_WLAN 0x9104 +#define SDIO_DEVICE_ID_MARVELL_8688_BT 0x9105 #define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128 #define SDIO_DEVICE_ID_MARVELL_8887_F0 0x9134 From 7d14c687376e6bd33cf42028300838466b95e765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:04 +0200 Subject: [PATCH 106/127] mmc: sdio: Move SDIO IDs from mwifiex driver to common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add _WLAN suffix to macro names for consistency with other Marvell macros. These IDs represents wlan function of combo bt/wlan cards. Other functions of these cards have different IDs. Signed-off-by: Pali Rohár Acked-by: Kalle Valo Link: https://lore.kernel.org/r/20200522144412.19712-4-pali@kernel.org Signed-off-by: Ulf Hansson Acked-by: Ganapathi Bhat --- drivers/net/wireless/marvell/mwifiex/sdio.c | 38 +++++---------------- include/linux/mmc/sdio_ids.h | 10 ++++++ 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 6a2dcb01caf4..a042965962a2 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -480,45 +480,25 @@ static void mwifiex_sdio_coredump(struct device *dev) schedule_work(&card->work); } -/* Device ID for SD8786 */ -#define SDIO_DEVICE_ID_MARVELL_8786 (0x9116) -/* Device ID for SD8787 */ -#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) -/* Device ID for SD8797 */ -#define SDIO_DEVICE_ID_MARVELL_8797 (0x9129) -/* Device ID for SD8897 */ -#define SDIO_DEVICE_ID_MARVELL_8897 (0x912d) -/* Device ID for SD8887 */ -#define SDIO_DEVICE_ID_MARVELL_8887 (0x9135) -/* Device ID for SD8801 */ -#define SDIO_DEVICE_ID_MARVELL_8801 (0x9139) -/* Device ID for SD8977 */ -#define SDIO_DEVICE_ID_MARVELL_8977 (0x9145) -/* Device ID for SD8987 */ -#define SDIO_DEVICE_ID_MARVELL_8987 (0x9149) -/* Device ID for SD8997 */ -#define SDIO_DEVICE_ID_MARVELL_8997 (0x9141) - - /* WLAN IDs */ static const struct sdio_device_id mwifiex_ids[] = { - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786_WLAN), .driver_data = (unsigned long) &mwifiex_sdio_sd8786}, - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787_WLAN), .driver_data = (unsigned long) &mwifiex_sdio_sd8787}, - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_WLAN), .driver_data = (unsigned long) &mwifiex_sdio_sd8797}, - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897_WLAN), .driver_data = (unsigned long) &mwifiex_sdio_sd8897}, - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887_WLAN), .driver_data = (unsigned long)&mwifiex_sdio_sd8887}, - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801_WLAN), .driver_data = (unsigned long)&mwifiex_sdio_sd8801}, - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8977), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8977_WLAN), .driver_data = (unsigned long)&mwifiex_sdio_sd8977}, - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8987), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8987_WLAN), .driver_data = (unsigned long)&mwifiex_sdio_sd8987}, - {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997), + {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997_WLAN), .driver_data = (unsigned long)&mwifiex_sdio_sd8997}, {}, }; diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 7e992a0e6cc0..90361ea7f5ed 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -58,8 +58,18 @@ #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 #define SDIO_DEVICE_ID_MARVELL_8688_WLAN 0x9104 #define SDIO_DEVICE_ID_MARVELL_8688_BT 0x9105 +#define SDIO_DEVICE_ID_MARVELL_8786_WLAN 0x9116 +#define SDIO_DEVICE_ID_MARVELL_8787_WLAN 0x9119 #define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128 +#define SDIO_DEVICE_ID_MARVELL_8797_WLAN 0x9129 +#define SDIO_DEVICE_ID_MARVELL_8897_WLAN 0x912d #define SDIO_DEVICE_ID_MARVELL_8887_F0 0x9134 +#define SDIO_DEVICE_ID_MARVELL_8887_WLAN 0x9135 +#define SDIO_DEVICE_ID_MARVELL_8801_WLAN 0x9139 +#define SDIO_DEVICE_ID_MARVELL_8997_F0 0x9140 +#define SDIO_DEVICE_ID_MARVELL_8997_WLAN 0x9141 +#define SDIO_DEVICE_ID_MARVELL_8977_WLAN 0x9145 +#define SDIO_DEVICE_ID_MARVELL_8987_WLAN 0x9149 #define SDIO_VENDOR_ID_MEDIATEK 0x037a From 649c7d76d87ca2285a82a65d86d99ddb60571e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:05 +0200 Subject: [PATCH 107/127] mmc: sdio: Move SDIO IDs from btmrvl driver to common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define appropriate macro names for consistency with other Marvell macros. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20200522144412.19712-5-pali@kernel.org Signed-off-by: Ulf Hansson Acked-by: Ganapathi Bhat --- drivers/bluetooth/btmrvl_sdio.c | 18 +++++++++--------- include/linux/mmc/sdio_ids.h | 8 ++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 0f3a020703ab..a296f8526433 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -355,31 +355,31 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = { static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8688 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8688_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8688 }, /* Marvell SD8787 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8787 }, /* Marvell SD8787 Bluetooth AMP device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787_BT_AMP), .driver_data = (unsigned long)&btmrvl_sdio_sd8787 }, /* Marvell SD8797 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8797 }, /* Marvell SD8887 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8887 }, /* Marvell SD8897 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8897 }, /* Marvell SD8977 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9146), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8977_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8977 }, /* Marvell SD8987 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x914A), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8987_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8987 }, /* Marvell SD8997 Bluetooth device */ - { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9142), + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8997_BT), .driver_data = (unsigned long)&btmrvl_sdio_sd8997 }, { } /* Terminating entry */ diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 90361ea7f5ed..1237e1048d06 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -60,16 +60,24 @@ #define SDIO_DEVICE_ID_MARVELL_8688_BT 0x9105 #define SDIO_DEVICE_ID_MARVELL_8786_WLAN 0x9116 #define SDIO_DEVICE_ID_MARVELL_8787_WLAN 0x9119 +#define SDIO_DEVICE_ID_MARVELL_8787_BT 0x911a +#define SDIO_DEVICE_ID_MARVELL_8787_BT_AMP 0x911b #define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128 #define SDIO_DEVICE_ID_MARVELL_8797_WLAN 0x9129 +#define SDIO_DEVICE_ID_MARVELL_8797_BT 0x912a #define SDIO_DEVICE_ID_MARVELL_8897_WLAN 0x912d +#define SDIO_DEVICE_ID_MARVELL_8897_BT 0x912e #define SDIO_DEVICE_ID_MARVELL_8887_F0 0x9134 #define SDIO_DEVICE_ID_MARVELL_8887_WLAN 0x9135 +#define SDIO_DEVICE_ID_MARVELL_8887_BT 0x9136 #define SDIO_DEVICE_ID_MARVELL_8801_WLAN 0x9139 #define SDIO_DEVICE_ID_MARVELL_8997_F0 0x9140 #define SDIO_DEVICE_ID_MARVELL_8997_WLAN 0x9141 +#define SDIO_DEVICE_ID_MARVELL_8997_BT 0x9142 #define SDIO_DEVICE_ID_MARVELL_8977_WLAN 0x9145 +#define SDIO_DEVICE_ID_MARVELL_8977_BT 0x9146 #define SDIO_DEVICE_ID_MARVELL_8987_WLAN 0x9149 +#define SDIO_DEVICE_ID_MARVELL_8987_BT 0x914a #define SDIO_VENDOR_ID_MEDIATEK 0x037a From baaa110dcacfd704d182a275c4307baecb81423b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:06 +0200 Subject: [PATCH 108/127] mmc: sdio: Move SDIO IDs from btmtksdio driver to common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define appropriate macro names for consistency with other macros. Signed-off-by: Pali Rohár Reviewed-by: Matthias Brugger Link: https://lore.kernel.org/r/20200522144412.19712-6-pali@kernel.org Signed-off-by: Ulf Hansson Acked-by: Ganapathi Bhat --- drivers/bluetooth/btmtksdio.c | 4 ++-- include/linux/mmc/sdio_ids.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 519788c442ca..bff095be2f97 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -51,9 +51,9 @@ static const struct btmtksdio_data mt7668_data = { }; static const struct sdio_device_id btmtksdio_table[] = { - {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7663), + {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7663), .driver_data = (kernel_ulong_t)&mt7663_data }, - {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7668), + {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7668), .driver_data = (kernel_ulong_t)&mt7668_data }, { } /* Terminating entry */ }; diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 1237e1048d06..c9aca57d4dea 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -80,6 +80,8 @@ #define SDIO_DEVICE_ID_MARVELL_8987_BT 0x914a #define SDIO_VENDOR_ID_MEDIATEK 0x037a +#define SDIO_DEVICE_ID_MEDIATEK_MT7663 0x7663 +#define SDIO_DEVICE_ID_MEDIATEK_MT7668 0x7668 #define SDIO_VENDOR_ID_SIANO 0x039a #define SDIO_DEVICE_ID_SIANO_NOVA_B0 0x0201 From b8c26a9663e1d888bbf4e14d3a62d033f286623e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:07 +0200 Subject: [PATCH 109/127] mmc: sdio: Move SDIO IDs from smssdio driver to common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define appropriate macro names for consistency with other Siano macros. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20200522144412.19712-7-pali@kernel.org Signed-off-by: Ulf Hansson --- drivers/media/mmc/siano/smssdio.c | 10 +++++----- include/linux/mmc/sdio_ids.h | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/media/mmc/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c index def5e93849d2..065b572e0272 100644 --- a/drivers/media/mmc/siano/smssdio.c +++ b/drivers/media/mmc/siano/smssdio.c @@ -58,15 +58,15 @@ static const struct sdio_device_id smssdio_ids[] = { .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE), .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x302), + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_MING), .driver_data = SMS1XXX_BOARD_SIANO_MING}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x500), + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_PELE), .driver_data = SMS1XXX_BOARD_SIANO_PELE}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x600), + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_RIO), .driver_data = SMS1XXX_BOARD_SIANO_RIO}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x700), + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_DENVER_2160), .driver_data = SMS1XXX_BOARD_SIANO_DENVER_2160}, - {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x800), + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_DENVER_1530), .driver_data = SMS1XXX_BOARD_SIANO_DENVER_1530}, { /* end: all zeroes */ }, }; diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index c9aca57d4dea..9ec675a7ac37 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -88,6 +88,11 @@ #define SDIO_DEVICE_ID_SIANO_NICE 0x0202 #define SDIO_DEVICE_ID_SIANO_VEGA_A0 0x0300 #define SDIO_DEVICE_ID_SIANO_VENICE 0x0301 +#define SDIO_DEVICE_ID_SIANO_MING 0x0302 +#define SDIO_DEVICE_ID_SIANO_PELE 0x0500 +#define SDIO_DEVICE_ID_SIANO_RIO 0x0600 +#define SDIO_DEVICE_ID_SIANO_DENVER_2160 0x0700 +#define SDIO_DEVICE_ID_SIANO_DENVER_1530 0x0800 #define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100 #define SDIO_DEVICE_ID_SIANO_STELLAR 0x5347 From ecc2f3962587aed327ccd3c32e99ccfc9e744fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:08 +0200 Subject: [PATCH 110/127] mmc: sdio: Move SDIO IDs from ath6kl driver to common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also replace generic MANUFACTURER macros by proper SDIO IDs macros. Check for "AR6003 or later" is slightly modified to use SDIO device IDs. This allows removal of all custom MANUFACTURER macros from ath6kl. Signed-off-by: Pali Rohár Acked-by: Kalle Valo Link: https://lore.kernel.org/r/20200522144412.19712-8-pali@kernel.org Signed-off-by: Ulf Hansson --- drivers/net/wireless/ath/ath6kl/hif.h | 6 ------ drivers/net/wireless/ath/ath6kl/sdio.c | 17 ++++++++--------- include/linux/mmc/sdio_ids.h | 10 ++++++++++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h index dc6bd8cd9b83..c6dafc38936a 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.h +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -35,12 +35,6 @@ #define MAX_SCATTER_ENTRIES_PER_REQ 16 #define MAX_SCATTER_REQ_TRANSFER_SIZE (32 * 1024) -#define MANUFACTURER_ID_AR6003_BASE 0x300 -#define MANUFACTURER_ID_AR6004_BASE 0x400 - /* SDIO manufacturer ID and Codes */ -#define MANUFACTURER_ID_ATH6KL_BASE_MASK 0xFF00 -#define MANUFACTURER_CODE 0x271 /* Atheros */ - /* Mailbox address in SDIO address space */ #define HIF_MBOX_BASE_ADDR 0x800 #define HIF_MBOX_WIDTH 0x800 diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index bb50680580f3..6b51a2dceadc 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -799,8 +799,7 @@ static int ath6kl_sdio_config(struct ath6kl *ar) sdio_claim_host(func); - if ((ar_sdio->id->device & MANUFACTURER_ID_ATH6KL_BASE_MASK) >= - MANUFACTURER_ID_AR6003_BASE) { + if (ar_sdio->id->device >= SDIO_DEVICE_ID_ATHEROS_AR6003_00) { /* enable 4-bit ASYNC interrupt on AR6003 or later */ ret = ath6kl_sdio_func0_cmd52_wr_byte(func->card, CCCR_SDIO_IRQ_MODE_REG, @@ -1409,13 +1408,13 @@ static void ath6kl_sdio_remove(struct sdio_func *func) } static const struct sdio_device_id ath6kl_sdio_devices[] = { - {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))}, - {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))}, - {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))}, - {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))}, - {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))}, - {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x18))}, - {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x19))}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_AR6003_00)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_AR6003_01)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_AR6004_00)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_AR6004_01)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_AR6004_02)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_AR6004_18)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_AR6004_19)}, {}, }; diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 9ec675a7ac37..95b67ab7d06a 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -24,6 +24,16 @@ /* * Vendors and devices. Sort key: vendor first, device next. */ + +#define SDIO_VENDOR_ID_ATHEROS 0x0271 +#define SDIO_DEVICE_ID_ATHEROS_AR6003_00 0x0300 +#define SDIO_DEVICE_ID_ATHEROS_AR6003_01 0x0301 +#define SDIO_DEVICE_ID_ATHEROS_AR6004_00 0x0400 +#define SDIO_DEVICE_ID_ATHEROS_AR6004_01 0x0401 +#define SDIO_DEVICE_ID_ATHEROS_AR6004_02 0x0402 +#define SDIO_DEVICE_ID_ATHEROS_AR6004_18 0x0418 +#define SDIO_DEVICE_ID_ATHEROS_AR6004_19 0x0419 + #define SDIO_VENDOR_ID_BROADCOM 0x02d0 #define SDIO_DEVICE_ID_BROADCOM_43143 0xa887 #define SDIO_DEVICE_ID_BROADCOM_43241 0x4324 From 4dc28c948f480c5004613aab153c7160bd4f29ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:09 +0200 Subject: [PATCH 111/127] mmc: sdio: Move SDIO IDs from ath10k driver to common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also replace generic MANUFACTURER macros by proper SDIO IDs macros. Checks for device IDs are slightly modified to use SDIO device IDs. This allows removal of all custom MANUFACTURER macros from ath10k. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20200522144412.19712-9-pali@kernel.org Signed-off-by: Ulf Hansson --- drivers/net/wireless/ath/ath10k/sdio.c | 25 ++++++++++--------------- drivers/net/wireless/ath/ath10k/sdio.h | 8 -------- include/linux/mmc/sdio_ids.h | 2 ++ 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 1f709b65c29b..59e725515041 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -1083,10 +1083,10 @@ static void ath10k_sdio_set_mbox_info(struct ath10k *ar) mbox_info->ext_info[0].htc_ext_addr = ATH10K_HIF_MBOX0_EXT_BASE_ADDR; - dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, device); - dev_id_chiprev = FIELD_GET(QCA_MANUFACTURER_ID_REV_MASK, device); + dev_id_base = (device & 0x0F00); + dev_id_chiprev = (device & 0x00FF); switch (dev_id_base) { - case QCA_MANUFACTURER_ID_AR6005_BASE: + case (SDIO_DEVICE_ID_ATHEROS_AR6005 & 0x0F00): if (dev_id_chiprev < 4) mbox_info->ext_info[0].htc_ext_sz = ATH10K_HIF_MBOX0_EXT_WIDTH; @@ -1097,7 +1097,7 @@ static void ath10k_sdio_set_mbox_info(struct ath10k *ar) mbox_info->ext_info[0].htc_ext_sz = ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0; break; - case QCA_MANUFACTURER_ID_QCA9377_BASE: + case (SDIO_DEVICE_ID_ATHEROS_QCA9377 & 0x0F00): mbox_info->ext_info[0].htc_ext_sz = ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0; break; @@ -2185,19 +2185,16 @@ static int ath10k_sdio_probe(struct sdio_func *func, skb_queue_head_init(&ar_sdio->rx_head); INIT_WORK(&ar_sdio->async_work_rx, ath10k_rx_indication_async_work); - dev_id_base = FIELD_GET(QCA_MANUFACTURER_ID_BASE, id->device); - switch (dev_id_base) { - case QCA_MANUFACTURER_ID_AR6005_BASE: - case QCA_MANUFACTURER_ID_QCA9377_BASE: - ar->dev_id = QCA9377_1_0_DEVICE_ID; - break; - default: + dev_id_base = (id->device & 0x0F00); + if (dev_id_base != (SDIO_DEVICE_ID_ATHEROS_AR6005 & 0x0F00) && + dev_id_base != (SDIO_DEVICE_ID_ATHEROS_QCA9377 & 0x0F00)) { ret = -ENODEV; ath10k_err(ar, "unsupported device id %u (0x%x)\n", dev_id_base, id->device); goto err_free_wq; } + ar->dev_id = QCA9377_1_0_DEVICE_ID; ar->id.vendor = id->vendor; ar->id.device = id->device; @@ -2246,10 +2243,8 @@ static void ath10k_sdio_remove(struct sdio_func *func) } static const struct sdio_device_id ath10k_sdio_devices[] = { - {SDIO_DEVICE(QCA_MANUFACTURER_CODE, - (QCA_SDIO_ID_AR6005_BASE | 0xA))}, - {SDIO_DEVICE(QCA_MANUFACTURER_CODE, - (QCA_SDIO_ID_QCA9377_BASE | 0x1))}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_AR6005)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_ATHEROS, SDIO_DEVICE_ID_ATHEROS_QCA9377)}, {}, }; diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h index 33195f49acab..e8951f9cdb5f 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.h +++ b/drivers/net/wireless/ath/ath10k/sdio.h @@ -10,14 +10,6 @@ #define ATH10K_HIF_MBOX_BLOCK_SIZE 256 -#define QCA_MANUFACTURER_ID_BASE GENMASK(11, 8) -#define QCA_MANUFACTURER_ID_AR6005_BASE 0x5 -#define QCA_MANUFACTURER_ID_QCA9377_BASE 0x7 -#define QCA_SDIO_ID_AR6005_BASE 0x500 -#define QCA_SDIO_ID_QCA9377_BASE 0x700 -#define QCA_MANUFACTURER_ID_REV_MASK 0x00FF -#define QCA_MANUFACTURER_CODE 0x271 /* Qualcomm/Atheros */ - #define ATH10K_SDIO_MAX_BUFFER_SIZE 4096 /*Unsure of this constant*/ /* Mailbox address in SDIO address space */ diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 95b67ab7d06a..2894f7739acc 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -33,6 +33,8 @@ #define SDIO_DEVICE_ID_ATHEROS_AR6004_02 0x0402 #define SDIO_DEVICE_ID_ATHEROS_AR6004_18 0x0418 #define SDIO_DEVICE_ID_ATHEROS_AR6004_19 0x0419 +#define SDIO_DEVICE_ID_ATHEROS_AR6005 0x050A +#define SDIO_DEVICE_ID_ATHEROS_QCA9377 0x0701 #define SDIO_VENDOR_ID_BROADCOM 0x02d0 #define SDIO_DEVICE_ID_BROADCOM_43143 0xa887 From 8baa6d1bce05cf26eec6b43bcd428735f33cb60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:10 +0200 Subject: [PATCH 112/127] mmc: sdio: Move SDIO IDs from b43-sdio driver to common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define appropriate macro names for consistency with other macros. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20200522144412.19712-10-pali@kernel.org Signed-off-by: Ulf Hansson --- drivers/net/wireless/broadcom/b43/sdio.c | 4 ++-- include/linux/mmc/sdio_ids.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/b43/sdio.c b/drivers/net/wireless/broadcom/b43/sdio.c index 881a7938c494..02b0cfd535ab 100644 --- a/drivers/net/wireless/broadcom/b43/sdio.c +++ b/drivers/net/wireless/broadcom/b43/sdio.c @@ -180,8 +180,8 @@ static void b43_sdio_remove(struct sdio_func *func) } static const struct sdio_device_id b43_sdio_ids[] = { - { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */ - { SDIO_DEVICE(0x0092, 0x0004) }, /* C-guys, Inc. EW-CG1102GC */ + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_NINTENDO_WII) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_CGUYS, SDIO_DEVICE_ID_CGUYS_EW_CG1102GC) }, { }, }; diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 2894f7739acc..8e7a0683b927 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -25,6 +25,9 @@ * Vendors and devices. Sort key: vendor first, device next. */ +#define SDIO_VENDOR_ID_CGUYS 0x0092 +#define SDIO_DEVICE_ID_CGUYS_EW_CG1102GC 0x0004 + #define SDIO_VENDOR_ID_ATHEROS 0x0271 #define SDIO_DEVICE_ID_ATHEROS_AR6003_00 0x0300 #define SDIO_DEVICE_ID_ATHEROS_AR6003_01 0x0301 @@ -37,6 +40,7 @@ #define SDIO_DEVICE_ID_ATHEROS_QCA9377 0x0701 #define SDIO_VENDOR_ID_BROADCOM 0x02d0 +#define SDIO_DEVICE_ID_BROADCOM_NINTENDO_WII 0x044b #define SDIO_DEVICE_ID_BROADCOM_43143 0xa887 #define SDIO_DEVICE_ID_BROADCOM_43241 0x4324 #define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 From 1eb911258805695c8f85795d3d4cdbd1e84fc2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:11 +0200 Subject: [PATCH 113/127] mmc: sdio: Fix Cypress SDIO IDs macros in common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All macro names for SDIO device IDs are prefixed by vendor name to which device ID belongs. So for consistency add Broadcom string vendor prefix to all Cypress macro names as they belong to SDIO Broadcom vendor ID. Change also Cypress 43012 value from decimal do hexadecimal notation to be consistent with all other values. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20200522144412.19712-11-pali@kernel.org Signed-off-by: Ulf Hansson --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 +++--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 4 ++-- include/linux/mmc/sdio_ids.h | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index b684a5b6d904..a1fdb618cf14 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -970,9 +970,9 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359), - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373), - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_43012), - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_89359), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359), { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 3a08252f1a53..1c9561665a67 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -4187,7 +4187,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, bus->hostintmask, NULL); switch (sdiod->func1->device) { - case SDIO_DEVICE_ID_CYPRESS_4373: + case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373: brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", CY_4373_F2_WATERMARK); brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, @@ -4201,7 +4201,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, CY_4373_F2_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB, &err); break; - case SDIO_DEVICE_ID_CYPRESS_43012: + case SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012: brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", CY_43012_F2_WATERMARK); brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 8e7a0683b927..b19200aea56a 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -58,9 +58,9 @@ #define SDIO_DEVICE_ID_BROADCOM_4354 0x4354 #define SDIO_DEVICE_ID_BROADCOM_4356 0x4356 #define SDIO_DEVICE_ID_BROADCOM_4359 0x4359 -#define SDIO_DEVICE_ID_CYPRESS_4373 0x4373 -#define SDIO_DEVICE_ID_CYPRESS_43012 43012 -#define SDIO_DEVICE_ID_CYPRESS_89359 0x4355 +#define SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373 0x4373 +#define SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012 0xa804 +#define SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359 0x4355 #define SDIO_VENDOR_ID_INTEL 0x0089 #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402 From 798dd3c311f6c862719a3fc71c3c14eba192c64e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 22 May 2020 16:44:12 +0200 Subject: [PATCH 114/127] mmc: sdio: Sort all SDIO IDs in common include file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix ordering of SDIO IDs to conform to the comment above, which says vendor first, device next. Signed-off-by: Pali Rohár Link: https://lore.kernel.org/r/20200522144412.19712-12-pali@kernel.org Signed-off-by: Ulf Hansson --- include/linux/mmc/sdio_ids.h | 43 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index b19200aea56a..15ed8ce9d394 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -25,9 +25,23 @@ * Vendors and devices. Sort key: vendor first, device next. */ +#define SDIO_VENDOR_ID_STE 0x0020 +#define SDIO_DEVICE_ID_STE_CW1200 0x2280 + +#define SDIO_VENDOR_ID_INTEL 0x0089 +#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402 +#define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403 +#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404 +#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405 +#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406 +#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5 0x1407 + #define SDIO_VENDOR_ID_CGUYS 0x0092 #define SDIO_DEVICE_ID_CGUYS_EW_CG1102GC 0x0004 +#define SDIO_VENDOR_ID_TI 0x0097 +#define SDIO_DEVICE_ID_TI_WL1271 0x4076 + #define SDIO_VENDOR_ID_ATHEROS 0x0271 #define SDIO_DEVICE_ID_ATHEROS_AR6003_00 0x0300 #define SDIO_DEVICE_ID_ATHEROS_AR6003_01 0x0301 @@ -41,34 +55,26 @@ #define SDIO_VENDOR_ID_BROADCOM 0x02d0 #define SDIO_DEVICE_ID_BROADCOM_NINTENDO_WII 0x044b -#define SDIO_DEVICE_ID_BROADCOM_43143 0xa887 #define SDIO_DEVICE_ID_BROADCOM_43241 0x4324 #define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 #define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 #define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 -#define SDIO_DEVICE_ID_BROADCOM_43340 0xa94c -#define SDIO_DEVICE_ID_BROADCOM_43341 0xa94d #define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335 #define SDIO_DEVICE_ID_BROADCOM_4339 0x4339 -#define SDIO_DEVICE_ID_BROADCOM_43362 0xa962 -#define SDIO_DEVICE_ID_BROADCOM_43364 0xa9a4 -#define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6 #define SDIO_DEVICE_ID_BROADCOM_4345 0x4345 -#define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf #define SDIO_DEVICE_ID_BROADCOM_4354 0x4354 +#define SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359 0x4355 #define SDIO_DEVICE_ID_BROADCOM_4356 0x4356 #define SDIO_DEVICE_ID_BROADCOM_4359 0x4359 #define SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373 0x4373 #define SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012 0xa804 -#define SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359 0x4355 - -#define SDIO_VENDOR_ID_INTEL 0x0089 -#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402 -#define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403 -#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404 -#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405 -#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406 -#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5 0x1407 +#define SDIO_DEVICE_ID_BROADCOM_43143 0xa887 +#define SDIO_DEVICE_ID_BROADCOM_43340 0xa94c +#define SDIO_DEVICE_ID_BROADCOM_43341 0xa94d +#define SDIO_DEVICE_ID_BROADCOM_43362 0xa962 +#define SDIO_DEVICE_ID_BROADCOM_43364 0xa9a4 +#define SDIO_DEVICE_ID_BROADCOM_43430 0xa9a6 +#define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf #define SDIO_VENDOR_ID_MARVELL 0x02df #define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103 @@ -112,12 +118,7 @@ #define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100 #define SDIO_DEVICE_ID_SIANO_STELLAR 0x5347 -#define SDIO_VENDOR_ID_TI 0x0097 -#define SDIO_DEVICE_ID_TI_WL1271 0x4076 #define SDIO_VENDOR_ID_TI_WL1251 0x104c #define SDIO_DEVICE_ID_TI_WL1251 0x9066 -#define SDIO_VENDOR_ID_STE 0x0020 -#define SDIO_DEVICE_ID_STE_CW1200 0x2280 - #endif /* LINUX_MMC_SDIO_IDS_H */ From f6bc8186a588627c7faf3f2f2615e4c0e4d454a6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 25 May 2020 10:40:53 +0300 Subject: [PATCH 115/127] mmc: sdhci-cadence: fix PHY write Accordingly to Cadence documentation, PHY write procedure is: 1. Software sets the PHY Register Address (HRS04[5:0]) and the PHY Write Data (HRS04[15:8]) fields. 2. Software sets the PHY Write Transaction Request (HRS04[24]) field to 1. 3. Software waits as the PHY Write Transaction Acknowledge (HRS04[26]) field is equal to 0. 4. Hardware performs the write transaction to PHY register where HRS04[15:8] is a data written to register under HRS04[5:0] address. 5. Hardware sets the PHY Transaction Acknowledge (HRS04[26]) to 1 when transaction is completed. 6. Software clears the PHY Write Transaction Request (HRS04[24]) to 1 after noticing that the PHY Write Transaction Acknowledge (HRS04[26]) field is equal to 1. 7. Software waits for the PHY Acknowledge Register (HRS04[26]) field is equal to 0. Add missing steps 3 and 7. Lack of these steps causes integrity errors detested by hardware. Signed-off-by: Vladimir Kondratiev Link: https://lore.kernel.org/r/20200525074053.7309-1-vladimir.kondratiev@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-cadence.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 6da6d4fb5edd..4a6c9ba82538 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -97,6 +97,11 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv, u32 tmp; int ret; + ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK), + 0, 10); + if (ret) + return ret; + tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) | FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr); writel(tmp, reg); @@ -111,7 +116,10 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv, tmp &= ~SDHCI_CDNS_HRS04_WR; writel(tmp, reg); - return 0; + ret = readl_poll_timeout(reg, tmp, !(tmp & SDHCI_CDNS_HRS04_ACK), + 0, 10); + + return ret; } static unsigned int sdhci_cdns_phy_param_count(struct device_node *np) From ce3fefacfb028c9ce0fde464adf2e372fb156599 Mon Sep 17 00:00:00 2001 From: Wan Ahmad Zainie Date: Tue, 26 May 2020 14:27:56 +0800 Subject: [PATCH 116/127] dt-bindings: mmc: arasan: Add compatible strings for Intel Keem Bay Add new compatible strings in sdhci-of-arasan.c to support Intel Keem Bay eMMC/SD/SDIO controller, based on Arasan SDHCI 5.1. Signed-off-by: Wan Ahmad Zainie Link: https://lore.kernel.org/r/20200526062758.17642-2-wan.ahmad.zainie.wan.mohamad@intel.com Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/arasan,sdhci.txt | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt index 630fe707f5c4..f29bf7dd2ece 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt @@ -27,6 +27,12 @@ Required Properties: For this device it is strongly suggested to include arasan,soc-ctl-syscon. - "intel,lgm-sdhci-5.1-sdxc", "arasan,sdhci-5.1": Intel LGM SDXC PHY For this device it is strongly suggested to include arasan,soc-ctl-syscon. + - "intel,keembay-sdhci-5.1-emmc", "arasan,sdhci-5.1": Intel Keem Bay eMMC + For this device it is strongly suggested to include arasan,soc-ctl-syscon. + - "intel,keembay-sdhci-5.1-sd": Intel Keem Bay SD controller + For this device it is strongly suggested to include arasan,soc-ctl-syscon. + - "intel,keembay-sdhci-5.1-sdio": Intel Keem Bay SDIO controller + For this device it is strongly suggested to include arasan,soc-ctl-syscon. [5] Documentation/devicetree/bindings/mmc/sdhci-am654.txt @@ -148,3 +154,39 @@ Example: phy-names = "phy_arasan"; arasan,soc-ctl-syscon = <&sysconf>; }; + + mmc: mmc@33000000 { + compatible = "intel,keembay-sdhci-5.1-emmc", "arasan,sdhci-5.1"; + interrupts = ; + reg = <0x0 0x33000000 0x0 0x300>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&scmi_clk KEEM_BAY_PSS_AUX_EMMC>, + <&scmi_clk KEEM_BAY_PSS_EMMC>; + phys = <&emmc_phy>; + phy-names = "phy_arasan"; + assigned-clocks = <&scmi_clk KEEM_BAY_PSS_AUX_EMMC>; + assigned-clock-rates = <200000000>; + clock-output-names = "emmc_cardclock"; + #clock-cells = <0>; + arasan,soc-ctl-syscon = <&mmc_phy_syscon>; + }; + + sd0: mmc@31000000 { + compatible = "intel,keembay-sdhci-5.1-sd"; + interrupts = ; + reg = <0x0 0x31000000 0x0 0x300>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&scmi_clk KEEM_BAY_PSS_AUX_SD0>, + <&scmi_clk KEEM_BAY_PSS_SD0>; + arasan,soc-ctl-syscon = <&sd0_phy_syscon>; + }; + + sd1: mmc@32000000 { + compatible = "intel,keembay-sdhci-5.1-sdio"; + interrupts = ; + reg = <0x0 0x32000000 0x0 0x300>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&scmi_clk KEEM_BAY_PSS_AUX_SD1>, + <&scmi_clk KEEM_BAY_PSS_SD1>; + arasan,soc-ctl-syscon = <&sd1_phy_syscon>; + }; From 36c6aadaae863024eae31dfce94db20a4514563d Mon Sep 17 00:00:00 2001 From: Wan Ahmad Zainie Date: Tue, 26 May 2020 14:27:57 +0800 Subject: [PATCH 117/127] mmc: sdhci-of-arasan: Add support for Intel Keem Bay Intel Keem Bay SoC eMMC/SD/SDIO controller is based on Arasan SD 3.0 / eMMC 5.1 host controller IP. However, it does not support 64-bit access as its AXI interface has 32-bit address ports. Signed-off-by: Wan Ahmad Zainie Reviewed-by: Adrian Hunter Link: https://lore.kernel.org/r/20200526062758.17642-3-wan.ahmad.zainie.wan.mohamad@intel.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-arasan.c | 123 +++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 18bf0e76b1eb..2a4c8a2f3e64 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -75,6 +75,7 @@ struct sdhci_arasan_soc_ctl_field { * * @baseclkfreq: Where to find corecfg_baseclkfreq * @clockmultiplier: Where to find corecfg_clockmultiplier + * @support64b: Where to find SUPPORT64B bit * @hiword_update: If true, use HIWORD_UPDATE to access the syscon * * It's up to the licensee of the Arsan IP block to make these available @@ -84,6 +85,7 @@ struct sdhci_arasan_soc_ctl_field { struct sdhci_arasan_soc_ctl_map { struct sdhci_arasan_soc_ctl_field baseclkfreq; struct sdhci_arasan_soc_ctl_field clockmultiplier; + struct sdhci_arasan_soc_ctl_field support64b; bool hiword_update; }; @@ -184,6 +186,13 @@ static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { .hiword_update = false, }; +static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = { + .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, + .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, + .support64b = { .reg = 0x4, .width = 1, .shift = 24 }, + .hiword_update = false, +}; + /** * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers * @@ -1113,6 +1122,50 @@ static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { .clk_ops = &arasan_clk_ops, }; +static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = { + .ops = &sdhci_arasan_cqe_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED | + SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_32BIT_DMA_SIZE | + SDHCI_QUIRK_32BIT_ADMA_SIZE, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | + SDHCI_QUIRK2_STOP_WITH_TC | + SDHCI_QUIRK2_BROKEN_64_BIT_DMA, +}; + +static const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = { + .ops = &sdhci_arasan_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED | + SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_32BIT_DMA_SIZE | + SDHCI_QUIRK_32BIT_ADMA_SIZE, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | + SDHCI_QUIRK2_STOP_WITH_TC | + SDHCI_QUIRK2_BROKEN_64_BIT_DMA, +}; + +static const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = { + .ops = &sdhci_arasan_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_NO_LED | + SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_32BIT_DMA_SIZE | + SDHCI_QUIRK_32BIT_ADMA_SIZE, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | + SDHCI_QUIRK2_HOST_OFF_CARD_ON | + SDHCI_QUIRK2_BROKEN_64_BIT_DMA, +}; + static struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { .soc_ctl_map = &rk3399_soc_ctl_map, .pdata = &sdhci_arasan_cqe_pdata, @@ -1158,6 +1211,21 @@ static struct sdhci_arasan_of_data sdhci_arasan_versal_data = { .clk_ops = &versal_clk_ops, }; +static struct sdhci_arasan_of_data intel_keembay_emmc_data = { + .soc_ctl_map = &intel_keembay_soc_ctl_map, + .pdata = &sdhci_keembay_emmc_pdata, +}; + +static struct sdhci_arasan_of_data intel_keembay_sd_data = { + .soc_ctl_map = &intel_keembay_soc_ctl_map, + .pdata = &sdhci_keembay_sd_pdata, +}; + +static struct sdhci_arasan_of_data intel_keembay_sdio_data = { + .soc_ctl_map = &intel_keembay_soc_ctl_map, + .pdata = &sdhci_keembay_sdio_pdata, +}; + static const struct of_device_id sdhci_arasan_of_match[] = { /* SoC-specific compatible strings w/ soc_ctl_map */ { @@ -1172,6 +1240,18 @@ static const struct of_device_id sdhci_arasan_of_match[] = { .compatible = "intel,lgm-sdhci-5.1-sdxc", .data = &intel_lgm_sdxc_data, }, + { + .compatible = "intel,keembay-sdhci-5.1-emmc", + .data = &intel_keembay_emmc_data, + }, + { + .compatible = "intel,keembay-sdhci-5.1-sd", + .data = &intel_keembay_sd_data, + }, + { + .compatible = "intel,keembay-sdhci-5.1-sdio", + .data = &intel_keembay_sdio_data, + }, /* Generic compatible below here */ { .compatible = "arasan,sdhci-8.9a", @@ -1315,6 +1395,40 @@ static void sdhci_arasan_unregister_sdclk(struct device *dev) of_clk_del_provider(dev->of_node); } +/** + * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support) + * + * This should be set based on the System Address Bus. + * 0: the Core supports only 32-bit System Address Bus. + * 1: the Core supports 64-bit System Address Bus. + * + * NOTES: + * - For Keem Bay, it is required to clear this bit. Its default value is 1'b1. + * Keem Bay does not support 64-bit access. + * + * @host The sdhci_host + */ +static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = + sdhci_arasan->soc_ctl_map; + + /* Having a map is optional */ + if (!soc_ctl_map) + return; + + /* If we have a map, we expect to have a syscon */ + if (!sdhci_arasan->soc_ctl_base) { + pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", + mmc_hostname(host->mmc)); + return; + } + + sdhci_arasan_syscon_write(host, &soc_ctl_map->support64b, value); +} + /** * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use * @@ -1487,6 +1601,15 @@ static int sdhci_arasan_probe(struct platform_device *pdev) "rockchip,rk3399-sdhci-5.1")) sdhci_arasan_update_clockmultiplier(host, 0x0); + if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") || + of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") || + of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) { + sdhci_arasan_update_clockmultiplier(host, 0x0); + sdhci_arasan_update_support64b(host, 0x0); + + host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; + } + sdhci_arasan_update_baseclkfreq(host); ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev); From fe8d33bd33d527dee3155d2bccd714a655f37334 Mon Sep 17 00:00:00 2001 From: Ludovic Barre Date: Tue, 26 May 2020 17:51:02 +0200 Subject: [PATCH 118/127] mmc: mmci_sdmmc: fix DMA API warning overlapping mappings Turning on CONFIG_DMA_API_DEBUG_SG results in the following warning: WARNING: CPU: 1 PID: 20 at kernel/dma/debug.c:500 add_dma_entry+0x16c/0x17c DMA-API: exceeded 7 overlapping mappings of cacheline 0x031d2645 Modules linked in: CPU: 1 PID: 20 Comm: kworker/1:1 Not tainted 5.5.0-rc2-00021-gdeda30999c2b-dirty #49 Hardware name: STM32 (Device Tree Support) Workqueue: events_freezable mmc_rescan [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0xc0/0xd4) [] (dump_stack) from [] (__warn+0xd0/0xf8) [] (__warn) from [] (warn_slowpath_fmt+0x94/0xb8) [] (warn_slowpath_fmt) from [] (add_dma_entry+0x16c/0x17c) [] (add_dma_entry) from [] (debug_dma_map_sg+0xe4/0x3d4) [] (debug_dma_map_sg) from [] (sdmmc_idma_prep_data+0x94/0xf8) [] (sdmmc_idma_prep_data) from [] (mmci_prep_data+0x2c/0xb0) [] (mmci_prep_data) from [] (mmci_start_data+0x134/0x2f0) [] (mmci_start_data) from [] (mmci_request+0xe8/0x154) [] (mmci_request) from [] (mmc_start_request+0x94/0xbc) DMA api debug brings to light leaking dma-mappings, dma_map_sg and dma_unmap_sg are not correctly balanced. If a request is prepared, the dma_map/unmap are done in asynchronous call pre_req (prep_data) and post_req (unprep_data). In this case the dma-mapping is right balanced. But if the request was not prepared, the data->host_cookie is define to zero and the dma_map/unmap must be done in the request. The dma_map is called by mmci_dma_start (prep_data), but there is no dma_unmap in this case. This patch adds dma_unmap_sg when the dma is finalized and the data cookie is zero (request not prepared). Signed-off-by: Ludovic Barre Link: https://lore.kernel.org/r/20200526155103.12514-2-ludovic.barre@st.com Fixes: 46b723dd867d ("mmc: mmci: add stm32 sdmmc variant") Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci_stm32_sdmmc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index 14f99d8aa3f0..2965b1c062e1 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -188,6 +188,9 @@ static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data) { writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); + + if (!data->host_cookie) + sdmmc_idma_unprep_data(host, data, 0); } static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) From 942d5e7bae36153a232102809bdf8b0a5ab110dc Mon Sep 17 00:00:00 2001 From: Ludovic Barre Date: Tue, 26 May 2020 17:51:03 +0200 Subject: [PATCH 119/127] mmc: mmci_sdmmc: fix DMA API warning max segment size Turning on CONFIG_DMA_API_DEBUG_SG results in the following warning: WARNING: CPU: 1 PID: 85 at kernel/dma/debug.c:1302 debug_dma_map_sg+0x2a0/0x3cc mmci-pl18x 58005000.sdmmc: DMA-API: mapping sg segment longer than device claims to support [len=126976] [max=65536] dma api debug checks and compares the segment size to dma_get_max_seg_size (dev->dma_parms->max_segment_size), the sdmmc variant has an internal DMA and should define its max_segment_size constraint to avoid this warning. This Patch defines the dev->dma_parms->max_segment_size with the constraint already set for mmc core (host->mmc->max_seg_size). Signed-off-by: Ludovic Barre Link: https://lore.kernel.org/r/20200526155103.12514-3-ludovic.barre@st.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci_stm32_sdmmc.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index 2965b1c062e1..51db30acf4dc 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -119,20 +119,19 @@ static void sdmmc_idma_unprep_data(struct mmci_host *host, static int sdmmc_idma_setup(struct mmci_host *host) { struct sdmmc_idma *idma; + struct device *dev = mmc_dev(host->mmc); - idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); + idma = devm_kzalloc(dev, sizeof(*idma), GFP_KERNEL); if (!idma) return -ENOMEM; host->dma_priv = idma; if (host->variant->dma_lli) { - idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc), - SDMMC_LLI_BUF_LEN, + idma->sg_cpu = dmam_alloc_coherent(dev, SDMMC_LLI_BUF_LEN, &idma->sg_dma, GFP_KERNEL); if (!idma->sg_cpu) { - dev_err(mmc_dev(host->mmc), - "Failed to alloc IDMA descriptor\n"); + dev_err(dev, "Failed to alloc IDMA descriptor\n"); return -ENOMEM; } host->mmc->max_segs = SDMMC_LLI_BUF_LEN / @@ -143,7 +142,7 @@ static int sdmmc_idma_setup(struct mmci_host *host) host->mmc->max_seg_size = host->mmc->max_req_size; } - return 0; + return dma_set_max_seg_size(dev, host->mmc->max_seg_size); } static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) From f61404626113080863c904a459576ba0c03a49ba Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Wed, 27 May 2020 10:39:35 +0800 Subject: [PATCH 120/127] mmc: host: sdhci-esdhc-imx: add wakeup feature for GPIO CD pin When use the specific GPIO to detect the card insert/remove, we can also add the GPIO as a wakeup source. When system suspend, insert or remove the card can wakeup the system. Signed-off-by: Haibo Chen Link: https://lore.kernel.org/r/1590547175-15070-1-git-send-email-haibo.chen@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 5398af4824c3..5a27511438c8 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1599,6 +1599,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (esdhc_is_usdhc(imx_data)) { host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR; + + /* GPIO CD can be set as a wakeup source */ + host->mmc->caps |= MMC_CAP_CD_WAKE; + if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; @@ -1734,8 +1738,14 @@ static int sdhci_esdhc_suspend(struct device *dev) mmc_retune_needed(host->mmc); ret = sdhci_suspend_host(host); - if (!ret) - return pinctrl_pm_select_sleep_state(dev); + if (ret) + return ret; + + ret = pinctrl_pm_select_sleep_state(dev); + if (ret) + return ret; + + ret = mmc_gpio_set_cd_wake(host->mmc, true); return ret; } @@ -1759,6 +1769,9 @@ static int sdhci_esdhc_resume(struct device *dev) if (host->mmc->caps2 & MMC_CAP2_CQE) ret = cqhci_resume(host->mmc); + if (!ret) + ret = mmc_gpio_set_cd_wake(host->mmc, false); + return ret; } #endif From 1194be8c949b8190b2882ad8335a5d98aa50c735 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 26 May 2020 18:22:01 +0800 Subject: [PATCH 121/127] mmc: sdhci-esdhc-imx: fix the mask for tuning start point According the RM, the bit[6~0] of register ESDHC_TUNING_CTRL is TUNING_START_TAP, bit[7] of this register is to disable the command CRC check for standard tuning. So fix it here. Fixes: d87fc9663688 ("mmc: sdhci-esdhc-imx: support setting tuning start point") Signed-off-by: Haibo Chen Link: https://lore.kernel.org/r/1590488522-9292-1-git-send-email-haibo.chen@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 5a27511438c8..37d466776dc1 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -90,7 +90,7 @@ #define ESDHC_STD_TUNING_EN (1 << 24) /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 -#define ESDHC_TUNING_START_TAP_MASK 0xff +#define ESDHC_TUNING_START_TAP_MASK 0x7f #define ESDHC_TUNING_STEP_MASK 0x00070000 #define ESDHC_TUNING_STEP_SHIFT 16 From 16e40e5b1e3c6646fd90d0c3186703d209216f03 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 26 May 2020 18:22:02 +0800 Subject: [PATCH 122/127] mmc: sdhci-esdhc-imx: disable the CMD CRC check for standard tuning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In current code, we add 1ms dealy after each tuning command for standard tuning method. Adding this 1ms dealy is because USDHC default check the CMD CRC and DATA line. If detect the CMD CRC, USDHC standard tuning IC logic do not wait for the tuning data sending out by the card, trigger the buffer read ready interrupt immediately, and step to next cycle. So when next time the new tuning command send out by USDHC, card may still not send out the tuning data of the upper command,then some eMMC cards may stuck, can't response to any command, block the whole tuning procedure. If do not check the CMD CRC for tuning, then do not has this issue. USDHC will wait for the tuning data of each tuning command and check them. If the tuning data pass the check, it also means the CMD line also okay for tuning. So this patch disable the CMD CRC check for tuning, save some time for the whole tuning procedure. Signed-off-by: Haibo Chen Link: https://lore.kernel.org/r/1590488522-9292-2-git-send-email-haibo.chen@nxp.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 37d466776dc1..1d7f84b23a22 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -91,6 +91,7 @@ /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 #define ESDHC_TUNING_START_TAP_MASK 0x7f +#define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE (1 << 7) #define ESDHC_TUNING_STEP_MASK 0x00070000 #define ESDHC_TUNING_STEP_SHIFT 16 @@ -1316,6 +1317,18 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) tmp |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT; } + + /* Disable the CMD CRC check for tuning, if not, need to + * add some delay after every tuning command, because + * hardware standard tuning logic will directly go to next + * step once it detect the CMD CRC error, will not wait for + * the card side to finally send out the tuning data, trigger + * the buffer read ready interrupt immediately. If usdhc send + * the next tuning command some eMMC card will stuck, can't + * response, block the tuning procedure or the first command + * after the whole tuning procedure always can't get any response. + */ + tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { /* @@ -1660,8 +1673,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (err) goto disable_ahb_clk; - host->tuning_delay = 1; - sdhci_esdhc_imx_hwinit(host); err = sdhci_add_host(host); From dbdea70f71d672c12bc4454e7c258a8f78194d74 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 27 May 2020 13:56:59 +0300 Subject: [PATCH 123/127] mmc: sdhci-of-at91: fix CALCR register being rewritten When enabling calibration at reset, the CALCR register was completely rewritten. This may cause certain bits being deleted unintentedly. Fix by issuing a read-modify-write operation. Fixes: 727d836a375a ("mmc: sdhci-of-at91: add DT property to enable calibration on full reset") Signed-off-by: Eugen Hristev Link: https://lore.kernel.org/r/20200527105659.142560-1-eugen.hristev@microchip.com Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-at91.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 25f4e0f4f53b..1ece2c50042c 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -121,9 +121,12 @@ static void sdhci_at91_reset(struct sdhci_host *host, u8 mask) || mmc_gpio_get_cd(host->mmc) >= 0) sdhci_at91_set_force_card_detect(host); - if (priv->cal_always_on && (mask & SDHCI_RESET_ALL)) - sdhci_writel(host, SDMMC_CALCR_ALWYSON | SDMMC_CALCR_EN, + if (priv->cal_always_on && (mask & SDHCI_RESET_ALL)) { + u32 calcr = sdhci_readl(host, SDMMC_CALCR); + + sdhci_writel(host, calcr | SDMMC_CALCR_ALWYSON | SDMMC_CALCR_EN, SDMMC_CALCR); + } } static const struct sdhci_ops sdhci_at91_sama5d2_ops = { From c03ac5e6fad13c3ef9ce505191ae7419fda2fa4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 27 May 2020 13:08:57 +0200 Subject: [PATCH 124/127] mmc: core: Do not export MMC_NAME= and MODALIAS=mmc:block for SDIO cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SDIO non-combo cards are not handled by mmc_block driver and do not have accessible CID register which is used for MMC_NAME= construction. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Link: https://lore.kernel.org/r/20200527110858.17504-1-pali@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/core/bus.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 74de3f2dda38..b1cb447da764 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -93,6 +93,13 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } + /* + * SDIO (non-combo) cards are not handled by mmc_block driver and do not + * have accessible CID register which used by mmc_card_name() function. + */ + if (card->type == MMC_TYPE_SDIO) + return 0; + retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); if (retval) return retval; From 254e175448b7dc2f40e41d8941ac925f07c5862b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Wed, 27 May 2020 13:08:58 +0200 Subject: [PATCH 125/127] mmc: core: Export device/vendor ids from Common CIS for SDIO cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device/vendor ids from Common CIS (Card Information Structure) may be different as device/vendor ids from CIS on particular SDIO function. Kernel currently exports only device/vendor ids from SDIO functions and not "main" device/vendor ids from Common CIS. This patch exports "main" device/vendor ids for SDIO and SD combo cards at top level mmc device in sysfs hierarchy. Userspace can use e.g. udev rules to correctly match whole SDIO card based on Common CIS device/vendor id and not only one particular SDIO function. Having this information in userspace also helps developers to debug whole SDIO card as e.g. kernel mmc quirks use device/vendor ids from Common CIS and not from particular SDIO function. Also it allows to write userspace applications which list all connected SDIO cards based on CIS ids. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Link: https://lore.kernel.org/r/20200527110858.17504-2-pali@kernel.org Signed-off-by: Ulf Hansson --- drivers/mmc/core/bus.c | 7 +++++++ drivers/mmc/core/sd.c | 26 +++++++++++++++++++++++++- drivers/mmc/core/sdio.c | 20 +++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index b1cb447da764..70207f11a654 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -93,6 +93,13 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } + if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) { + retval = add_uevent_var(env, "SDIO_ID=%04X:%04X", + card->cis.vendor, card->cis.device); + if (retval) + return retval; + } + /* * SDIO (non-combo) cards are not handled by mmc_block driver and do not * have accessible CID register which used by mmc_card_name() function. diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 43de3190d718..5a2210c25aa7 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -707,7 +707,12 @@ static ssize_t mmc_dsr_show(struct device *dev, static DEVICE_ATTR(dsr, S_IRUGO, mmc_dsr_show, NULL); +MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor); +MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device); + static struct attribute *sd_std_attrs[] = { + &dev_attr_vendor.attr, + &dev_attr_device.attr, &dev_attr_cid.attr, &dev_attr_csd.attr, &dev_attr_scr.attr, @@ -726,7 +731,26 @@ static struct attribute *sd_std_attrs[] = { &dev_attr_dsr.attr, NULL, }; -ATTRIBUTE_GROUPS(sd_std); + +static umode_t sd_std_is_visible(struct kobject *kobj, struct attribute *attr, + int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct mmc_card *card = mmc_dev_to_card(dev); + + /* CIS vendor and device ids are available only for Combo cards */ + if ((attr == &dev_attr_vendor.attr || attr == &dev_attr_device.attr) && + card->type != MMC_TYPE_SD_COMBO) + return 0; + + return attr->mode; +} + +static const struct attribute_group sd_std_group = { + .attrs = sd_std_attrs, + .is_visible = sd_std_is_visible, +}; +__ATTRIBUTE_GROUPS(sd_std); struct device_type sd_type = { .groups = sd_std_groups, diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 435de47a6ee0..b65b26f76d71 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -27,6 +27,24 @@ #include "sdio_ops.h" #include "sdio_cis.h" +MMC_DEV_ATTR(vendor, "0x%04x\n", card->cis.vendor); +MMC_DEV_ATTR(device, "0x%04x\n", card->cis.device); +MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); +MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); + +static struct attribute *sdio_std_attrs[] = { + &dev_attr_vendor.attr, + &dev_attr_device.attr, + &dev_attr_ocr.attr, + &dev_attr_rca.attr, + NULL, +}; +ATTRIBUTE_GROUPS(sdio_std); + +static struct device_type sdio_type = { + .groups = sdio_std_groups, +}; + static int sdio_read_fbr(struct sdio_func *func) { int ret; @@ -618,7 +636,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, /* * Allocate card structure. */ - card = mmc_alloc_card(host, NULL); + card = mmc_alloc_card(host, &sdio_type); if (IS_ERR(card)) return PTR_ERR(card); From 9253d71011c349d5f5cc0cebdf68b4a80811b92d Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Thu, 28 May 2020 20:43:52 +0530 Subject: [PATCH 126/127] mmc: sdhci-msm: Clear tuning done flag while hs400 tuning Clear tuning_done flag while executing tuning to ensure vendor specific HS400 settings are applied properly when the controller is re-initialized in HS400 mode. Without this, re-initialization of the qcom SDHC in HS400 mode fails while resuming the driver from runtime-suspend or system-suspend. Fixes: ff06ce417828 ("mmc: sdhci-msm: Add HS400 platform support") Cc: stable@vger.kernel.org Signed-off-by: Veerabhadrarao Badiganti Link: https://lore.kernel.org/r/1590678838-18099-1-git-send-email-vbadigan@codeaurora.org Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-msm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 95cd9735e9a3..b277dd7fbdb5 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1173,6 +1173,12 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode) /* Clock-Data-Recovery used to dynamically adjust RX sampling point */ msm_host->use_cdr = true; + /* + * Clear tuning_done flag before tuning to ensure proper + * HS400 settings. + */ + msm_host->tuning_done = 0; + /* * For HS400 tuning in HS200 timing requires: * - select MCLK/2 in VENDOR_SPEC From ae5c0585dfc2168c589de5878df2e591dfbd4bf0 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 21 May 2020 11:13:48 +0200 Subject: [PATCH 127/127] dt-bindings: mmc: Convert sdhci-pxa to json-schema Convert the sdhci-pxa binding to DT schema format using json-schema. At the same time, fix a couple of issues with the examples discovered by the validation tool -- a semicolon instead of a comma and wrong node names. Signed-off-by: Lubomir Rintel Link: https://lore.kernel.org/r/20200521091356.2211020-2-lkundrak@v3.sk Reviewed-by: Rob Herring Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/sdhci-pxa.txt | 50 --------- .../devicetree/bindings/mmc/sdhci-pxa.yaml | 102 ++++++++++++++++++ 2 files changed, 102 insertions(+), 50 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mmc/sdhci-pxa.txt create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt deleted file mode 100644 index 3d1b449d6097..000000000000 --- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt +++ /dev/null @@ -1,50 +0,0 @@ -* Marvell sdhci-pxa v2/v3 controller - -This file documents differences between the core properties in mmc.txt -and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers. - -Required properties: -- compatible: Should be "mrvl,pxav2-mmc", "mrvl,pxav3-mmc" or - "marvell,armada-380-sdhci". -- reg: - * for "mrvl,pxav2-mmc" and "mrvl,pxav3-mmc", one register area for - the SDHCI registers. - - * for "marvell,armada-380-sdhci", three register areas. The first - one for the SDHCI registers themselves, the second one for the - AXI/Mbus bridge registers of the SDHCI unit, the third one for the - SDIO3 Configuration register -- reg names: should be "sdhci", "mbus", "conf-sdio3". only mandatory - for "marvell,armada-380-sdhci" -- clocks: Array of clocks required for SDHCI; requires at least one for - I/O clock. -- clock-names: Array of names corresponding to clocks property; shall be - "io" for I/O clock and "core" for optional core clock. - -Optional properties: -- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning. - -Example: - -sdhci@d4280800 { - compatible = "mrvl,pxav3-mmc"; - reg = <0xd4280800 0x800>; - bus-width = <8>; - interrupts = <27>; - clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>; - clock-names = "io", "core"; - non-removable; - mrvl,clk-delay-cycles = <31>; -}; - -sdhci@d8000 { - compatible = "marvell,armada-380-sdhci"; - reg-names = "sdhci", "mbus", "conf-sdio3"; - reg = <0xd8000 0x1000>, - <0xdc000 0x100>; - <0x18454 0x4>; - interrupts = <0 25 0x4>; - clocks = <&gateclk 17>; - clock-names = "io"; - mrvl,clk-delay-cycles = <0x1F>; -}; diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml b/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml new file mode 100644 index 000000000000..a58715c860b7 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mmc/sdhci-pxa.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell PXA SDHCI v2/v3 bindings + +maintainers: + - Ulf Hansson + +allOf: + - $ref: mmc-controller.yaml# + - if: + properties: + compatible: + contains: + const: marvell,armada-380-sdhci + then: + properties: + regs: + minItems: 3 + reg-names: + minItems: 3 + required: + - reg-names + else: + properties: + regs: + maxItems: 1 + reg-names: + maxItems: 1 + +properties: + compatible: + enum: + - mrvl,pxav2-mmc + - mrvl,pxav3-mmc + - marvell,armada-380-sdhci + + reg: + minItems: 1 + maxItems: 3 + + reg-names: + items: + - const: sdhci + - const: mbus + - const: conf-sdio3 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + items: + - const: io + - const: core + + mrvl,clk-delay-cycles: + description: Specify a number of cycles to delay for tuning. + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +examples: + - | + #include + mmc@d4280800 { + compatible = "mrvl,pxav3-mmc"; + reg = <0xd4280800 0x800>; + bus-width = <8>; + interrupts = <27>; + clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>; + clock-names = "io", "core"; + non-removable; + mrvl,clk-delay-cycles = <31>; + }; + - | + mmc@d8000 { + compatible = "marvell,armada-380-sdhci"; + reg-names = "sdhci", "mbus", "conf-sdio3"; + reg = <0xd8000 0x1000>, + <0xdc000 0x100>, + <0x18454 0x4>; + interrupts = <0 25 0x4>; + clocks = <&gateclk 17>; + clock-names = "io"; + mrvl,clk-delay-cycles = <0x1F>; + }; + +...