Commit 8a73c77c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC and MEMSTICK updates from Ulf Hansson:
 "MMC core:
   - Update maintainer and URL for the mmc-utils
   - Set default label for slot-gpio in case of no con-id
   - Convert MMC card DT bindings to a schema
   - Add optional host specific tuning support for eMMC HS400
   - Add error handling of add_disk()

  MMC host:
   - mtk-sd: Add host specific tuning support for eMMC HS400
   - mtk-sd: Make DMA handling more robust
   - dw_mmc: Prevent hangs for some data writes
   - dw_mmc: Move away from using the ->init_card() callback
   - mxs-mmc: Manage the regulator in the error path and in ->remove()
   - sdhci-cadence: Add support for the Microchip MPFS variant
   - sdhci-esdhc-imx: Add support for the NXP S32G2 variant
   - sdhci-of-arasan: Add support for the Intel Thunder Bay variant
   - sdhci-omap: Prepare to support more SoCs
   - sdhci-omap: Add support for omap3 and omap4 variants
   - sdhci-omap: Add support for power management
   - sdhci-omap: Add support for system wakeups
   - sdhci-msm: Add support for the msm8226 variant
   - sdhci-sprd: Verify that the DLL locks according to spec

  MEMSTICK:
   - Add error handling of add_disk()
   - A couple of small fixes and improvements"

* tag 'mmc-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (60 commits)
  docs: mmc: update maintainer name and URL
  mmc: dw_mmc: exynos: Fix spelling mistake "candiates" -> candidates
  MAINTAINERS: drop obsolete file pattern in SDHCI DRIVER section
  mmc: sdhci-esdhc-imx: add NXP S32G2 support
  dt-bindings: mmc: fsl-imx-esdhc: add NXP S32G2 support
  mmc: dw_mmc: Drop use of ->init_card() callback
  mmc: sdhci-omap: Fix build if CONFIG_PM_SLEEP is not set
  mmc: sdhci-omap: Remove forward declaration of sdhci_omap_context_save()
  memstick: r592: Fix a UAF bug when removing the driver
  mmc: mxs-mmc: disable regulator on error and in the remove function
  mmc: sdhci-omap: Configure optional wakeirq
  mmc: sdhci-omap: Allow SDIO card power off and enable aggressive PM
  mmc: sdhci-omap: Implement PM runtime functions
  mmc: sdhci-omap: Add omap_offset to support omap3 and earlier
  mmc: sdhci-omap: Handle voltages to add support omap4
  dt-bindings: sdhci-omap: Update binding for legacy SoCs
  mmc: sdhci-pci: Remove dead code (rst_n_gpio et al)
  mmc: sdhci-pci: Remove dead code (cd_gpio, cd_irq et al)
  mmc: sdhci-pci: Remove dead code (struct sdhci_pci_data et al)
  mmc: sdhci: Remove unused prototype declaration in the header
  ...
parents 316b7eaa 348ecd61
...@@ -88,6 +88,12 @@ properties: ...@@ -88,6 +88,12 @@ properties:
description: description:
For this device it is strongly suggested to include For this device it is strongly suggested to include
arasan,soc-ctl-syscon. arasan,soc-ctl-syscon.
- items:
- const: intel,thunderbay-sdhci-5.1 # Intel Thunder Bay eMMC PHY
- const: arasan,sdhci-5.1
description:
For this device it is strongly suggested to include
clock-output-names and '#clock-cells'.
reg: reg:
maxItems: 1 maxItems: 1
...@@ -153,7 +159,6 @@ properties: ...@@ -153,7 +159,6 @@ properties:
The MIO bank number in which the command and data lines are configured. The MIO bank number in which the command and data lines are configured.
dependencies: dependencies:
clock-output-names: [ '#clock-cells' ]
'#clock-cells': [ clock-output-names ] '#clock-cells': [ clock-output-names ]
required: required:
...@@ -301,3 +306,22 @@ examples: ...@@ -301,3 +306,22 @@ examples:
<&scmi_clk KEEM_BAY_PSS_SD0>; <&scmi_clk KEEM_BAY_PSS_SD0>;
arasan,soc-ctl-syscon = <&sd0_phy_syscon>; arasan,soc-ctl-syscon = <&sd0_phy_syscon>;
}; };
- |
#define EMMC_XIN_CLK
#define EMMC_AXI_CLK
#define TBH_PSS_EMMC_RST_N
mmc@80420000 {
compatible = "intel,thunderbay-sdhci-5.1", "arasan,sdhci-5.1";
interrupts = <GIC_SPI 714 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x80420000 0x400>;
clocks = <&scmi_clk EMMC_XIN_CLK>,
<&scmi_clk EMMC_AXI_CLK>;
clock-names = "clk_xin", "clk_ahb";
phys = <&emmc_phy>;
phy-names = "phy_arasan";
assigned-clocks = <&scmi_clk EMMC_XIN_CLK>;
clock-output-names = "emmc_cardclock";
resets = <&rst_pss1 TBH_PSS_EMMC_RST_N>;
#clock-cells = <0x0>;
};
...@@ -17,6 +17,7 @@ properties: ...@@ -17,6 +17,7 @@ properties:
compatible: compatible:
items: items:
- enum: - enum:
- microchip,mpfs-sd4hc
- socionext,uniphier-sd4hc - socionext,uniphier-sd4hc
- const: cdns,sd4hc - const: cdns,sd4hc
......
...@@ -34,6 +34,7 @@ properties: ...@@ -34,6 +34,7 @@ properties:
- fsl,imx6ull-usdhc - fsl,imx6ull-usdhc
- fsl,imx7d-usdhc - fsl,imx7d-usdhc
- fsl,imx7ulp-usdhc - fsl,imx7ulp-usdhc
- nxp,s32g2-usdhc
- items: - items:
- enum: - enum:
- fsl,imx8mm-usdhc - fsl,imx8mm-usdhc
......
mmc-card / eMMC bindings
------------------------
This documents describes the devicetree bindings for a mmc-host controller
child node describing a mmc-card / an eMMC, see "Use of Function subnodes"
in mmc.txt
Required properties:
-compatible : Must be "mmc-card"
-reg : Must be <0>
Optional properties:
-broken-hpi : Use this to indicate that the mmc-card has a broken hpi
implementation, and that hpi should not be used
Example:
&mmc2 {
pinctrl-names = "default";
pinctrl-0 = <&mmc2_pins_a>;
vmmc-supply = <&reg_vcc3v3>;
bus-width = <8>;
non-removable;
mmccard: mmccard@0 {
reg = <0>;
compatible = "mmc-card";
broken-hpi;
};
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/mmc-card.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MMC Card / eMMC Generic Device Tree Bindings
maintainers:
- Ulf Hansson <ulf.hansson@linaro.org>
description: |
This documents describes the devicetree bindings for a mmc-host controller
child node describing a mmc-card / an eMMC.
properties:
compatible:
const: mmc-card
reg:
const: 0
broken-hpi:
$ref: /schemas/types.yaml#/definitions/flag
description:
Use this to indicate that the mmc-card has a broken hpi
implementation, and that hpi should not be used.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
mmc {
#address-cells = <1>;
#size-cells = <0>;
card@0 {
compatible = "mmc-card";
reg = <0>;
broken-hpi;
};
};
...
...@@ -333,12 +333,6 @@ patternProperties: ...@@ -333,12 +333,6 @@ patternProperties:
subnode describes. A value of 0 denotes the memory SD subnode describes. A value of 0 denotes the memory SD
function, values from 1 to 7 denote the SDIO functions. function, values from 1 to 7 denote the SDIO functions.
broken-hpi:
$ref: /schemas/types.yaml#/definitions/flag
description:
Use this to indicate that the mmc-card has a broken hpi
implementation, and that hpi should not be used.
required: required:
- reg - reg
......
...@@ -119,6 +119,18 @@ properties: ...@@ -119,6 +119,18 @@ properties:
If present, HS400 command responses are sampled on rising edges. If present, HS400 command responses are sampled on rising edges.
If not present, HS400 command responses are sampled on falling edges. If not present, HS400 command responses are sampled on falling edges.
mediatek,hs400-ds-dly3:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Gear of the third delay line for DS for input data latch in data
pad macro, there are 32 stages from 0 to 31.
For different corner IC, the time is different about one step, it is
about 100ps.
The value is confirmed by doing scan and calibration to find a best
value with corner IC and it is valid only for HS400 mode.
minimum: 0
maximum: 31
mediatek,latch-ck: mediatek,latch-ck:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
description: description:
......
...@@ -13,6 +13,7 @@ Required properties: ...@@ -13,6 +13,7 @@ Required properties:
string is added to support this change - "qcom,sdhci-msm-v5". string is added to support this change - "qcom,sdhci-msm-v5".
full compatible strings with SoC and version: full compatible strings with SoC and version:
"qcom,apq8084-sdhci", "qcom,sdhci-msm-v4" "qcom,apq8084-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8226-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8974-sdhci", "qcom,sdhci-msm-v4" "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8916-sdhci", "qcom,sdhci-msm-v4" "qcom,msm8916-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8992-sdhci", "qcom,sdhci-msm-v4" "qcom,msm8992-sdhci", "qcom,sdhci-msm-v4"
......
...@@ -5,7 +5,11 @@ Refer to mmc.txt for standard MMC bindings. ...@@ -5,7 +5,11 @@ Refer to mmc.txt for standard MMC bindings.
For UHS devices which require tuning, the device tree should have a "cpu_thermal" node which maps to the appropriate thermal zone. This is used to get the temperature of the zone during tuning. For UHS devices which require tuning, the device tree should have a "cpu_thermal" node which maps to the appropriate thermal zone. This is used to get the temperature of the zone during tuning.
Required properties: Required properties:
- compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers - compatible: Should be "ti,omap2430-sdhci" for omap2430 controllers
Should be "ti,omap3-sdhci" for omap3 controllers
Should be "ti,omap4-sdhci" for omap4 and ti81 controllers
Should be "ti,omap5-sdhci" for omap5 controllers
Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
Should be "ti,k2g-sdhci" for K2G Should be "ti,k2g-sdhci" for K2G
Should be "ti,am335-sdhci" for am335x controllers Should be "ti,am335-sdhci" for am335x controllers
Should be "ti,am437-sdhci" for am437x controllers Should be "ti,am437-sdhci" for am437x controllers
...@@ -24,6 +28,9 @@ Optional properties: ...@@ -24,6 +28,9 @@ Optional properties:
DMA specifiers listed in dmas. The string naming is to be "tx" DMA specifiers listed in dmas. The string naming is to be "tx"
and "rx" for TX and RX DMA requests, respectively. and "rx" for TX and RX DMA requests, respectively.
Deprecated properties:
- ti,non-removable: Compatible with the generic non-removable property
Example: Example:
mmc1: mmc@4809c000 { mmc1: mmc@4809c000 {
compatible = "ti,dra7-sdhci"; compatible = "ti,dra7-sdhci";
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
MMC tools introduction MMC tools introduction
====================== ======================
There is one MMC test tools called mmc-utils, which is maintained by Chris Ball, There is one MMC test tools called mmc-utils, which is maintained by Ulf Hansson,
you can find it at the below public git repository: you can find it at the below public git repository:
https://git.kernel.org/cgit/linux/kernel/git/cjb/mmc-utils.git/ https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git
Functions Functions
========= =========
......
...@@ -16839,7 +16839,6 @@ M: Adrian Hunter <adrian.hunter@intel.com> ...@@ -16839,7 +16839,6 @@ M: Adrian Hunter <adrian.hunter@intel.com>
L: linux-mmc@vger.kernel.org L: linux-mmc@vger.kernel.org
S: Maintained S: Maintained
F: drivers/mmc/host/sdhci* F: drivers/mmc/host/sdhci*
F: include/linux/mmc/sdhci*
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
M: Eugen Hristev <eugen.hristev@microchip.com> M: Eugen Hristev <eugen.hristev@microchip.com>
......
...@@ -1736,7 +1736,7 @@ static int msb_init_card(struct memstick_dev *card) ...@@ -1736,7 +1736,7 @@ static int msb_init_card(struct memstick_dev *card)
msb->pages_in_block = boot_block->attr.block_size * 2; msb->pages_in_block = boot_block->attr.block_size * 2;
msb->block_size = msb->page_size * msb->pages_in_block; msb->block_size = msb->page_size * msb->pages_in_block;
if (msb->page_size > PAGE_SIZE) { if ((size_t)msb->page_size > PAGE_SIZE) {
/* this isn't supported by linux at all, anyway*/ /* this isn't supported by linux at all, anyway*/
dbg("device page %d size isn't supported", msb->page_size); dbg("device page %d size isn't supported", msb->page_size);
return -EINVAL; return -EINVAL;
...@@ -2156,10 +2156,14 @@ static int msb_init_disk(struct memstick_dev *card) ...@@ -2156,10 +2156,14 @@ static int msb_init_disk(struct memstick_dev *card)
set_disk_ro(msb->disk, 1); set_disk_ro(msb->disk, 1);
msb_start(card); msb_start(card);
device_add_disk(&card->dev, msb->disk, NULL); rc = device_add_disk(&card->dev, msb->disk, NULL);
if (rc)
goto out_cleanup_disk;
dbg("Disk added"); dbg("Disk added");
return 0; return 0;
out_cleanup_disk:
blk_cleanup_disk(msb->disk);
out_free_tag_set: out_free_tag_set:
blk_mq_free_tag_set(&msb->tag_set); blk_mq_free_tag_set(&msb->tag_set);
out_release_id: out_release_id:
......
...@@ -1239,10 +1239,14 @@ static int mspro_block_init_disk(struct memstick_dev *card) ...@@ -1239,10 +1239,14 @@ static int mspro_block_init_disk(struct memstick_dev *card)
set_capacity(msb->disk, capacity); set_capacity(msb->disk, capacity);
dev_dbg(&card->dev, "capacity set %ld\n", capacity); dev_dbg(&card->dev, "capacity set %ld\n", capacity);
device_add_disk(&card->dev, msb->disk, NULL); rc = device_add_disk(&card->dev, msb->disk, NULL);
if (rc)
goto out_cleanup_disk;
msb->active = 1; msb->active = 1;
return 0; return 0;
out_cleanup_disk:
blk_cleanup_disk(msb->disk);
out_free_tag_set: out_free_tag_set:
blk_mq_free_tag_set(&msb->tag_set); blk_mq_free_tag_set(&msb->tag_set);
out_release_id: out_release_id:
......
...@@ -882,7 +882,7 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt) ...@@ -882,7 +882,7 @@ static struct memstick_host *jmb38x_ms_alloc_host(struct jmb38x_ms *jm, int cnt)
iounmap(host->addr); iounmap(host->addr);
err_out_free: err_out_free:
kfree(msh); memstick_free_host(msh);
return NULL; return NULL;
} }
...@@ -927,8 +927,7 @@ static int jmb38x_ms_probe(struct pci_dev *pdev, ...@@ -927,8 +927,7 @@ static int jmb38x_ms_probe(struct pci_dev *pdev,
goto err_out_int; goto err_out_int;
} }
jm = kzalloc(sizeof(struct jmb38x_ms) jm = kzalloc(struct_size(jm, hosts, cnt), GFP_KERNEL);
+ cnt * sizeof(struct memstick_host *), GFP_KERNEL);
if (!jm) { if (!jm) {
rc = -ENOMEM; rc = -ENOMEM;
goto err_out_int; goto err_out_int;
......
...@@ -838,15 +838,15 @@ static void r592_remove(struct pci_dev *pdev) ...@@ -838,15 +838,15 @@ static void r592_remove(struct pci_dev *pdev)
} }
memstick_remove_host(dev->host); memstick_remove_host(dev->host);
if (dev->dummy_dma_page)
dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->dummy_dma_page,
dev->dummy_dma_page_physical_address);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
iounmap(dev->mmio); iounmap(dev->mmio);
pci_release_regions(pdev); pci_release_regions(pdev);
pci_disable_device(pdev); pci_disable_device(pdev);
memstick_free_host(dev->host); memstick_free_host(dev->host);
if (dev->dummy_dma_page)
dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->dummy_dma_page,
dev->dummy_dma_page_physical_address);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
......
...@@ -2442,9 +2442,14 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, ...@@ -2442,9 +2442,14 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
/* used in ->open, must be set before add_disk: */ /* used in ->open, must be set before add_disk: */
if (area_type == MMC_BLK_DATA_AREA_MAIN) if (area_type == MMC_BLK_DATA_AREA_MAIN)
dev_set_drvdata(&card->dev, md); dev_set_drvdata(&card->dev, md);
device_add_disk(md->parent, md->disk, mmc_disk_attr_groups); ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups);
if (ret)
goto err_cleanup_queue;
return md; return md;
err_cleanup_queue:
blk_cleanup_queue(md->disk->queue);
blk_mq_free_tag_set(&md->queue.tag_set);
err_kfree: err_kfree:
kfree(md); kfree(md);
out: out:
......
...@@ -1224,6 +1224,14 @@ static int mmc_select_hs400(struct mmc_card *card) ...@@ -1224,6 +1224,14 @@ static int mmc_select_hs400(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS400); mmc_set_timing(host, MMC_TIMING_MMC_HS400);
mmc_set_bus_speed(card); mmc_set_bus_speed(card);
if (host->ops->execute_hs400_tuning) {
mmc_retune_disable(host);
err = host->ops->execute_hs400_tuning(host, card);
mmc_retune_enable(host);
if (err)
goto out_err;
}
if (host->ops->hs400_complete) if (host->ops->hs400_complete)
host->ops->hs400_complete(host); host->ops->hs400_complete(host);
......
...@@ -38,7 +38,6 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); ...@@ -38,7 +38,6 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc); int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
int mmc_bus_test(struct mmc_card *card, u8 bus_width); int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_can_ext_csd(struct mmc_card *card); int mmc_can_ext_csd(struct mmc_card *card);
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal); int mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd, bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
unsigned int timeout_ms); unsigned int timeout_ms);
......
...@@ -39,24 +39,24 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) ...@@ -39,24 +39,24 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
int mmc_gpio_alloc(struct mmc_host *host) int mmc_gpio_alloc(struct mmc_host *host)
{ {
struct mmc_gpio *ctx = devm_kzalloc(host->parent, const char *devname = dev_name(host->parent);
sizeof(*ctx), GFP_KERNEL); struct mmc_gpio *ctx;
if (ctx) { ctx = devm_kzalloc(host->parent, sizeof(*ctx), GFP_KERNEL);
ctx->cd_debounce_delay_ms = 200; if (!ctx)
ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL, return -ENOMEM;
"%s cd", dev_name(host->parent));
if (!ctx->cd_label) ctx->cd_debounce_delay_ms = 200;
return -ENOMEM; ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s cd", devname);
ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL, if (!ctx->cd_label)
"%s ro", dev_name(host->parent)); return -ENOMEM;
if (!ctx->ro_label) ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL, "%s ro", devname);
return -ENOMEM; if (!ctx->ro_label)
host->slot.handler_priv = ctx; return -ENOMEM;
host->slot.cd_irq = -EINVAL; host->slot.handler_priv = ctx;
} host->slot.cd_irq = -EINVAL;
return ctx ? 0 : -ENOMEM; return 0;
} }
int mmc_gpio_get_ro(struct mmc_host *host) int mmc_gpio_get_ro(struct mmc_host *host)
...@@ -178,6 +178,10 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, ...@@ -178,6 +178,10 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
if (IS_ERR(desc)) if (IS_ERR(desc))
return PTR_ERR(desc); return PTR_ERR(desc);
/* Update default label if no con_id provided */
if (!con_id)
gpiod_set_consumer_name(desc, ctx->cd_label);
if (debounce) { if (debounce) {
ret = gpiod_set_debounce(desc, debounce); ret = gpiod_set_debounce(desc, debounce);
if (ret < 0) if (ret < 0)
...@@ -226,6 +230,10 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, ...@@ -226,6 +230,10 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
if (IS_ERR(desc)) if (IS_ERR(desc))
return PTR_ERR(desc); return PTR_ERR(desc);
/* Update default label if no con_id provided */
if (!con_id)
gpiod_set_consumer_name(desc, ctx->ro_label);
if (debounce) { if (debounce) {
ret = gpiod_set_debounce(desc, debounce); ret = gpiod_set_debounce(desc, debounce);
if (ret < 0) if (ret < 0)
......
...@@ -315,15 +315,17 @@ config MMC_SDHCI_TEGRA ...@@ -315,15 +315,17 @@ config MMC_SDHCI_TEGRA
If unsure, say N. If unsure, say N.
config MMC_SDHCI_S3C config MMC_SDHCI_S3C
tristate "SDHCI support on Samsung S3C SoC" tristate "SDHCI support on Samsung S3C/S5P/Exynos SoC"
depends on MMC_SDHCI depends on MMC_SDHCI
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
often referrered to as the HSMMC block in some of the Samsung S3C often referrered to as the HSMMC block in some of the Samsung S3C
range of SoC. (S3C2416, S3C2443, S3C6410), S5Pv210 and Exynos (Exynso4210,
Exynos4412) SoCs.
If you have a controller with this interface, say Y or M here. If you have a controller with this interface (thereforeyou build for
such Samsung SoC), say Y or M here.
If unsure, say N. If unsure, say N.
......
...@@ -14,7 +14,6 @@ obj-$(CONFIG_MMC_SDHCI) += sdhci.o ...@@ -14,7 +14,6 @@ obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
sdhci-pci-dwc-mshc.o sdhci-pci-gli.o sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o
......
...@@ -902,8 +902,8 @@ static bool cqhci_timeout(struct mmc_host *mmc, struct mmc_request *mrq, ...@@ -902,8 +902,8 @@ static bool cqhci_timeout(struct mmc_host *mmc, struct mmc_request *mrq,
spin_unlock_irqrestore(&cq_host->lock, flags); spin_unlock_irqrestore(&cq_host->lock, flags);
if (timed_out) { if (timed_out) {
pr_err("%s: cqhci: timeout for tag %d\n", pr_err("%s: cqhci: timeout for tag %d, qcnt %d\n",
mmc_hostname(mmc), tag); mmc_hostname(mmc), tag, cq_host->qcnt);
cqhci_dumpregs(cq_host); cqhci_dumpregs(cq_host);
} }
......
...@@ -442,14 +442,14 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) ...@@ -442,14 +442,14 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
return sample; return sample;
} }
static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates) static s8 dw_mci_exynos_get_best_clksmpl(u8 candidates)
{ {
const u8 iter = 8; const u8 iter = 8;
u8 __c; u8 __c;
s8 i, loc = -1; s8 i, loc = -1;
for (i = 0; i < iter; i++) { for (i = 0; i < iter; i++) {
__c = ror8(candiates, i); __c = ror8(candidates, i);
if ((__c & 0xc7) == 0xc7) { if ((__c & 0xc7) == 0xc7) {
loc = i; loc = i;
goto out; goto out;
...@@ -457,7 +457,7 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates) ...@@ -457,7 +457,7 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates)
} }
for (i = 0; i < iter; i++) { for (i = 0; i < iter; i++) {
__c = ror8(candiates, i); __c = ror8(candidates, i);
if ((__c & 0x83) == 0x83) { if ((__c & 0x83) == 0x83) {
loc = i; loc = i;
goto out; goto out;
...@@ -466,11 +466,11 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates) ...@@ -466,11 +466,11 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates)
/* /*
* If there is no cadiates value, then it needs to return -EIO. * If there is no cadiates value, then it needs to return -EIO.
* If there are candiates values and don't find bset clk sample value, * If there are candidates values and don't find bset clk sample value,
* then use a first candiates clock sample value. * then use a first candidates clock sample value.
*/ */
for (i = 0; i < iter; i++) { for (i = 0; i < iter; i++) {
__c = ror8(candiates, i); __c = ror8(candidates, i);
if ((__c & 0x1) == 0x1) { if ((__c & 0x1) == 0x1) {
loc = i; loc = i;
goto out; goto out;
...@@ -485,7 +485,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode) ...@@ -485,7 +485,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
struct mmc_host *mmc = slot->mmc; struct mmc_host *mmc = slot->mmc;
u8 start_smpl, smpl, candiates = 0; u8 start_smpl, smpl, candidates = 0;
s8 found; s8 found;
int ret = 0; int ret = 0;
...@@ -496,18 +496,18 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode) ...@@ -496,18 +496,18 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
smpl = dw_mci_exynos_move_next_clksmpl(host); smpl = dw_mci_exynos_move_next_clksmpl(host);
if (!mmc_send_tuning(mmc, opcode, NULL)) if (!mmc_send_tuning(mmc, opcode, NULL))
candiates |= (1 << smpl); candidates |= (1 << smpl);
} while (start_smpl != smpl); } while (start_smpl != smpl);
found = dw_mci_exynos_get_best_clksmpl(candiates); found = dw_mci_exynos_get_best_clksmpl(candidates);
if (found >= 0) { if (found >= 0) {
dw_mci_exynos_set_clksmpl(host, found); dw_mci_exynos_set_clksmpl(host, found);
priv->tuned_sample = found; priv->tuned_sample = found;
} else { } else {
ret = -EIO; ret = -EIO;
dev_warn(&mmc->class_dev, dev_warn(&mmc->class_dev,
"There is no candiates value about clksmpl!\n"); "There is no candidates value about clksmpl!\n");
} }
return ret; return ret;
......
...@@ -1611,37 +1611,32 @@ static void dw_mci_hw_reset(struct mmc_host *mmc) ...@@ -1611,37 +1611,32 @@ static void dw_mci_hw_reset(struct mmc_host *mmc)
usleep_range(200, 300); usleep_range(200, 300);
} }
static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) static void dw_mci_prepare_sdio_irq(struct dw_mci_slot *slot, bool prepare)
{ {
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
u32 clk_en_a_old;
u32 clk_en_a;
/* /*
* Low power mode will stop the card clock when idle. According to the * Low power mode will stop the card clock when idle. According to the
* description of the CLKENA register we should disable low power mode * description of the CLKENA register we should disable low power mode
* for SDIO cards if we need SDIO interrupts to work. * for SDIO cards if we need SDIO interrupts to work.
*/ */
if (mmc->caps & MMC_CAP_SDIO_IRQ) {
const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
u32 clk_en_a_old;
u32 clk_en_a;
clk_en_a_old = mci_readl(host, CLKENA); clk_en_a_old = mci_readl(host, CLKENA);
if (prepare) {
if (card->type == MMC_TYPE_SDIO || set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
card->type == MMC_TYPE_SD_COMBO) { clk_en_a = clk_en_a_old & ~clken_low_pwr;
set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); } else {
clk_en_a = clk_en_a_old & ~clken_low_pwr; clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
} else { clk_en_a = clk_en_a_old | clken_low_pwr;
clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags); }
clk_en_a = clk_en_a_old | clken_low_pwr;
}
if (clk_en_a != clk_en_a_old) { if (clk_en_a != clk_en_a_old) {
mci_writel(host, CLKENA, clk_en_a); mci_writel(host, CLKENA, clk_en_a);
mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT,
SDMMC_CMD_PRV_DAT_WAIT, 0); 0);
}
} }
} }
...@@ -1669,6 +1664,7 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) ...@@ -1669,6 +1664,7 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
dw_mci_prepare_sdio_irq(slot, enb);
__dw_mci_enable_sdio_irq(slot, enb); __dw_mci_enable_sdio_irq(slot, enb);
/* Avoid runtime suspending the device when SDIO IRQ is enabled */ /* Avoid runtime suspending the device when SDIO IRQ is enabled */
...@@ -1790,7 +1786,6 @@ static const struct mmc_host_ops dw_mci_ops = { ...@@ -1790,7 +1786,6 @@ static const struct mmc_host_ops dw_mci_ops = {
.execute_tuning = dw_mci_execute_tuning, .execute_tuning = dw_mci_execute_tuning,
.card_busy = dw_mci_card_busy, .card_busy = dw_mci_card_busy,
.start_signal_voltage_switch = dw_mci_switch_voltage, .start_signal_voltage_switch = dw_mci_switch_voltage,
.init_card = dw_mci_init_card,
.prepare_hs400_tuning = dw_mci_prepare_hs400_tuning, .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
}; };
...@@ -2086,7 +2081,8 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t) ...@@ -2086,7 +2081,8 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t)
* delayed. Allowing the transfer to take place * delayed. Allowing the transfer to take place
* avoids races and keeps things simple. * avoids races and keeps things simple.
*/ */
if (err != -ETIMEDOUT) { if (err != -ETIMEDOUT &&
host->dir_status == DW_MCI_RECV_STATUS) {
state = STATE_SENDING_DATA; state = STATE_SENDING_DATA;
continue; continue;
} }
......
...@@ -1394,6 +1394,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, ...@@ -1394,6 +1394,10 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
} else if (host->variant->busy_timeout && busy_resp && } else if (host->variant->busy_timeout && busy_resp &&
status & MCI_DATATIMEOUT) { status & MCI_DATATIMEOUT) {
cmd->error = -ETIMEDOUT; cmd->error = -ETIMEDOUT;
/*
* This will wake up mmci_irq_thread() which will issue
* a hardware reset of the MMCI block.
*/
host->irq_action = IRQ_WAKE_THREAD; host->irq_action = IRQ_WAKE_THREAD;
} else { } else {
cmd->resp[0] = readl(base + MMCIRESPONSE0); cmd->resp[0] = readl(base + MMCIRESPONSE0);
......
...@@ -566,37 +566,37 @@ static int moxart_probe(struct platform_device *pdev) ...@@ -566,37 +566,37 @@ static int moxart_probe(struct platform_device *pdev)
if (!mmc) { if (!mmc) {
dev_err(dev, "mmc_alloc_host failed\n"); dev_err(dev, "mmc_alloc_host failed\n");
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out_mmc;
} }
ret = of_address_to_resource(node, 0, &res_mmc); ret = of_address_to_resource(node, 0, &res_mmc);
if (ret) { if (ret) {
dev_err(dev, "of_address_to_resource failed\n"); dev_err(dev, "of_address_to_resource failed\n");
goto out; goto out_mmc;
} }
irq = irq_of_parse_and_map(node, 0); irq = irq_of_parse_and_map(node, 0);
if (irq <= 0) { if (irq <= 0) {
dev_err(dev, "irq_of_parse_and_map failed\n"); dev_err(dev, "irq_of_parse_and_map failed\n");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out_mmc;
} }
clk = devm_clk_get(dev, NULL); clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
ret = PTR_ERR(clk); ret = PTR_ERR(clk);
goto out; goto out_mmc;
} }
reg_mmc = devm_ioremap_resource(dev, &res_mmc); reg_mmc = devm_ioremap_resource(dev, &res_mmc);
if (IS_ERR(reg_mmc)) { if (IS_ERR(reg_mmc)) {
ret = PTR_ERR(reg_mmc); ret = PTR_ERR(reg_mmc);
goto out; goto out_mmc;
} }
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret) if (ret)
goto out; goto out_mmc;
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
...@@ -621,6 +621,14 @@ static int moxart_probe(struct platform_device *pdev) ...@@ -621,6 +621,14 @@ static int moxart_probe(struct platform_device *pdev)
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
goto out; goto out;
} }
if (!IS_ERR(host->dma_chan_tx)) {
dma_release_channel(host->dma_chan_tx);
host->dma_chan_tx = NULL;
}
if (!IS_ERR(host->dma_chan_rx)) {
dma_release_channel(host->dma_chan_rx);
host->dma_chan_rx = NULL;
}
dev_dbg(dev, "PIO mode transfer enabled\n"); dev_dbg(dev, "PIO mode transfer enabled\n");
host->have_dma = false; host->have_dma = false;
} else { } else {
...@@ -675,6 +683,11 @@ static int moxart_probe(struct platform_device *pdev) ...@@ -675,6 +683,11 @@ static int moxart_probe(struct platform_device *pdev)
return 0; return 0;
out: out:
if (!IS_ERR_OR_NULL(host->dma_chan_tx))
dma_release_channel(host->dma_chan_tx);
if (!IS_ERR_OR_NULL(host->dma_chan_rx))
dma_release_channel(host->dma_chan_rx);
out_mmc:
if (mmc) if (mmc)
mmc_free_host(mmc); mmc_free_host(mmc);
return ret; return ret;
...@@ -687,9 +700,9 @@ static int moxart_remove(struct platform_device *pdev) ...@@ -687,9 +700,9 @@ static int moxart_remove(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, NULL); dev_set_drvdata(&pdev->dev, NULL);
if (!IS_ERR(host->dma_chan_tx)) if (!IS_ERR_OR_NULL(host->dma_chan_tx))
dma_release_channel(host->dma_chan_tx); dma_release_channel(host->dma_chan_tx);
if (!IS_ERR(host->dma_chan_rx)) if (!IS_ERR_OR_NULL(host->dma_chan_rx))
dma_release_channel(host->dma_chan_rx); dma_release_channel(host->dma_chan_rx);
mmc_remove_host(mmc); mmc_remove_host(mmc);
mmc_free_host(mmc); mmc_free_host(mmc);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -258,6 +259,7 @@ ...@@ -258,6 +259,7 @@
#define MSDC_PAD_TUNE_RD_SEL (0x1 << 13) /* RW */ #define MSDC_PAD_TUNE_RD_SEL (0x1 << 13) /* RW */
#define MSDC_PAD_TUNE_CMD_SEL (0x1 << 21) /* RW */ #define MSDC_PAD_TUNE_CMD_SEL (0x1 << 21) /* RW */
#define PAD_DS_TUNE_DLY_SEL (0x1 << 0) /* RW */
#define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */ #define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */
#define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */ #define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */
#define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */ #define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */
...@@ -301,6 +303,11 @@ ...@@ -301,6 +303,11 @@
#define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */ #define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */
#define PAD_CMD_TX_DLY (0x1f << 12) /* RW */ #define PAD_CMD_TX_DLY (0x1f << 12) /* RW */
/* EMMC50_PAD_DS_TUNE mask */
#define PAD_DS_DLY_SEL (0x1 << 16) /* RW */
#define PAD_DS_DLY1 (0x1f << 10) /* RW */
#define PAD_DS_DLY3 (0x1f << 0) /* RW */
#define REQ_CMD_EIO (0x1 << 0) #define REQ_CMD_EIO (0x1 << 0)
#define REQ_CMD_TMO (0x1 << 1) #define REQ_CMD_TMO (0x1 << 1)
#define REQ_DAT_ERR (0x1 << 2) #define REQ_DAT_ERR (0x1 << 2)
...@@ -448,11 +455,13 @@ struct msdc_host { ...@@ -448,11 +455,13 @@ struct msdc_host {
bool vqmmc_enabled; bool vqmmc_enabled;
u32 latch_ck; u32 latch_ck;
u32 hs400_ds_delay; u32 hs400_ds_delay;
u32 hs400_ds_dly3;
u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */ u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */
u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */ u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */
bool hs400_cmd_resp_sel_rising; bool hs400_cmd_resp_sel_rising;
/* cmd response sample selection for HS400 */ /* cmd response sample selection for HS400 */
bool hs400_mode; /* current eMMC will run at hs400 mode */ bool hs400_mode; /* current eMMC will run at hs400 mode */
bool hs400_tuning; /* hs400 mode online tuning */
bool internal_cd; /* Use internal card-detect logic */ bool internal_cd; /* Use internal card-detect logic */
bool cqhci; /* support eMMC hw cmdq */ bool cqhci; /* support eMMC hw cmdq */
struct msdc_save_para save_para; /* used when gate HCLK */ struct msdc_save_para save_para; /* used when gate HCLK */
...@@ -961,7 +970,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) ...@@ -961,7 +970,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
} }
static inline u32 msdc_cmd_find_resp(struct msdc_host *host, static inline u32 msdc_cmd_find_resp(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd) struct mmc_command *cmd)
{ {
u32 resp; u32 resp;
...@@ -997,7 +1006,7 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, ...@@ -997,7 +1006,7 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
* stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode
*/ */
u32 opcode = cmd->opcode; u32 opcode = cmd->opcode;
u32 resp = msdc_cmd_find_resp(host, mrq, cmd); u32 resp = msdc_cmd_find_resp(host, cmd);
u32 rawcmd = (opcode & 0x3f) | ((resp & 0x7) << 7); u32 rawcmd = (opcode & 0x3f) | ((resp & 0x7) << 7);
host->cmd_rsp = resp; host->cmd_rsp = resp;
...@@ -1043,8 +1052,8 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host, ...@@ -1043,8 +1052,8 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
return rawcmd; return rawcmd;
} }
static void msdc_start_data(struct msdc_host *host, struct mmc_request *mrq, static void msdc_start_data(struct msdc_host *host, struct mmc_command *cmd,
struct mmc_command *cmd, struct mmc_data *data) struct mmc_data *data)
{ {
bool read; bool read;
...@@ -1112,8 +1121,7 @@ static void msdc_recheck_sdio_irq(struct msdc_host *host) ...@@ -1112,8 +1121,7 @@ static void msdc_recheck_sdio_irq(struct msdc_host *host)
} }
} }
static void msdc_track_cmd_data(struct msdc_host *host, static void msdc_track_cmd_data(struct msdc_host *host, struct mmc_command *cmd)
struct mmc_command *cmd, struct mmc_data *data)
{ {
if (host->error) if (host->error)
dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n", dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n",
...@@ -1134,7 +1142,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) ...@@ -1134,7 +1142,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
host->mrq = NULL; host->mrq = NULL;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
msdc_track_cmd_data(host, mrq->cmd, mrq->data); msdc_track_cmd_data(host, mrq->cmd);
if (mrq->data) if (mrq->data)
msdc_unprepare_data(host, mrq->data); msdc_unprepare_data(host, mrq->data);
if (host->error) if (host->error)
...@@ -1190,7 +1198,8 @@ static bool msdc_cmd_done(struct msdc_host *host, int events, ...@@ -1190,7 +1198,8 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
if (!sbc_error && !(events & MSDC_INT_CMDRDY)) { if (!sbc_error && !(events & MSDC_INT_CMDRDY)) {
if (events & MSDC_INT_CMDTMO || if (events & MSDC_INT_CMDTMO ||
(cmd->opcode != MMC_SEND_TUNING_BLOCK && (cmd->opcode != MMC_SEND_TUNING_BLOCK &&
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)) cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
!host->hs400_tuning))
/* /*
* should not clear fifo/interrupt as the tune data * should not clear fifo/interrupt as the tune data
* may have alreay come when cmd19/cmd21 gets response * may have alreay come when cmd19/cmd21 gets response
...@@ -1287,7 +1296,8 @@ static void msdc_cmd_next(struct msdc_host *host, ...@@ -1287,7 +1296,8 @@ static void msdc_cmd_next(struct msdc_host *host,
if ((cmd->error && if ((cmd->error &&
!(cmd->error == -EILSEQ && !(cmd->error == -EILSEQ &&
(cmd->opcode == MMC_SEND_TUNING_BLOCK || (cmd->opcode == MMC_SEND_TUNING_BLOCK ||
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200))) || cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
host->hs400_tuning))) ||
(mrq->sbc && mrq->sbc->error)) (mrq->sbc && mrq->sbc->error))
msdc_request_done(host, mrq); msdc_request_done(host, mrq);
else if (cmd == mrq->sbc) else if (cmd == mrq->sbc)
...@@ -1295,7 +1305,7 @@ static void msdc_cmd_next(struct msdc_host *host, ...@@ -1295,7 +1305,7 @@ static void msdc_cmd_next(struct msdc_host *host,
else if (!cmd->data) else if (!cmd->data)
msdc_request_done(host, mrq); msdc_request_done(host, mrq);
else else
msdc_start_data(host, mrq, cmd, cmd->data); msdc_start_data(host, cmd, cmd->data);
} }
static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
...@@ -2251,6 +2261,67 @@ static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -2251,6 +2261,67 @@ static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
return 0; return 0;
} }
static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card)
{
struct msdc_host *host = mmc_priv(mmc);
struct msdc_delay_phase dly1_delay;
u32 val, result_dly1 = 0;
u8 *ext_csd;
int i, ret;
if (host->top_base) {
sdr_set_bits(host->top_base + EMMC50_PAD_DS_TUNE,
PAD_DS_DLY_SEL);
if (host->hs400_ds_dly3)
sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE,
PAD_DS_DLY3, host->hs400_ds_dly3);
} else {
sdr_set_bits(host->base + PAD_DS_TUNE, PAD_DS_TUNE_DLY_SEL);
if (host->hs400_ds_dly3)
sdr_set_field(host->base + PAD_DS_TUNE,
PAD_DS_TUNE_DLY3, host->hs400_ds_dly3);
}
host->hs400_tuning = true;
for (i = 0; i < PAD_DELAY_MAX; i++) {
if (host->top_base)
sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE,
PAD_DS_DLY1, i);
else
sdr_set_field(host->base + PAD_DS_TUNE,
PAD_DS_TUNE_DLY1, i);
ret = mmc_get_ext_csd(card, &ext_csd);
if (!ret)
result_dly1 |= (1 << i);
}
host->hs400_tuning = false;
dly1_delay = get_best_delay(host, result_dly1);
if (dly1_delay.maxlen == 0) {
dev_err(host->dev, "Failed to get DLY1 delay!\n");
goto fail;
}
if (host->top_base)
sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE,
PAD_DS_DLY1, dly1_delay.final_phase);
else
sdr_set_field(host->base + PAD_DS_TUNE,
PAD_DS_TUNE_DLY1, dly1_delay.final_phase);
if (host->top_base)
val = readl(host->top_base + EMMC50_PAD_DS_TUNE);
else
val = readl(host->base + PAD_DS_TUNE);
dev_info(host->dev, "Fianl PAD_DS_TUNE: 0x%x\n", val);
return 0;
fail:
dev_err(host->dev, "Failed to tuning DS pin delay!\n");
return -EIO;
}
static void msdc_hw_reset(struct mmc_host *mmc) static void msdc_hw_reset(struct mmc_host *mmc)
{ {
struct msdc_host *host = mmc_priv(mmc); struct msdc_host *host = mmc_priv(mmc);
...@@ -2330,6 +2401,7 @@ static void msdc_cqe_enable(struct mmc_host *mmc) ...@@ -2330,6 +2401,7 @@ static void msdc_cqe_enable(struct mmc_host *mmc)
static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery) static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
{ {
struct msdc_host *host = mmc_priv(mmc); struct msdc_host *host = mmc_priv(mmc);
unsigned int val = 0;
/* disable cmdq irq */ /* disable cmdq irq */
sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INT_CMDQ); sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INT_CMDQ);
...@@ -2339,6 +2411,9 @@ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery) ...@@ -2339,6 +2411,9 @@ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
if (recovery) { if (recovery) {
sdr_set_field(host->base + MSDC_DMA_CTRL, sdr_set_field(host->base + MSDC_DMA_CTRL,
MSDC_DMA_CTRL_STOP, 1); MSDC_DMA_CTRL_STOP, 1);
if (WARN_ON(readl_poll_timeout(host->base + MSDC_DMA_CFG, val,
!(val & MSDC_DMA_CFG_STS), 1, 3000)))
return;
msdc_reset_hw(host); msdc_reset_hw(host);
} }
} }
...@@ -2377,6 +2452,7 @@ static const struct mmc_host_ops mt_msdc_ops = { ...@@ -2377,6 +2452,7 @@ static const struct mmc_host_ops mt_msdc_ops = {
.card_busy = msdc_card_busy, .card_busy = msdc_card_busy,
.execute_tuning = msdc_execute_tuning, .execute_tuning = msdc_execute_tuning,
.prepare_hs400_tuning = msdc_prepare_hs400_tuning, .prepare_hs400_tuning = msdc_prepare_hs400_tuning,
.execute_hs400_tuning = msdc_execute_hs400_tuning,
.hw_reset = msdc_hw_reset, .hw_reset = msdc_hw_reset,
}; };
...@@ -2396,6 +2472,9 @@ static void msdc_of_property_parse(struct platform_device *pdev, ...@@ -2396,6 +2472,9 @@ static void msdc_of_property_parse(struct platform_device *pdev,
of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay", of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay",
&host->hs400_ds_delay); &host->hs400_ds_delay);
of_property_read_u32(pdev->dev.of_node, "mediatek,hs400-ds-dly3",
&host->hs400_ds_dly3);
of_property_read_u32(pdev->dev.of_node, "mediatek,hs200-cmd-int-delay", of_property_read_u32(pdev->dev.of_node, "mediatek,hs200-cmd-int-delay",
&host->hs200_cmd_int_delay); &host->hs200_cmd_int_delay);
......
...@@ -552,6 +552,11 @@ static const struct of_device_id mxs_mmc_dt_ids[] = { ...@@ -552,6 +552,11 @@ static const struct of_device_id mxs_mmc_dt_ids[] = {
}; };
MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids); MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids);
static void mxs_mmc_regulator_disable(void *regulator)
{
regulator_disable(regulator);
}
static int mxs_mmc_probe(struct platform_device *pdev) static int mxs_mmc_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
...@@ -591,6 +596,11 @@ static int mxs_mmc_probe(struct platform_device *pdev) ...@@ -591,6 +596,11 @@ static int mxs_mmc_probe(struct platform_device *pdev)
"Failed to enable vmmc regulator: %d\n", ret); "Failed to enable vmmc regulator: %d\n", ret);
goto out_mmc_free; goto out_mmc_free;
} }
ret = devm_add_action_or_reset(&pdev->dev, mxs_mmc_regulator_disable,
reg_vmmc);
if (ret)
goto out_mmc_free;
} }
ssp->clk = devm_clk_get(&pdev->dev, NULL); ssp->clk = devm_clk_get(&pdev->dev, NULL);
......
...@@ -702,11 +702,6 @@ static void omap_hsmmc_context_save(struct omap_hsmmc_host *host) ...@@ -702,11 +702,6 @@ static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
#else #else
static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
{
return 0;
}
static void omap_hsmmc_context_save(struct omap_hsmmc_host *host) static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
{ {
} }
...@@ -1515,7 +1510,7 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) ...@@ -1515,7 +1510,7 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
* REVISIT: should be moved to sdio core and made more * REVISIT: should be moved to sdio core and made more
* general e.g. by expanding the DT bindings of child nodes * general e.g. by expanding the DT bindings of child nodes
* to provide a mechanism to provide this information: * to provide a mechanism to provide this information:
* Documentation/devicetree/bindings/mmc/mmc-card.txt * Documentation/devicetree/bindings/mmc/mmc-card.yaml
*/ */
np = of_get_compatible_child(np, "ti,wl1251"); np = of_get_compatible_child(np, "ti,wl1251");
...@@ -2086,6 +2081,7 @@ static int omap_hsmmc_resume(struct device *dev) ...@@ -2086,6 +2081,7 @@ static int omap_hsmmc_resume(struct device *dev)
} }
#endif #endif
#ifdef CONFIG_PM
static int omap_hsmmc_runtime_suspend(struct device *dev) static int omap_hsmmc_runtime_suspend(struct device *dev)
{ {
struct omap_hsmmc_host *host; struct omap_hsmmc_host *host;
...@@ -2153,11 +2149,11 @@ static int omap_hsmmc_runtime_resume(struct device *dev) ...@@ -2153,11 +2149,11 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
spin_unlock_irqrestore(&host->irq_lock, flags); spin_unlock_irqrestore(&host->irq_lock, flags);
return 0; return 0;
} }
#endif
static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = { static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume) SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)
.runtime_suspend = omap_hsmmc_runtime_suspend, SET_RUNTIME_PM_OPS(omap_hsmmc_runtime_suspend, omap_hsmmc_runtime_resume, NULL)
.runtime_resume = omap_hsmmc_runtime_resume,
}; };
static struct platform_driver omap_hsmmc_driver = { static struct platform_driver omap_hsmmc_driver = {
......
...@@ -362,23 +362,11 @@ static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev) ...@@ -362,23 +362,11 @@ static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev)
static int bxt_get_cd(struct mmc_host *mmc) static int bxt_get_cd(struct mmc_host *mmc)
{ {
int gpio_cd = mmc_gpio_get_cd(mmc); int gpio_cd = mmc_gpio_get_cd(mmc);
struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
int ret = 0;
if (!gpio_cd) if (!gpio_cd)
return 0; return 0;
spin_lock_irqsave(&host->lock, flags); return sdhci_get_cd_nogpio(mmc);
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
out:
spin_unlock_irqrestore(&host->lock, flags);
return ret;
} }
static int intel_probe_slot(struct platform_device *pdev, struct acpi_device *adev) static int intel_probe_slot(struct platform_device *pdev, struct acpi_device *adev)
......
...@@ -196,6 +196,9 @@ ...@@ -196,6 +196,9 @@
*/ */
#define ESDHC_FLAG_BROKEN_AUTO_CMD23 BIT(16) #define ESDHC_FLAG_BROKEN_AUTO_CMD23 BIT(16)
/* ERR004536 is not applicable for the IP */
#define ESDHC_FLAG_SKIP_ERR004536 BIT(17)
enum wp_types { enum wp_types {
ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ ESDHC_WP_NONE, /* no WP, neither controller nor gpio */
ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ ESDHC_WP_CONTROLLER, /* mmc controller internal WP */
...@@ -289,6 +292,13 @@ static const struct esdhc_soc_data usdhc_imx7d_data = { ...@@ -289,6 +292,13 @@ static const struct esdhc_soc_data usdhc_imx7d_data = {
| ESDHC_FLAG_BROKEN_AUTO_CMD23, | ESDHC_FLAG_BROKEN_AUTO_CMD23,
}; };
static struct esdhc_soc_data usdhc_s32g2_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
| ESDHC_FLAG_SKIP_ERR004536,
};
static struct esdhc_soc_data usdhc_imx7ulp_data = { static struct esdhc_soc_data usdhc_imx7ulp_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
...@@ -347,6 +357,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { ...@@ -347,6 +357,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
{ .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, },
{ .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, },
{ .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, },
{ .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
...@@ -1375,8 +1386,10 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) ...@@ -1375,8 +1386,10 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
* erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
* TO1.1, it's harmless for MX6SL * TO1.1, it's harmless for MX6SL
*/ */
writel(readl(host->ioaddr + 0x6c) & ~BIT(7), if (!(imx_data->socdata->flags & ESDHC_FLAG_SKIP_ERR004536)) {
host->ioaddr + 0x6c); writel(readl(host->ioaddr + 0x6c) & ~BIT(7),
host->ioaddr + 0x6c);
}
/* disable DLL_CTRL delay line settings */ /* disable DLL_CTRL delay line settings */
writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
......
...@@ -191,6 +191,13 @@ static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { ...@@ -191,6 +191,13 @@ static const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = {
.hiword_update = false, .hiword_update = false,
}; };
static const struct sdhci_arasan_soc_ctl_map thunderbay_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,
};
static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = { static const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = {
.baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 },
.clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 },
...@@ -456,6 +463,15 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { ...@@ -456,6 +463,15 @@ static const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = {
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
}; };
static const struct sdhci_pltfm_data sdhci_arasan_thunderbay_pdata = {
.ops = &sdhci_arasan_cqe_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC |
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
};
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
/** /**
* sdhci_arasan_suspend - Suspend method for the driver * sdhci_arasan_suspend - Suspend method for the driver
...@@ -1132,6 +1148,12 @@ static struct sdhci_arasan_of_data sdhci_arasan_generic_data = { ...@@ -1132,6 +1148,12 @@ static struct sdhci_arasan_of_data sdhci_arasan_generic_data = {
.clk_ops = &arasan_clk_ops, .clk_ops = &arasan_clk_ops,
}; };
static const struct sdhci_arasan_of_data sdhci_arasan_thunderbay_data = {
.soc_ctl_map = &thunderbay_soc_ctl_map,
.pdata = &sdhci_arasan_thunderbay_pdata,
.clk_ops = &arasan_clk_ops,
};
static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = { static const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = {
.ops = &sdhci_arasan_cqe_ops, .ops = &sdhci_arasan_cqe_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
...@@ -1265,6 +1287,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = { ...@@ -1265,6 +1287,10 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
.compatible = "intel,keembay-sdhci-5.1-sdio", .compatible = "intel,keembay-sdhci-5.1-sdio",
.data = &intel_keembay_sdio_data, .data = &intel_keembay_sdio_data,
}, },
{
.compatible = "intel,thunderbay-sdhci-5.1",
.data = &sdhci_arasan_thunderbay_data,
},
/* Generic compatible below here */ /* Generic compatible below here */
{ {
.compatible = "arasan,sdhci-8.9a", .compatible = "arasan,sdhci-8.9a",
...@@ -1626,7 +1652,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev) ...@@ -1626,7 +1652,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") || 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-sd") ||
of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) { of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio") ||
of_device_is_compatible(np, "intel,thunderbay-sdhci-5.1")) {
sdhci_arasan_update_clockmultiplier(host, 0x0); sdhci_arasan_update_clockmultiplier(host, 0x0);
sdhci_arasan_update_support64b(host, 0x0); sdhci_arasan_update_support64b(host, 0x0);
......
This diff is collapsed.
...@@ -17,8 +17,6 @@ ...@@ -17,8 +17,6 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
...@@ -26,11 +24,13 @@ ...@@ -26,11 +24,13 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mmc/sdhci-pci-data.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#ifdef CONFIG_X86 #ifdef CONFIG_X86
#include <asm/iosf_mbi.h> #include <asm/iosf_mbi.h>
#endif #endif
...@@ -345,73 +345,6 @@ static int pch_hc_probe_slot(struct sdhci_pci_slot *slot) ...@@ -345,73 +345,6 @@ static int pch_hc_probe_slot(struct sdhci_pci_slot *slot)
return 0; return 0;
} }
#ifdef CONFIG_PM
static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
{
struct sdhci_pci_slot *slot = dev_id;
struct sdhci_host *host = slot->host;
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
return IRQ_HANDLED;
}
static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
{
int err, irq, gpio = slot->cd_gpio;
slot->cd_gpio = -EINVAL;
slot->cd_irq = -EINVAL;
if (!gpio_is_valid(gpio))
return;
err = devm_gpio_request(&slot->chip->pdev->dev, gpio, "sd_cd");
if (err < 0)
goto out;
err = gpio_direction_input(gpio);
if (err < 0)
goto out_free;
irq = gpio_to_irq(gpio);
if (irq < 0)
goto out_free;
err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING, "sd_cd", slot);
if (err)
goto out_free;
slot->cd_gpio = gpio;
slot->cd_irq = irq;
return;
out_free:
devm_gpio_free(&slot->chip->pdev->dev, gpio);
out:
dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
}
static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
{
if (slot->cd_irq >= 0)
free_irq(slot->cd_irq, slot);
}
#else
static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
{
}
static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
{
}
#endif
static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
{ {
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
...@@ -616,24 +549,6 @@ static int intel_select_drive_strength(struct mmc_card *card, ...@@ -616,24 +549,6 @@ static int intel_select_drive_strength(struct mmc_card *card,
return intel_host->drv_strength; return intel_host->drv_strength;
} }
static int sdhci_get_cd_nogpio(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
out:
spin_unlock_irqrestore(&host->lock, flags);
return ret;
}
static int bxt_get_cd(struct mmc_host *mmc) static int bxt_get_cd(struct mmc_host *mmc)
{ {
int gpio_cd = mmc_gpio_get_cd(mmc); int gpio_cd = mmc_gpio_get_cd(mmc);
...@@ -2000,21 +1915,6 @@ int sdhci_pci_enable_dma(struct sdhci_host *host) ...@@ -2000,21 +1915,6 @@ int sdhci_pci_enable_dma(struct sdhci_host *host)
return 0; return 0;
} }
static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host)
{
struct sdhci_pci_slot *slot = sdhci_priv(host);
int rst_n_gpio = slot->rst_n_gpio;
if (!gpio_is_valid(rst_n_gpio))
return;
gpio_set_value_cansleep(rst_n_gpio, 0);
/* For eMMC, minimum is 1us but give it 10us for good measure */
udelay(10);
gpio_set_value_cansleep(rst_n_gpio, 1);
/* For eMMC, minimum is 200us but give it 300us for good measure */
usleep_range(300, 1000);
}
static void sdhci_pci_hw_reset(struct sdhci_host *host) static void sdhci_pci_hw_reset(struct sdhci_host *host)
{ {
struct sdhci_pci_slot *slot = sdhci_priv(host); struct sdhci_pci_slot *slot = sdhci_priv(host);
...@@ -2145,26 +2045,8 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( ...@@ -2145,26 +2045,8 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
slot->chip = chip; slot->chip = chip;
slot->host = host; slot->host = host;
slot->rst_n_gpio = -EINVAL;
slot->cd_gpio = -EINVAL;
slot->cd_idx = -1; slot->cd_idx = -1;
/* Retrieve platform data if there is any */
if (*sdhci_pci_get_data)
slot->data = sdhci_pci_get_data(pdev, slotno);
if (slot->data) {
if (slot->data->setup) {
ret = slot->data->setup(slot->data);
if (ret) {
dev_err(&pdev->dev, "platform setup failed\n");
goto free;
}
}
slot->rst_n_gpio = slot->data->rst_n_gpio;
slot->cd_gpio = slot->data->cd_gpio;
}
host->hw_name = "PCI"; host->hw_name = "PCI";
host->ops = chip->fixes && chip->fixes->ops ? host->ops = chip->fixes && chip->fixes->ops ?
chip->fixes->ops : chip->fixes->ops :
...@@ -2188,17 +2070,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( ...@@ -2188,17 +2070,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
goto cleanup; goto cleanup;
} }
if (gpio_is_valid(slot->rst_n_gpio)) {
if (!devm_gpio_request(&pdev->dev, slot->rst_n_gpio, "eMMC_reset")) {
gpio_direction_output(slot->rst_n_gpio, 1);
slot->host->mmc->caps |= MMC_CAP_HW_RESET;
slot->hw_reset = sdhci_pci_gpio_hw_reset;
} else {
dev_warn(&pdev->dev, "failed to request rst_n_gpio\n");
slot->rst_n_gpio = -EINVAL;
}
}
host->mmc->pm_caps = MMC_PM_KEEP_POWER; host->mmc->pm_caps = MMC_PM_KEEP_POWER;
host->mmc->slotno = slotno; host->mmc->slotno = slotno;
host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
...@@ -2233,15 +2104,11 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( ...@@ -2233,15 +2104,11 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
if (ret) if (ret)
goto remove; goto remove;
sdhci_pci_add_own_cd(slot);
/* /*
* Check if the chip needs a separate GPIO for card detect to wake up * Check if the chip needs a separate GPIO for card detect to wake up
* from runtime suspend. If it is not there, don't allow runtime PM. * from runtime suspend. If it is not there, don't allow runtime PM.
* Note sdhci_pci_add_own_cd() sets slot->cd_gpio to -EINVAL on failure.
*/ */
if (chip->fixes && chip->fixes->own_cd_for_runtime_pm && if (chip->fixes && chip->fixes->own_cd_for_runtime_pm && slot->cd_idx < 0)
!gpio_is_valid(slot->cd_gpio) && slot->cd_idx < 0)
chip->allow_runtime_pm = false; chip->allow_runtime_pm = false;
return slot; return slot;
...@@ -2251,10 +2118,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( ...@@ -2251,10 +2118,6 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
chip->fixes->remove_slot(slot, 0); chip->fixes->remove_slot(slot, 0);
cleanup: cleanup:
if (slot->data && slot->data->cleanup)
slot->data->cleanup(slot->data);
free:
sdhci_free_host(host); sdhci_free_host(host);
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -2265,8 +2128,6 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) ...@@ -2265,8 +2128,6 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
int dead; int dead;
u32 scratch; u32 scratch;
sdhci_pci_remove_own_cd(slot);
dead = 0; dead = 0;
scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS);
if (scratch == (u32)-1) if (scratch == (u32)-1)
...@@ -2277,9 +2138,6 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) ...@@ -2277,9 +2138,6 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
if (slot->chip->fixes && slot->chip->fixes->remove_slot) if (slot->chip->fixes && slot->chip->fixes->remove_slot)
slot->chip->fixes->remove_slot(slot, dead); slot->chip->fixes->remove_slot(slot, dead);
if (slot->data && slot->data->cleanup)
slot->data->cleanup(slot->data);
sdhci_free_host(slot->host); sdhci_free_host(slot->host);
} }
......
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/module.h>
#include <linux/mmc/sdhci-pci-data.h>
struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno);
EXPORT_SYMBOL_GPL(sdhci_pci_get_data);
...@@ -489,7 +489,7 @@ static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip, ...@@ -489,7 +489,7 @@ static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip,
ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI); ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI);
if (!ret) { if (!ret) {
pr_info("%s: unsupport msi, use INTx irq\n", pr_info("%s: unsupported MSI, use INTx irq\n",
mmc_hostname(host->mmc)); mmc_hostname(host->mmc));
return; return;
} }
......
...@@ -156,11 +156,6 @@ struct sdhci_pci_fixes { ...@@ -156,11 +156,6 @@ struct sdhci_pci_fixes {
struct sdhci_pci_slot { struct sdhci_pci_slot {
struct sdhci_pci_chip *chip; struct sdhci_pci_chip *chip;
struct sdhci_host *host; struct sdhci_host *host;
struct sdhci_pci_data *data;
int rst_n_gpio;
int cd_gpio;
int cd_irq;
int cd_idx; int cd_idx;
bool cd_override_level; bool cd_override_level;
......
...@@ -791,4 +791,3 @@ module_platform_driver(sdhci_s3c_driver); ...@@ -791,4 +791,3 @@ module_platform_driver(sdhci_s3c_driver);
MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue"); MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue");
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:s3c-sdhci");
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/iopoll.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -39,6 +40,9 @@ ...@@ -39,6 +40,9 @@
#define SDHCI_SPRD_BIT_POSRD_DLY_INV BIT(21) #define SDHCI_SPRD_BIT_POSRD_DLY_INV BIT(21)
#define SDHCI_SPRD_BIT_NEGRD_DLY_INV BIT(29) #define SDHCI_SPRD_BIT_NEGRD_DLY_INV BIT(29)
#define SDHCI_SPRD_REG_32_DLL_STS0 0x210
#define SDHCI_SPRD_DLL_LOCKED BIT(18)
#define SDHCI_SPRD_REG_32_BUSY_POSI 0x250 #define SDHCI_SPRD_REG_32_BUSY_POSI 0x250
#define SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN BIT(25) #define SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN BIT(25)
#define SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN BIT(24) #define SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN BIT(24)
...@@ -256,6 +260,15 @@ static void sdhci_sprd_enable_phy_dll(struct sdhci_host *host) ...@@ -256,6 +260,15 @@ static void sdhci_sprd_enable_phy_dll(struct sdhci_host *host)
sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG); sdhci_writel(host, tmp, SDHCI_SPRD_REG_32_DLL_CFG);
/* wait 1ms */ /* wait 1ms */
usleep_range(1000, 1250); usleep_range(1000, 1250);
if (read_poll_timeout(sdhci_readl, tmp, (tmp & SDHCI_SPRD_DLL_LOCKED),
2000, USEC_PER_SEC, false, host, SDHCI_SPRD_REG_32_DLL_STS0)) {
pr_err("%s: DLL locked fail!\n", mmc_hostname(host->mmc));
pr_info("%s: DLL_STS0 : 0x%x, DLL_CFG : 0x%x\n",
mmc_hostname(host->mmc),
sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_STS0),
sdhci_readl(host, SDHCI_SPRD_REG_32_DLL_CFG));
}
} }
static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock) static void sdhci_sprd_set_clock(struct sdhci_host *host, unsigned int clock)
......
...@@ -930,7 +930,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, ...@@ -930,7 +930,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
struct mmc_data *data; struct mmc_data *data;
unsigned target_timeout, current_timeout; unsigned target_timeout, current_timeout;
*too_big = true; *too_big = false;
/* /*
* If the host controller provides us with an incorrect timeout * If the host controller provides us with an incorrect timeout
...@@ -941,7 +941,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, ...@@ -941,7 +941,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
return host->max_timeout_count; return host->max_timeout_count;
/* Unspecified command, asume max */ /* Unspecified command, assume max */
if (cmd == NULL) if (cmd == NULL)
return host->max_timeout_count; return host->max_timeout_count;
...@@ -968,17 +968,14 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd, ...@@ -968,17 +968,14 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd,
while (current_timeout < target_timeout) { while (current_timeout < target_timeout) {
count++; count++;
current_timeout <<= 1; current_timeout <<= 1;
if (count > host->max_timeout_count) if (count > host->max_timeout_count) {
if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
DBG("Too large timeout 0x%x requested for CMD%d!\n",
count, cmd->opcode);
count = host->max_timeout_count;
*too_big = true;
break; break;
} }
if (count > host->max_timeout_count) {
if (!(host->quirks2 & SDHCI_QUIRK2_DISABLE_HW_TIMEOUT))
DBG("Too large timeout 0x%x requested for CMD%d!\n",
count, cmd->opcode);
count = host->max_timeout_count;
} else {
*too_big = false;
} }
return count; return count;
...@@ -2428,6 +2425,25 @@ static int sdhci_get_cd(struct mmc_host *mmc) ...@@ -2428,6 +2425,25 @@ static int sdhci_get_cd(struct mmc_host *mmc)
return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
} }
int sdhci_get_cd_nogpio(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD)
goto out;
ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
out:
spin_unlock_irqrestore(&host->lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(sdhci_get_cd_nogpio);
static int sdhci_check_ro(struct sdhci_host *host) static int sdhci_check_ro(struct sdhci_host *host)
{ {
unsigned long flags; unsigned long flags;
...@@ -3238,7 +3254,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) ...@@ -3238,7 +3254,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p)
-ETIMEDOUT : -ETIMEDOUT :
-EILSEQ; -EILSEQ;
if (mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { if (sdhci_auto_cmd23(host, mrq)) {
mrq->sbc->error = err; mrq->sbc->error = err;
__sdhci_finish_mrq(host, mrq); __sdhci_finish_mrq(host, mrq);
return; return;
......
...@@ -750,7 +750,6 @@ static inline void *sdhci_priv(struct sdhci_host *host) ...@@ -750,7 +750,6 @@ static inline void *sdhci_priv(struct sdhci_host *host)
return host->private; return host->private;
} }
void sdhci_card_detect(struct sdhci_host *host);
void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver, void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
const u32 *caps, const u32 *caps1); const u32 *caps, const u32 *caps1);
int sdhci_setup_host(struct sdhci_host *host); int sdhci_setup_host(struct sdhci_host *host);
...@@ -775,6 +774,7 @@ void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, ...@@ -775,6 +774,7 @@ void sdhci_set_power_and_bus_voltage(struct sdhci_host *host,
unsigned short vdd); unsigned short vdd);
void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
unsigned short vdd); unsigned short vdd);
int sdhci_get_cd_nogpio(struct mmc_host *mmc);
void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq); void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq);
int sdhci_request_atomic(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_set_bus_width(struct sdhci_host *host, int width);
......
...@@ -162,6 +162,9 @@ struct mmc_host_ops { ...@@ -162,6 +162,9 @@ struct mmc_host_ops {
/* Prepare HS400 target operating frequency depending host driver */ /* Prepare HS400 target operating frequency depending host driver */
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios); int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
/* Execute HS400 tuning depending host driver */
int (*execute_hs400_tuning)(struct mmc_host *host, struct mmc_card *card);
/* Prepare switch to DDR during the HS400 init sequence */ /* Prepare switch to DDR during the HS400 init sequence */
int (*hs400_prepare_ddr)(struct mmc_host *host); int (*hs400_prepare_ddr)(struct mmc_host *host);
...@@ -634,5 +637,6 @@ static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data) ...@@ -634,5 +637,6 @@ static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data)
int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode); int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
#endif /* LINUX_MMC_HOST_H */ #endif /* LINUX_MMC_HOST_H */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef LINUX_MMC_SDHCI_PCI_DATA_H
#define LINUX_MMC_SDHCI_PCI_DATA_H
struct pci_dev;
struct sdhci_pci_data {
struct pci_dev *pdev;
int slotno;
int rst_n_gpio; /* Set to -EINVAL if unused */
int cd_gpio; /* Set to -EINVAL if unused */
int (*setup)(struct sdhci_pci_data *data);
void (*cleanup)(struct sdhci_pci_data *data);
};
extern struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev,
int slotno);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment