Commit 1151e3cd authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Use common polling loop for CMD1
   - Add support for DT compatibles for card quirks and use it for ti,wl1251
   - Fixup storing of the OCR mask for MMC_QUIRK_NONSTD_SDIO

  MMC host:
   - dw_mmc: Add support for MMC_GEN_CMDs
   - dw_mmc: Fixup calculation of the data timeout
   - dw_mmc-exynos: Add support for the ARTPEC-8 variant
   - jz4740: Add support for bi-directional DMA channels
   - mmci: Add support for eMMC HS200 mode for the stm32 sdmmc variant
   - mmci: Add support for stm32 sdmmc variant revision v2.2
   - mtk-sd: A couple of various minor improvements
   - omap_hsmmc: Drop redundant initialization for the ti,wl1251 chip
   - sdhci-esdhc-imx: Add support for the i.MXRT series variant
   - sdhci-esdhc-imx: Add Haibo Chen as maintainer
   - sdhci-pci: Add support for the Intel ADL variant
   - sdhci-pci-gli: GL975[50]: Add support for the Apple ARM64 variant
   - sdhci-pci-o2micro: Improve support for SDR104/HS200"

* tag 'mmc-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (54 commits)
  dt-bindings: mmc: synopsys-dw-mshc: integrate Altera and Imagination
  mmc: pwrseq: Use bitmap_free() to free bitmap
  dt-bindings: mmc: PL18x stop relying on order of dma-names
  dt-bindings: mmc: sdhci-msm: Add compatible string for msm8994
  mmc: au1xmmc: propagate errors from platform_get_irq()
  mmc: sdhci-pci-o2micro: Restore the SD clock's base clock frequency
  mmc: sdhci-pci-o2micro: Improve card input timing at SDR104/HS200 mode
  mmc: mtk-sd: Assign src_clk parent to src_clk_cg for legacy DTs
  mmc: mtk-sd: Fix usage of devm_clk_get_optional()
  mmc: mtk-sd: Take action for no-sdio device-tree parameter
  mmc: mtk-sd: Use BIT() and GENMASK() macros to describe fields
  mmc: mtk-sd: Use readl_poll_timeout instead of open-coded polling
  MAINTAINERS: Add i.MX sdhci maintainer
  mmc: jz4740: Support using a bi-directional DMA channel
  dt-bindings: mmc: ingenic: Support using bi-directional DMA channel
  mmc: dw_mmc: Do not wait for DTO in case of error
  mmc: dw_mmc: Add driver callbacks for data read timeout
  mmc: dw_mmc-exynos: Add support for ARTPEC-8
  dt-bindings: mmc: exynos-dw-mshc: Add support for ARTPEC-8
  mmc: meson-mx-sdio: add IRQ check
  ...
parents 1cc8d14c 356f3f2c
...@@ -118,6 +118,9 @@ properties: ...@@ -118,6 +118,9 @@ properties:
phy-names: phy-names:
const: phy_arasan const: phy_arasan
resets:
maxItems: 1
arasan,soc-ctl-syscon: arasan,soc-ctl-syscon:
$ref: /schemas/types.yaml#/definitions/phandle $ref: /schemas/types.yaml#/definitions/phandle
description: description:
......
...@@ -53,6 +53,12 @@ properties: ...@@ -53,6 +53,12 @@ properties:
items: items:
- const: arm,pl18x - const: arm,pl18x
- const: arm,primecell - const: arm,primecell
- description: Entry for STMicroelectronics variant of PL18x.
This dedicated compatible is used by bootloaders.
items:
- const: st,stm32-sdmmc2
- const: arm,pl18x
- const: arm,primecell
clocks: clocks:
description: One or two clocks, the "apb_pclk" and the "MCLK" description: One or two clocks, the "apb_pclk" and the "MCLK"
...@@ -60,6 +66,18 @@ properties: ...@@ -60,6 +66,18 @@ properties:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
dmas:
maxItems: 2
dma-names:
oneOf:
- items:
- const: tx
- const: rx
- items:
- const: rx
- const: tx
power-domains: true power-domains: true
resets: resets:
...@@ -213,7 +231,6 @@ examples: ...@@ -213,7 +231,6 @@ examples:
arm,primecell-periphid = <0x10153180>; arm,primecell-periphid = <0x10153180>;
reg = <0x52007000 0x1000>; reg = <0x52007000 0x1000>;
interrupts = <49>; interrupts = <49>;
interrupt-names = "cmd_irq";
clocks = <&rcc 0>; clocks = <&rcc 0>;
clock-names = "apb_pclk"; clock-names = "apb_pclk";
resets = <&rcc 1>; resets = <&rcc 1>;
......
* BROADCOM BRCMSTB/BMIPS SDHCI Controller
This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci-brcmstb driver.
NOTE: The driver disables all UHS speed modes by default and depends
on Device Tree properties to enable them for SoC/Board combinations
that support them.
Required properties:
- compatible: should be one of the following
- "brcm,bcm7425-sdhci"
- "brcm,bcm7445-sdhci"
- "brcm,bcm7216-sdhci"
Refer to clocks/clock-bindings.txt for generic clock consumer properties.
Example:
sdhci@84b0000 {
sd-uhs-sdr50;
sd-uhs-ddr50;
sd-uhs-sdr104;
sdhci,auto-cmd12;
compatible = "brcm,bcm7216-sdhci",
"brcm,bcm7445-sdhci",
"brcm,sdhci-brcmstb";
reg = <0x84b0000 0x260 0x84b0300 0x200>;
reg-names = "host", "cfg";
interrupts = <0x0 0x26 0x4>;
interrupt-names = "sdio0_0";
clocks = <&scmi_clk 245>;
clock-names = "sw_sdio";
};
sdhci@84b1000 {
mmc-ddr-1_8v;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
mmc-hs400-enhanced-strobe;
supports-cqe;
non-removable;
bus-width = <0x8>;
compatible = "brcm,bcm7216-sdhci",
"brcm,bcm7445-sdhci",
"brcm,sdhci-brcmstb";
reg = <0x84b1000 0x260 0x84b1300 0x200>;
reg-names = "host", "cfg";
interrupts = <0x0 0x27 0x4>;
interrupt-names = "sdio1_0";
clocks = <&scmi_clk 245>;
clock-names = "sw_sdio";
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/brcm,sdhci-brcmstb.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom BRCMSTB/BMIPS SDHCI Controller binding
maintainers:
- Al Cooper <alcooperx@gmail.com>
- Florian Fainelli <f.fainelli@gmail.com>
allOf:
- $ref: mmc-controller.yaml#
properties:
compatible:
oneOf:
- items:
- enum:
- brcm,bcm7216-sdhci
- const: brcm,bcm7445-sdhci
- const: brcm,sdhci-brcmstb
- items:
- enum:
- brcm,bcm7445-sdhci
- const: brcm,sdhci-brcmstb
- items:
- enum:
- brcm,bcm7425-sdhci
- const: brcm,sdhci-brcmstb
reg:
minItems: 2
reg-names:
items:
- const: host
- const: cfg
interrupts:
maxItems: 1
clocks:
maxItems: 1
description:
handle to core clock for the sdhci controller.
clock-names:
items:
- const: sw_sdio
sdhci,auto-cmd12:
type: boolean
description: Specifies that controller should use auto CMD12
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
mmc@84b0000 {
sd-uhs-sdr50;
sd-uhs-ddr50;
sd-uhs-sdr104;
sdhci,auto-cmd12;
compatible = "brcm,bcm7216-sdhci",
"brcm,bcm7445-sdhci",
"brcm,sdhci-brcmstb";
reg = <0x84b0000 0x260>, <0x84b0300 0x200>;
reg-names = "host", "cfg";
interrupts = <0x0 0x26 0x4>;
interrupt-names = "sdio0_0";
clocks = <&scmi_clk 245>;
clock-names = "sw_sdio";
};
mmc@84b1000 {
mmc-ddr-1_8v;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
mmc-hs400-enhanced-strobe;
supports-cqe;
non-removable;
bus-width = <0x8>;
compatible = "brcm,bcm7216-sdhci",
"brcm,bcm7445-sdhci",
"brcm,sdhci-brcmstb";
reg = <0x84b1000 0x260>, <0x84b1300 0x200>;
reg-names = "host", "cfg";
interrupts = <0x0 0x27 0x4>;
interrupt-names = "sdio1_0";
clocks = <&scmi_clk 245>;
clock-names = "sw_sdio";
};
...@@ -22,6 +22,8 @@ Required Properties: ...@@ -22,6 +22,8 @@ Required Properties:
specific extensions. specific extensions.
- "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7 - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
specific extensions having an SMU. specific extensions having an SMU.
- "axis,artpec8-dw-mshc": for controllers with ARTPEC-8 specific
extensions.
* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface * samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
unit (ciu) clock. This property is applicable only for Exynos5 SoC's and unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
......
...@@ -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
- fsl,imxrt1050-usdhc
- nxp,s32g2-usdhc - nxp,s32g2-usdhc
- items: - items:
- enum: - enum:
...@@ -44,6 +45,10 @@ properties: ...@@ -44,6 +45,10 @@ properties:
- fsl,imx8qm-usdhc - fsl,imx8qm-usdhc
- fsl,imx8qxp-usdhc - fsl,imx8qxp-usdhc
- const: fsl,imx7d-usdhc - const: fsl,imx7d-usdhc
- items:
- enum:
- fsl,imx8ulp-usdhc
- const: fsl,imx8mm-usdhc
reg: reg:
maxItems: 1 maxItems: 1
...@@ -116,6 +121,9 @@ properties: ...@@ -116,6 +121,9 @@ properties:
- const: ahb - const: ahb
- const: per - const: per
power-domains:
maxItems: 1
pinctrl-names: pinctrl-names:
oneOf: oneOf:
- minItems: 3 - minItems: 3
......
* Imagination specific extensions to the Synopsys Designware Mobile Storage
Host Controller
The Synopsys designware mobile storage host controller is used to interface
a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
differences between the core Synopsys dw mshc controller properties described
by synopsys-dw-mshc.txt and the properties used by the Imagination specific
extensions to the Synopsys Designware Mobile Storage Host Controller.
Required Properties:
* compatible: should be
- "img,pistachio-dw-mshc": for Pistachio SoCs
Example:
mmc@18142000 {
compatible = "img,pistachio-dw-mshc";
reg = <0x18142000 0x400>;
interrupts = <GIC_SHARED 39 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&system_clk>, <&sdhost_clk>;
clock-names = "biu", "ciu";
fifo-depth = <0x20>;
bus-width = <4>;
disable-wp;
};
...@@ -39,14 +39,15 @@ properties: ...@@ -39,14 +39,15 @@ properties:
const: mmc const: mmc
dmas: dmas:
items: minItems: 1
- description: DMA controller phandle and request line for RX maxItems: 2
- description: DMA controller phandle and request line for TX
dma-names: dma-names:
items: oneOf:
- const: rx - items:
- const: tx - const: rx
- const: tx
- const: tx-rx
required: required:
- compatible - compatible
...@@ -80,3 +81,27 @@ examples: ...@@ -80,3 +81,27 @@ examples:
<&dma JZ4780_DMA_MSC0_TX 0xffffffff>; <&dma JZ4780_DMA_MSC0_TX 0xffffffff>;
dma-names = "rx", "tx"; dma-names = "rx", "tx";
}; };
- |
#include <dt-bindings/clock/ingenic,jz4780-cgu.h>
#include <dt-bindings/dma/jz4780-dma.h>
/*
* Alternative version of the example above,
* but using one single DMA channel for both
* TX and RX.
*/
mmc1: mmc@13460000 {
compatible = "ingenic,jz4780-mmc";
reg = <0x13460000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <36>;
clocks = <&cgu JZ4780_CLK_MSC1>;
clock-names = "mmc";
cap-sd-highspeed;
cap-mmc-highspeed;
cap-sdio-irq;
dmas = <&dma JZ4780_DMA_MSC1_TX JZ4780_DMA_MSC1_RX 0xffffffff>;
dma-names = "tx-rx";
};
...@@ -36,6 +36,9 @@ properties: ...@@ -36,6 +36,9 @@ properties:
- const: mediatek,mt8195-mmc - const: mediatek,mt8195-mmc
- const: mediatek,mt8183-mmc - const: mediatek,mt8183-mmc
reg:
maxItems: 1
clocks: clocks:
description: description:
Should contain phandle for the clock feeding the MMC controller. Should contain phandle for the clock feeding the MMC controller.
...@@ -62,6 +65,9 @@ properties: ...@@ -62,6 +65,9 @@ properties:
- const: axi_cg - const: axi_cg
- const: ahb_cg - const: ahb_cg
interrupts:
maxItems: 1
pinctrl-names: pinctrl-names:
items: items:
- const: default - const: default
......
...@@ -48,6 +48,8 @@ properties: ...@@ -48,6 +48,8 @@ properties:
- const: clk_ahb - const: clk_ahb
- const: clk_xin - const: clk_xin
sdhci-caps-mask: true
# PHY output tap delays: # PHY output tap delays:
# Used to delay the data valid window and align it to the sampling clock. # Used to delay the data valid window and align it to the sampling clock.
# Binding needs to be provided for each supported speed mode otherwise the # Binding needs to be provided for each supported speed mode otherwise the
......
...@@ -17,6 +17,7 @@ Required properties: ...@@ -17,6 +17,7 @@ Required properties:
"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"
"qcom,msm8994-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8996-sdhci", "qcom,sdhci-msm-v4" "qcom,msm8996-sdhci", "qcom,sdhci-msm-v4"
"qcom,qcs404-sdhci", "qcom,sdhci-msm-v5" "qcom,qcs404-sdhci", "qcom,sdhci-msm-v5"
"qcom,sc7180-sdhci", "qcom,sdhci-msm-v5"; "qcom,sc7180-sdhci", "qcom,sdhci-msm-v5";
......
* Altera SOCFPGA specific extensions to the Synopsys Designware Mobile
Storage Host Controller
The Synopsys designware mobile storage host controller is used to interface
a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
differences between the core Synopsys dw mshc controller properties described
by synopsys-dw-mshc.txt and the properties used by the Altera SOCFPGA specific
extensions to the Synopsys Designware Mobile Storage Host Controller.
Required Properties:
* compatible: should be
- "altr,socfpga-dw-mshc": for Altera's SOCFPGA platform
Example:
mmc: dwmmc0@ff704000 {
compatible = "altr,socfpga-dw-mshc";
reg = <0xff704000 0x1000>;
interrupts = <0 129 4>;
#address-cells = <1>;
#size-cells = <0>;
};
...@@ -26,6 +26,12 @@ properties: ...@@ -26,6 +26,12 @@ properties:
clocks: clocks:
maxItems: 1 maxItems: 1
dmas:
maxItems: 1
dma-names:
const: rx-tx
reset-names: reset-names:
description: | description: |
There are three reset signals at maximum There are three reset signals at maximum
......
...@@ -15,7 +15,10 @@ maintainers: ...@@ -15,7 +15,10 @@ maintainers:
# Everything else is described in the common file # Everything else is described in the common file
properties: properties:
compatible: compatible:
const: snps,dw-mshc enum:
- altr,socfpga-dw-mshc
- img,pistachio-dw-mshc
- snps,dw-mshc
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -17251,6 +17251,13 @@ L: linux-mmc@vger.kernel.org ...@@ -17251,6 +17251,13 @@ L: linux-mmc@vger.kernel.org
S: Maintained S: Maintained
F: drivers/mmc/host/sdhci-omap.c F: drivers/mmc/host/sdhci-omap.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) NXP i.MX DRIVER
M: Haibo Chen <haibo.chen@nxp.com>
L: linux-imx@nxp.com
L: linux-mmc@vger.kernel.org
S: Maintained
F: drivers/mmc/host/sdhci-esdhc-imx.c
SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER
M: Jonathan Derrick <jonathan.derrick@intel.com> M: Jonathan Derrick <jonathan.derrick@intel.com>
M: Revanth Rajashekar <revanth.rajashekar@intel.com> M: Revanth Rajashekar <revanth.rajashekar@intel.com>
......
...@@ -1908,8 +1908,8 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req) ...@@ -1908,8 +1908,8 @@ static int mmc_blk_card_busy(struct mmc_card *card, struct request *req)
cb_data.card = card; cb_data.card = card;
cb_data.status = 0; cb_data.status = 0;
err = __mmc_poll_for_busy(card, MMC_BLK_TIMEOUT_MS, &mmc_blk_busy_cb, err = __mmc_poll_for_busy(card->host, MMC_BLK_TIMEOUT_MS,
&cb_data); &mmc_blk_busy_cb, &cb_data);
/* /*
* Do not assume data transferred correctly if there are any error bits * Do not assume data transferred correctly if there are any error bits
......
...@@ -53,16 +53,6 @@ static struct attribute *mmc_dev_attrs[] = { ...@@ -53,16 +53,6 @@ static struct attribute *mmc_dev_attrs[] = {
}; };
ATTRIBUTE_GROUPS(mmc_dev); ATTRIBUTE_GROUPS(mmc_dev);
/*
* This currently matches any MMC driver to any MMC card - drivers
* themselves make the decision whether to drive this card in their
* probe method.
*/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
static int static int
mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{ {
...@@ -226,7 +216,6 @@ static const struct dev_pm_ops mmc_bus_pm_ops = { ...@@ -226,7 +216,6 @@ static const struct dev_pm_ops mmc_bus_pm_ops = {
static struct bus_type mmc_bus_type = { static struct bus_type mmc_bus_type = {
.name = "mmc", .name = "mmc",
.dev_groups = mmc_dev_groups, .dev_groups = mmc_dev_groups,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent, .uevent = mmc_bus_uevent,
.probe = mmc_bus_probe, .probe = mmc_bus_probe,
.remove = mmc_bus_remove, .remove = mmc_bus_remove,
......
...@@ -59,6 +59,9 @@ struct mmc_fixup { ...@@ -59,6 +59,9 @@ struct mmc_fixup {
/* for MMC cards */ /* for MMC cards */
unsigned int ext_csd_rev; unsigned int ext_csd_rev;
/* Match against functions declared in device tree */
const char *of_compatible;
void (*vendor_fixup)(struct mmc_card *card, int data); void (*vendor_fixup)(struct mmc_card *card, int data);
int data; int data;
}; };
...@@ -119,6 +122,21 @@ struct mmc_fixup { ...@@ -119,6 +122,21 @@ struct mmc_fixup {
_vendor, _device, \ _vendor, _device, \
_fixup, _data, EXT_CSD_REV_ANY) \ _fixup, _data, EXT_CSD_REV_ANY) \
#define SDIO_FIXUP_COMPATIBLE(_compatible, _fixup, _data) \
{ \
.name = CID_NAME_ANY, \
.manfid = CID_MANFID_ANY, \
.oemid = CID_OEMID_ANY, \
.rev_start = 0, \
.rev_end = -1ull, \
.cis_vendor = SDIO_ANY_ID, \
.cis_device = SDIO_ANY_ID, \
.vendor_fixup = (_fixup), \
.data = (_data), \
.ext_csd_rev = EXT_CSD_REV_ANY, \
.of_compatible = _compatible, \
}
#define cid_rev(hwrev, fwrev, year, month) \ #define cid_rev(hwrev, fwrev, year, month) \
(((u64) hwrev) << 40 | \ (((u64) hwrev) << 40 | \
((u64) fwrev) << 32 | \ ((u64) fwrev) << 32 | \
...@@ -150,6 +168,24 @@ static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card, ...@@ -150,6 +168,24 @@ static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card,
card->quirk_max_rate = data; card->quirk_max_rate = data;
} }
static inline void __maybe_unused wl1251_quirk(struct mmc_card *card,
int data)
{
/*
* We have TI wl1251 attached to this mmc. Pass this
* information to the SDIO core because it can't be
* probed by normal methods.
*/
dev_info(card->host->parent, "found wl1251\n");
card->quirks |= MMC_QUIRK_NONSTD_SDIO;
card->cccr.wide_bus = 1;
card->cis.vendor = 0x104c;
card->cis.device = 0x9066;
card->cis.blksize = 512;
card->cis.max_dtr = 24000000;
}
/* /*
* Quirk add/remove for MMC products. * Quirk add/remove for MMC products.
*/ */
......
...@@ -1962,7 +1962,7 @@ static int mmc_sleep(struct mmc_host *host) ...@@ -1962,7 +1962,7 @@ static int mmc_sleep(struct mmc_host *host)
goto out_release; goto out_release;
} }
err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host); err = __mmc_poll_for_busy(host, timeout_ms, &mmc_sleep_busy_cb, host);
out_release: out_release:
mmc_retune_release(host); mmc_retune_release(host);
......
...@@ -58,6 +58,12 @@ struct mmc_busy_data { ...@@ -58,6 +58,12 @@ struct mmc_busy_data {
enum mmc_busy_cmd busy_cmd; enum mmc_busy_cmd busy_cmd;
}; };
struct mmc_op_cond_busy_data {
struct mmc_host *host;
u32 ocr;
struct mmc_command *cmd;
};
int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries) int __mmc_send_status(struct mmc_card *card, u32 *status, unsigned int retries)
{ {
int err; int err;
...@@ -173,43 +179,62 @@ int mmc_go_idle(struct mmc_host *host) ...@@ -173,43 +179,62 @@ int mmc_go_idle(struct mmc_host *host)
return err; return err;
} }
static int __mmc_send_op_cond_cb(void *cb_data, bool *busy)
{
struct mmc_op_cond_busy_data *data = cb_data;
struct mmc_host *host = data->host;
struct mmc_command *cmd = data->cmd;
u32 ocr = data->ocr;
int err = 0;
err = mmc_wait_for_cmd(host, cmd, 0);
if (err)
return err;
if (mmc_host_is_spi(host)) {
if (!(cmd->resp[0] & R1_SPI_IDLE)) {
*busy = false;
return 0;
}
} else {
if (cmd->resp[0] & MMC_CARD_BUSY) {
*busy = false;
return 0;
}
}
*busy = true;
/*
* According to eMMC specification v5.1 section 6.4.3, we
* should issue CMD1 repeatedly in the idle state until
* the eMMC is ready. Otherwise some eMMC devices seem to enter
* the inactive mode after mmc_init_card() issued CMD0 when
* the eMMC device is busy.
*/
if (!ocr && !mmc_host_is_spi(host))
cmd->arg = cmd->resp[0] | BIT(30);
return 0;
}
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{ {
struct mmc_command cmd = {}; struct mmc_command cmd = {};
int i, err = 0; int err = 0;
struct mmc_op_cond_busy_data cb_data = {
.host = host,
.ocr = ocr,
.cmd = &cmd
};
cmd.opcode = MMC_SEND_OP_COND; cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr; cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) { err = __mmc_poll_for_busy(host, 1000, &__mmc_send_op_cond_cb, &cb_data);
err = mmc_wait_for_cmd(host, &cmd, 0); if (err)
if (err) return err;
break;
/* wait until reset completes */
if (mmc_host_is_spi(host)) {
if (!(cmd.resp[0] & R1_SPI_IDLE))
break;
} else {
if (cmd.resp[0] & MMC_CARD_BUSY)
break;
}
err = -ETIMEDOUT;
mmc_delay(10);
/*
* According to eMMC specification v5.1 section 6.4.3, we
* should issue CMD1 repeatedly in the idle state until
* the eMMC is ready. Otherwise some eMMC devices seem to enter
* the inactive mode after mmc_init_card() issued CMD0 when
* the eMMC device is busy.
*/
if (!ocr && !mmc_host_is_spi(host))
cmd.arg = cmd.resp[0] | BIT(30);
}
if (rocr && !mmc_host_is_spi(host)) if (rocr && !mmc_host_is_spi(host))
*rocr = cmd.resp[0]; *rocr = cmd.resp[0];
...@@ -470,11 +495,10 @@ static int mmc_busy_cb(void *cb_data, bool *busy) ...@@ -470,11 +495,10 @@ static int mmc_busy_cb(void *cb_data, bool *busy)
return 0; return 0;
} }
int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, int __mmc_poll_for_busy(struct mmc_host *host, unsigned int timeout_ms,
int (*busy_cb)(void *cb_data, bool *busy), int (*busy_cb)(void *cb_data, bool *busy),
void *cb_data) void *cb_data)
{ {
struct mmc_host *host = card->host;
int err; int err;
unsigned long timeout; unsigned long timeout;
unsigned int udelay = 32, udelay_max = 32768; unsigned int udelay = 32, udelay_max = 32768;
...@@ -515,13 +539,14 @@ EXPORT_SYMBOL_GPL(__mmc_poll_for_busy); ...@@ -515,13 +539,14 @@ EXPORT_SYMBOL_GPL(__mmc_poll_for_busy);
int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
bool retry_crc_err, enum mmc_busy_cmd busy_cmd) bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
{ {
struct mmc_host *host = card->host;
struct mmc_busy_data cb_data; struct mmc_busy_data cb_data;
cb_data.card = card; cb_data.card = card;
cb_data.retry_crc_err = retry_crc_err; cb_data.retry_crc_err = retry_crc_err;
cb_data.busy_cmd = busy_cmd; cb_data.busy_cmd = busy_cmd;
return __mmc_poll_for_busy(card, timeout_ms, &mmc_busy_cb, &cb_data); return __mmc_poll_for_busy(host, timeout_ms, &mmc_busy_cb, &cb_data);
} }
EXPORT_SYMBOL_GPL(mmc_poll_for_busy); EXPORT_SYMBOL_GPL(mmc_poll_for_busy);
......
...@@ -41,7 +41,7 @@ int mmc_can_ext_csd(struct mmc_card *card); ...@@ -41,7 +41,7 @@ int mmc_can_ext_csd(struct mmc_card *card);
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);
int __mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, int __mmc_poll_for_busy(struct mmc_host *host, unsigned int timeout_ms,
int (*busy_cb)(void *cb_data, bool *busy), int (*busy_cb)(void *cb_data, bool *busy),
void *cb_data); void *cb_data);
int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
......
...@@ -54,7 +54,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, ...@@ -54,7 +54,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc,
reset_gpios->info, values); reset_gpios->info, values);
kfree(values); bitmap_free(values);
} }
} }
......
...@@ -234,7 +234,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx, ...@@ -234,7 +234,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
enum mmc_issue_type issue_type; enum mmc_issue_type issue_type;
enum mmc_issued issued; enum mmc_issued issued;
bool get_card, cqe_retune_ok; bool get_card, cqe_retune_ok;
int ret; blk_status_t ret;
if (mmc_card_removed(mq->card)) { if (mmc_card_removed(mq->card)) {
req->rq_flags |= RQF_QUIET; req->rq_flags |= RQF_QUIET;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* *
*/ */
#include <linux/of.h>
#include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_ids.h>
#include "card.h" #include "card.h"
...@@ -145,6 +146,25 @@ static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = { ...@@ -145,6 +146,25 @@ static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = {
END_FIXUP END_FIXUP
}; };
static const struct mmc_fixup __maybe_unused sdio_card_init_methods[] = {
SDIO_FIXUP_COMPATIBLE("ti,wl1251", wl1251_quirk, 0),
END_FIXUP
};
static inline bool mmc_fixup_of_compatible_match(struct mmc_card *card,
const char *compatible)
{
struct device_node *np;
for_each_child_of_node(mmc_dev(card->host)->of_node, np) {
if (of_device_is_compatible(np, compatible))
return true;
}
return false;
}
static inline void mmc_fixup_device(struct mmc_card *card, static inline void mmc_fixup_device(struct mmc_card *card,
const struct mmc_fixup *table) const struct mmc_fixup *table)
{ {
...@@ -152,22 +172,32 @@ static inline void mmc_fixup_device(struct mmc_card *card, ...@@ -152,22 +172,32 @@ static inline void mmc_fixup_device(struct mmc_card *card,
u64 rev = cid_rev_card(card); u64 rev = cid_rev_card(card);
for (f = table; f->vendor_fixup; f++) { for (f = table; f->vendor_fixup; f++) {
if ((f->manfid == CID_MANFID_ANY || if (f->manfid != CID_MANFID_ANY &&
f->manfid == card->cid.manfid) && f->manfid != card->cid.manfid)
(f->oemid == CID_OEMID_ANY || continue;
f->oemid == card->cid.oemid) && if (f->oemid != CID_OEMID_ANY &&
(f->name == CID_NAME_ANY || f->oemid != card->cid.oemid)
!strncmp(f->name, card->cid.prod_name, continue;
sizeof(card->cid.prod_name))) && if (f->name != CID_NAME_ANY &&
(f->cis_vendor == card->cis.vendor || strncmp(f->name, card->cid.prod_name,
f->cis_vendor == (u16) SDIO_ANY_ID) && sizeof(card->cid.prod_name)))
(f->cis_device == card->cis.device || continue;
f->cis_device == (u16) SDIO_ANY_ID) && if (f->cis_vendor != (u16)SDIO_ANY_ID &&
(f->ext_csd_rev == EXT_CSD_REV_ANY || f->cis_vendor != card->cis.vendor)
f->ext_csd_rev == card->ext_csd.rev) && continue;
rev >= f->rev_start && rev <= f->rev_end) { if (f->cis_device != (u16)SDIO_ANY_ID &&
dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup); f->cis_device != card->cis.device)
f->vendor_fixup(card, f->data); continue;
} if (f->ext_csd_rev != EXT_CSD_REV_ANY &&
f->ext_csd_rev != card->ext_csd.rev)
continue;
if (rev < f->rev_start || rev > f->rev_end)
continue;
if (f->of_compatible &&
!mmc_fixup_of_compatible_match(card, f->of_compatible))
continue;
dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup);
f->vendor_fixup(card, f->data);
} }
} }
...@@ -1666,7 +1666,7 @@ static int sd_poweroff_notify(struct mmc_card *card) ...@@ -1666,7 +1666,7 @@ static int sd_poweroff_notify(struct mmc_card *card)
cb_data.card = card; cb_data.card = card;
cb_data.reg_buf = reg_buf; cb_data.reg_buf = reg_buf;
err = __mmc_poll_for_busy(card, SD_POWEROFF_NOTIFY_TIMEOUT_MS, err = __mmc_poll_for_busy(card->host, SD_POWEROFF_NOTIFY_TIMEOUT_MS,
&sd_busy_poweroff_notify_cb, &cb_data); &sd_busy_poweroff_notify_cb, &cb_data);
out: out:
......
...@@ -707,6 +707,9 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -707,6 +707,9 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
*/ */
if (host->ops->init_card) if (host->ops->init_card)
host->ops->init_card(host, card); host->ops->init_card(host, card);
mmc_fixup_device(card, sdio_card_init_methods);
card->ocr = ocr_card;
/* /*
* If the host and card support UHS-I mode request the card * If the host and card support UHS-I mode request the card
...@@ -820,7 +823,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -820,7 +823,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
goto mismatch; goto mismatch;
} }
} }
card->ocr = ocr_card;
mmc_fixup_device(card, sdio_fixup_methods); mmc_fixup_device(card, sdio_fixup_methods);
if (card->type == MMC_TYPE_SD_COMBO) { if (card->type == MMC_TYPE_SD_COMBO) {
......
...@@ -969,8 +969,10 @@ static int au1xmmc_probe(struct platform_device *pdev) ...@@ -969,8 +969,10 @@ static int au1xmmc_probe(struct platform_device *pdev)
} }
host->irq = platform_get_irq(pdev, 0); host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0) if (host->irq < 0) {
ret = host->irq;
goto out3; goto out3;
}
mmc->ops = &au1xmmc_ops; mmc->ops = &au1xmmc_ops;
......
...@@ -28,6 +28,7 @@ enum dw_mci_exynos_type { ...@@ -28,6 +28,7 @@ enum dw_mci_exynos_type {
DW_MCI_TYPE_EXYNOS5420_SMU, DW_MCI_TYPE_EXYNOS5420_SMU,
DW_MCI_TYPE_EXYNOS7, DW_MCI_TYPE_EXYNOS7,
DW_MCI_TYPE_EXYNOS7_SMU, DW_MCI_TYPE_EXYNOS7_SMU,
DW_MCI_TYPE_ARTPEC8,
}; };
/* Exynos implementation specific driver private data */ /* Exynos implementation specific driver private data */
...@@ -69,6 +70,9 @@ static struct dw_mci_exynos_compatible { ...@@ -69,6 +70,9 @@ static struct dw_mci_exynos_compatible {
}, { }, {
.compatible = "samsung,exynos7-dw-mshc-smu", .compatible = "samsung,exynos7-dw-mshc-smu",
.ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU, .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU,
}, {
.compatible = "axis,artpec8-dw-mshc",
.ctrl_type = DW_MCI_TYPE_ARTPEC8,
}, },
}; };
...@@ -81,7 +85,8 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) ...@@ -81,7 +85,8 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
return EXYNOS4210_FIXED_CIU_CLK_DIV; return EXYNOS4210_FIXED_CIU_CLK_DIV;
else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1; return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
else else
return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1; return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
...@@ -122,6 +127,11 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) ...@@ -122,6 +127,11 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
} }
if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) {
/* Quirk needed for the ARTPEC-8 SoC */
host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT;
}
host->bus_hz /= (priv->ciu_div + 1); host->bus_hz /= (priv->ciu_div + 1);
return 0; return 0;
...@@ -133,7 +143,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) ...@@ -133,7 +143,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
u32 clksel; u32 clksel;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
clksel = mci_readl(host, CLKSEL64); clksel = mci_readl(host, CLKSEL64);
else else
clksel = mci_readl(host, CLKSEL); clksel = mci_readl(host, CLKSEL);
...@@ -141,7 +152,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) ...@@ -141,7 +152,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing; clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
mci_writel(host, CLKSEL64, clksel); mci_writel(host, CLKSEL64, clksel);
else else
mci_writel(host, CLKSEL, clksel); mci_writel(host, CLKSEL, clksel);
...@@ -210,14 +222,16 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) ...@@ -210,14 +222,16 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
return ret; return ret;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
clksel = mci_readl(host, CLKSEL64); clksel = mci_readl(host, CLKSEL64);
else else
clksel = mci_readl(host, CLKSEL); clksel = mci_readl(host, CLKSEL);
if (clksel & SDMMC_CLKSEL_WAKEUP_INT) { if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
mci_writel(host, CLKSEL64, clksel); mci_writel(host, CLKSEL64, clksel);
else else
mci_writel(host, CLKSEL, clksel); mci_writel(host, CLKSEL, clksel);
...@@ -238,7 +252,8 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) ...@@ -238,7 +252,8 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
* Not supported to configure register * Not supported to configure register
* related to HS400 * related to HS400
*/ */
if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) { if ((priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) ||
(priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)) {
if (timing == MMC_TIMING_MMC_HS400) if (timing == MMC_TIMING_MMC_HS400)
dev_warn(host->dev, dev_warn(host->dev,
"cannot configure HS400, unsupported chipset\n"); "cannot configure HS400, unsupported chipset\n");
...@@ -394,7 +409,8 @@ static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host) ...@@ -394,7 +409,8 @@ static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64)); return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64));
else else
return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL)); return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
...@@ -406,13 +422,15 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) ...@@ -406,13 +422,15 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
clksel = mci_readl(host, CLKSEL64); clksel = mci_readl(host, CLKSEL64);
else else
clksel = mci_readl(host, CLKSEL); clksel = mci_readl(host, CLKSEL);
clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
mci_writel(host, CLKSEL64, clksel); mci_writel(host, CLKSEL64, clksel);
else else
mci_writel(host, CLKSEL, clksel); mci_writel(host, CLKSEL, clksel);
...@@ -425,7 +443,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) ...@@ -425,7 +443,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
u8 sample; u8 sample;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
clksel = mci_readl(host, CLKSEL64); clksel = mci_readl(host, CLKSEL64);
else else
clksel = mci_readl(host, CLKSEL); clksel = mci_readl(host, CLKSEL);
...@@ -434,7 +453,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) ...@@ -434,7 +453,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
mci_writel(host, CLKSEL64, clksel); mci_writel(host, CLKSEL64, clksel);
else else
mci_writel(host, CLKSEL, clksel); mci_writel(host, CLKSEL, clksel);
...@@ -524,17 +544,65 @@ static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host, ...@@ -524,17 +544,65 @@ static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
return 0; return 0;
} }
static void dw_mci_exynos_set_data_timeout(struct dw_mci *host,
unsigned int timeout_ns)
{
u32 clk_div, tmout;
u64 tmp;
unsigned int tmp2;
clk_div = (mci_readl(host, CLKDIV) & 0xFF) * 2;
if (clk_div == 0)
clk_div = 1;
tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC);
tmp = DIV_ROUND_UP_ULL(tmp, clk_div);
/* TMOUT[7:0] (RESPONSE_TIMEOUT) */
tmout = 0xFF; /* Set maximum */
/*
* Extended HW timer (max = 0x6FFFFF2):
* ((TMOUT[10:8] - 1) * 0xFFFFFF + TMOUT[31:11] * 8)
*/
if (!tmp || tmp > 0x6FFFFF2)
tmout |= (0xFFFFFF << 8);
else {
/* TMOUT[10:8] */
tmp2 = (((unsigned int)tmp / 0xFFFFFF) + 1) & 0x7;
tmout |= tmp2 << 8;
/* TMOUT[31:11] */
tmp = tmp - ((tmp2 - 1) * 0xFFFFFF);
tmout |= (tmp & 0xFFFFF8) << 8;
}
mci_writel(host, TMOUT, tmout);
dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: %#08x",
timeout_ns, tmout >> 8);
}
static u32 dw_mci_exynos_get_drto_clks(struct dw_mci *host)
{
u32 drto_clks;
drto_clks = mci_readl(host, TMOUT) >> 8;
return (((drto_clks & 0x7) - 1) * 0xFFFFFF) + ((drto_clks & 0xFFFFF8));
}
/* Common capabilities of Exynos4/Exynos5 SoC */ /* Common capabilities of Exynos4/Exynos5 SoC */
static unsigned long exynos_dwmmc_caps[4] = { static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA,
MMC_CAP_CMD23, 0,
MMC_CAP_CMD23, 0,
MMC_CAP_CMD23, 0,
}; };
static const struct dw_mci_drv_data exynos_drv_data = { static const struct dw_mci_drv_data exynos_drv_data = {
.caps = exynos_dwmmc_caps, .caps = exynos_dwmmc_caps,
.num_caps = ARRAY_SIZE(exynos_dwmmc_caps), .num_caps = ARRAY_SIZE(exynos_dwmmc_caps),
.common_caps = MMC_CAP_CMD23,
.init = dw_mci_exynos_priv_init, .init = dw_mci_exynos_priv_init,
.set_ios = dw_mci_exynos_set_ios, .set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt, .parse_dt = dw_mci_exynos_parse_dt,
...@@ -542,6 +610,16 @@ static const struct dw_mci_drv_data exynos_drv_data = { ...@@ -542,6 +610,16 @@ static const struct dw_mci_drv_data exynos_drv_data = {
.prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning, .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
}; };
static const struct dw_mci_drv_data artpec_drv_data = {
.common_caps = MMC_CAP_CMD23,
.init = dw_mci_exynos_priv_init,
.set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt,
.execute_tuning = dw_mci_exynos_execute_tuning,
.set_data_timeout = dw_mci_exynos_set_data_timeout,
.get_drto_clks = dw_mci_exynos_get_drto_clks,
};
static const struct of_device_id dw_mci_exynos_match[] = { static const struct of_device_id dw_mci_exynos_match[] = {
{ .compatible = "samsung,exynos4412-dw-mshc", { .compatible = "samsung,exynos4412-dw-mshc",
.data = &exynos_drv_data, }, .data = &exynos_drv_data, },
...@@ -555,6 +633,8 @@ static const struct of_device_id dw_mci_exynos_match[] = { ...@@ -555,6 +633,8 @@ static const struct of_device_id dw_mci_exynos_match[] = {
.data = &exynos_drv_data, }, .data = &exynos_drv_data, },
{ .compatible = "samsung,exynos7-dw-mshc-smu", { .compatible = "samsung,exynos7-dw-mshc-smu",
.data = &exynos_drv_data, }, .data = &exynos_drv_data, },
{ .compatible = "axis,artpec8-dw-mshc",
.data = &artpec_drv_data, },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
......
...@@ -23,12 +23,6 @@ struct hi3798cv200_priv { ...@@ -23,12 +23,6 @@ struct hi3798cv200_priv {
struct clk *drive_clk; struct clk *drive_clk;
}; };
static unsigned long dw_mci_hi3798cv200_caps[] = {
MMC_CAP_CMD23,
MMC_CAP_CMD23,
MMC_CAP_CMD23
};
static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios) static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{ {
struct hi3798cv200_priv *priv = host->priv; struct hi3798cv200_priv *priv = host->priv;
...@@ -166,8 +160,7 @@ static int dw_mci_hi3798cv200_init(struct dw_mci *host) ...@@ -166,8 +160,7 @@ static int dw_mci_hi3798cv200_init(struct dw_mci *host)
} }
static const struct dw_mci_drv_data hi3798cv200_data = { static const struct dw_mci_drv_data hi3798cv200_data = {
.caps = dw_mci_hi3798cv200_caps, .common_caps = MMC_CAP_CMD23,
.num_caps = ARRAY_SIZE(dw_mci_hi3798cv200_caps),
.init = dw_mci_hi3798cv200_init, .init = dw_mci_hi3798cv200_init,
.set_ios = dw_mci_hi3798cv200_set_ios, .set_ios = dw_mci_hi3798cv200_set_ios,
.execute_tuning = dw_mci_hi3798cv200_execute_tuning, .execute_tuning = dw_mci_hi3798cv200_execute_tuning,
......
...@@ -300,21 +300,12 @@ static int dw_mci_rockchip_init(struct dw_mci *host) ...@@ -300,21 +300,12 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
return 0; return 0;
} }
/* Common capabilities of RK3288 SoC */
static unsigned long dw_mci_rk3288_dwmmc_caps[4] = {
MMC_CAP_CMD23,
MMC_CAP_CMD23,
MMC_CAP_CMD23,
MMC_CAP_CMD23,
};
static const struct dw_mci_drv_data rk2928_drv_data = { static const struct dw_mci_drv_data rk2928_drv_data = {
.init = dw_mci_rockchip_init, .init = dw_mci_rockchip_init,
}; };
static const struct dw_mci_drv_data rk3288_drv_data = { static const struct dw_mci_drv_data rk3288_drv_data = {
.caps = dw_mci_rk3288_dwmmc_caps, .common_caps = MMC_CAP_CMD23,
.num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps),
.set_ios = dw_mci_rk3288_set_ios, .set_ios = dw_mci_rk3288_set_ios,
.execute_tuning = dw_mci_rk3288_execute_tuning, .execute_tuning = dw_mci_rk3288_execute_tuning,
.parse_dt = dw_mci_rk3288_parse_dt, .parse_dt = dw_mci_rk3288_parse_dt,
......
...@@ -335,7 +335,8 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) ...@@ -335,7 +335,8 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
cmdr == MMC_WRITE_BLOCK || cmdr == MMC_WRITE_BLOCK ||
cmdr == MMC_WRITE_MULTIPLE_BLOCK || cmdr == MMC_WRITE_MULTIPLE_BLOCK ||
cmdr == MMC_SEND_TUNING_BLOCK || cmdr == MMC_SEND_TUNING_BLOCK ||
cmdr == MMC_SEND_TUNING_BLOCK_HS200) { cmdr == MMC_SEND_TUNING_BLOCK_HS200 ||
cmdr == MMC_GEN_CMD) {
stop->opcode = MMC_STOP_TRANSMISSION; stop->opcode = MMC_STOP_TRANSMISSION;
stop->arg = 0; stop->arg = 0;
stop->flags = MMC_RSP_R1B | MMC_CMD_AC; stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
...@@ -1283,6 +1284,37 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) ...@@ -1283,6 +1284,37 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
mci_writel(host, CTYPE, (slot->ctype << slot->id)); mci_writel(host, CTYPE, (slot->ctype << slot->id));
} }
static void dw_mci_set_data_timeout(struct dw_mci *host,
unsigned int timeout_ns)
{
const struct dw_mci_drv_data *drv_data = host->drv_data;
u32 clk_div, tmout;
u64 tmp;
if (drv_data && drv_data->set_data_timeout)
return drv_data->set_data_timeout(host, timeout_ns);
clk_div = (mci_readl(host, CLKDIV) & 0xFF) * 2;
if (clk_div == 0)
clk_div = 1;
tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC);
tmp = DIV_ROUND_UP_ULL(tmp, clk_div);
/* TMOUT[7:0] (RESPONSE_TIMEOUT) */
tmout = 0xFF; /* Set maximum */
/* TMOUT[31:8] (DATA_TIMEOUT) */
if (!tmp || tmp > 0xFFFFFF)
tmout |= (0xFFFFFF << 8);
else
tmout |= (tmp & 0xFFFFFF) << 8;
mci_writel(host, TMOUT, tmout);
dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: %#08x",
timeout_ns, tmout >> 8);
}
static void __dw_mci_start_request(struct dw_mci *host, static void __dw_mci_start_request(struct dw_mci *host,
struct dw_mci_slot *slot, struct dw_mci_slot *slot,
struct mmc_command *cmd) struct mmc_command *cmd)
...@@ -1303,7 +1335,7 @@ static void __dw_mci_start_request(struct dw_mci *host, ...@@ -1303,7 +1335,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
data = cmd->data; data = cmd->data;
if (data) { if (data) {
mci_writel(host, TMOUT, 0xFFFFFFFF); dw_mci_set_data_timeout(host, data->timeout_ns);
mci_writel(host, BYTCNT, data->blksz*data->blocks); mci_writel(host, BYTCNT, data->blksz*data->blocks);
mci_writel(host, BLKSIZ, data->blksz); mci_writel(host, BLKSIZ, data->blksz);
} }
...@@ -1967,12 +1999,16 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data) ...@@ -1967,12 +1999,16 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
static void dw_mci_set_drto(struct dw_mci *host) static void dw_mci_set_drto(struct dw_mci *host)
{ {
const struct dw_mci_drv_data *drv_data = host->drv_data;
unsigned int drto_clks; unsigned int drto_clks;
unsigned int drto_div; unsigned int drto_div;
unsigned int drto_ms; unsigned int drto_ms;
unsigned long irqflags; unsigned long irqflags;
drto_clks = mci_readl(host, TMOUT) >> 8; if (drv_data && drv_data->get_drto_clks)
drto_clks = drv_data->get_drto_clks(host);
else
drto_clks = mci_readl(host, TMOUT) >> 8;
drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2; drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
if (drto_div == 0) if (drto_div == 0)
drto_div = 1; drto_div = 1;
...@@ -1980,6 +2016,8 @@ static void dw_mci_set_drto(struct dw_mci *host) ...@@ -1980,6 +2016,8 @@ static void dw_mci_set_drto(struct dw_mci *host)
drto_ms = DIV_ROUND_UP_ULL((u64)MSEC_PER_SEC * drto_clks * drto_div, drto_ms = DIV_ROUND_UP_ULL((u64)MSEC_PER_SEC * drto_clks * drto_div,
host->bus_hz); host->bus_hz);
dev_dbg(host->dev, "drto_ms: %u\n", drto_ms);
/* add a bit spare time */ /* add a bit spare time */
drto_ms += 10; drto_ms += 10;
...@@ -2724,11 +2762,20 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) ...@@ -2724,11 +2762,20 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
if (pending & DW_MCI_DATA_ERROR_FLAGS) { if (pending & DW_MCI_DATA_ERROR_FLAGS) {
spin_lock(&host->irq_lock); spin_lock(&host->irq_lock);
if (host->quirks & DW_MMC_QUIRK_EXTENDED_TMOUT)
del_timer(&host->dto_timer);
/* if there is an error report DATA_ERROR */ /* if there is an error report DATA_ERROR */
mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
host->data_status = pending; host->data_status = pending;
smp_wmb(); /* drain writebuffer */ smp_wmb(); /* drain writebuffer */
set_bit(EVENT_DATA_ERROR, &host->pending_events); set_bit(EVENT_DATA_ERROR, &host->pending_events);
if (host->quirks & DW_MMC_QUIRK_EXTENDED_TMOUT)
/* In case of error, we cannot expect a DTO */
set_bit(EVENT_DATA_COMPLETE,
&host->pending_events);
tasklet_schedule(&host->tasklet); tasklet_schedule(&host->tasklet);
spin_unlock(&host->irq_lock); spin_unlock(&host->irq_lock);
...@@ -2828,6 +2875,9 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot) ...@@ -2828,6 +2875,9 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot)
if (host->pdata->pm_caps) if (host->pdata->pm_caps)
mmc->pm_caps = host->pdata->pm_caps; mmc->pm_caps = host->pdata->pm_caps;
if (drv_data)
mmc->caps |= drv_data->common_caps;
if (host->dev->of_node) { if (host->dev->of_node) {
ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
if (ctrl_id < 0) if (ctrl_id < 0)
......
...@@ -118,6 +118,7 @@ struct dw_mci_dma_slave { ...@@ -118,6 +118,7 @@ struct dw_mci_dma_slave {
* @part_buf: Simple buffer for partial fifo reads/writes. * @part_buf: Simple buffer for partial fifo reads/writes.
* @push_data: Pointer to FIFO push function. * @push_data: Pointer to FIFO push function.
* @pull_data: Pointer to FIFO pull function. * @pull_data: Pointer to FIFO pull function.
* @quirks: Set of quirks that apply to specific versions of the IP.
* @vqmmc_enabled: Status of vqmmc, should be true or false. * @vqmmc_enabled: Status of vqmmc, should be true or false.
* @irq_flags: The flags to be passed to request_irq. * @irq_flags: The flags to be passed to request_irq.
* @irq: The irq value to be passed to request_irq. * @irq: The irq value to be passed to request_irq.
...@@ -223,6 +224,7 @@ struct dw_mci { ...@@ -223,6 +224,7 @@ struct dw_mci {
void (*push_data)(struct dw_mci *host, void *buf, int cnt); void (*push_data)(struct dw_mci *host, void *buf, int cnt);
void (*pull_data)(struct dw_mci *host, void *buf, int cnt); void (*pull_data)(struct dw_mci *host, void *buf, int cnt);
u32 quirks;
bool vqmmc_enabled; bool vqmmc_enabled;
unsigned long irq_flags; /* IRQ flags */ unsigned long irq_flags; /* IRQ flags */
int irq; int irq;
...@@ -274,6 +276,9 @@ struct dw_mci_board { ...@@ -274,6 +276,9 @@ struct dw_mci_board {
struct dma_pdata *data; struct dma_pdata *data;
}; };
/* Support for longer data read timeout */
#define DW_MMC_QUIRK_EXTENDED_TMOUT BIT(0)
#define DW_MMC_240A 0x240a #define DW_MMC_240A 0x240a
#define DW_MMC_280A 0x280a #define DW_MMC_280A 0x280a
...@@ -550,10 +555,14 @@ struct dw_mci_slot { ...@@ -550,10 +555,14 @@ struct dw_mci_slot {
* dw_mci driver data - dw-mshc implementation specific driver data. * dw_mci driver data - dw-mshc implementation specific driver data.
* @caps: mmc subsystem specified capabilities of the controller(s). * @caps: mmc subsystem specified capabilities of the controller(s).
* @num_caps: number of capabilities specified by @caps. * @num_caps: number of capabilities specified by @caps.
* @common_caps: mmc subsystem specified capabilities applicable to all of
* the controllers
* @init: early implementation specific initialization. * @init: early implementation specific initialization.
* @set_ios: handle bus specific extensions. * @set_ios: handle bus specific extensions.
* @parse_dt: parse implementation specific device tree properties. * @parse_dt: parse implementation specific device tree properties.
* @execute_tuning: implementation specific tuning procedure. * @execute_tuning: implementation specific tuning procedure.
* @set_data_timeout: implementation specific timeout.
* @get_drto_clks: implementation specific cycle count for data read timeout.
* *
* Provide controller implementation specific extensions. The usage of this * Provide controller implementation specific extensions. The usage of this
* data structure is fully optional and usage of each member in this structure * data structure is fully optional and usage of each member in this structure
...@@ -562,6 +571,7 @@ struct dw_mci_slot { ...@@ -562,6 +571,7 @@ struct dw_mci_slot {
struct dw_mci_drv_data { struct dw_mci_drv_data {
unsigned long *caps; unsigned long *caps;
u32 num_caps; u32 num_caps;
u32 common_caps;
int (*init)(struct dw_mci *host); int (*init)(struct dw_mci *host);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host); int (*parse_dt)(struct dw_mci *host);
...@@ -570,5 +580,8 @@ struct dw_mci_drv_data { ...@@ -570,5 +580,8 @@ struct dw_mci_drv_data {
struct mmc_ios *ios); struct mmc_ios *ios);
int (*switch_voltage)(struct mmc_host *mmc, int (*switch_voltage)(struct mmc_host *mmc,
struct mmc_ios *ios); struct mmc_ios *ios);
void (*set_data_timeout)(struct dw_mci *host,
unsigned int timeout_ns);
u32 (*get_drto_clks)(struct dw_mci *host);
}; };
#endif /* _DW_MMC_H_ */ #endif /* _DW_MMC_H_ */
...@@ -217,11 +217,23 @@ static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host) ...@@ -217,11 +217,23 @@ static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host)
return; return;
dma_release_channel(host->dma_tx); dma_release_channel(host->dma_tx);
dma_release_channel(host->dma_rx); if (host->dma_rx)
dma_release_channel(host->dma_rx);
} }
static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host) static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
{ {
struct device *dev = mmc_dev(host->mmc);
host->dma_tx = dma_request_chan(dev, "tx-rx");
if (!IS_ERR(host->dma_tx))
return 0;
if (PTR_ERR(host->dma_tx) != -ENODEV) {
dev_err(dev, "Failed to get dma tx-rx channel\n");
return PTR_ERR(host->dma_tx);
}
host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx"); host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx");
if (IS_ERR(host->dma_tx)) { if (IS_ERR(host->dma_tx)) {
dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n"); dev_err(mmc_dev(host->mmc), "Failed to get dma_tx channel\n");
...@@ -241,7 +253,10 @@ static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host) ...@@ -241,7 +253,10 @@ static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host, static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host,
struct mmc_data *data) struct mmc_data *data)
{ {
return (data->flags & MMC_DATA_READ) ? host->dma_rx : host->dma_tx; if ((data->flags & MMC_DATA_READ) && host->dma_rx)
return host->dma_rx;
else
return host->dma_tx;
} }
static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host, static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#include "meson-mx-sdhc.h" #include "meson-mx-sdhc.h"
#define MESON_SDHC_NUM_BUILTIN_CLKS 6
struct meson_mx_sdhc_clkc { struct meson_mx_sdhc_clkc {
struct clk_mux src_sel; struct clk_mux src_sel;
struct clk_divider div; struct clk_divider div;
......
...@@ -854,6 +854,11 @@ static int meson_mx_sdhc_probe(struct platform_device *pdev) ...@@ -854,6 +854,11 @@ static int meson_mx_sdhc_probe(struct platform_device *pdev)
goto err_disable_pclk; goto err_disable_pclk;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
goto err_disable_pclk;
}
ret = devm_request_threaded_irq(dev, irq, meson_mx_sdhc_irq, ret = devm_request_threaded_irq(dev, irq, meson_mx_sdhc_irq,
meson_mx_sdhc_irq_thread, IRQF_ONESHOT, meson_mx_sdhc_irq_thread, IRQF_ONESHOT,
NULL, host); NULL, host);
......
...@@ -662,6 +662,11 @@ static int meson_mx_mmc_probe(struct platform_device *pdev) ...@@ -662,6 +662,11 @@ static int meson_mx_mmc_probe(struct platform_device *pdev)
} }
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
goto error_free_mmc;
}
ret = devm_request_threaded_irq(host->controller_dev, irq, ret = devm_request_threaded_irq(host->controller_dev, irq,
meson_mx_mmc_irq, meson_mx_mmc_irq,
meson_mx_mmc_irq_thread, IRQF_ONESHOT, meson_mx_mmc_irq_thread, IRQF_ONESHOT,
......
...@@ -547,7 +547,7 @@ mmc_spi_command_send(struct mmc_spi_host *host, ...@@ -547,7 +547,7 @@ mmc_spi_command_send(struct mmc_spi_host *host,
static void static void
mmc_spi_setup_data_message( mmc_spi_setup_data_message(
struct mmc_spi_host *host, struct mmc_spi_host *host,
int multiple, bool multiple,
enum dma_data_direction direction) enum dma_data_direction direction)
{ {
struct spi_transfer *t; struct spi_transfer *t;
...@@ -859,14 +859,14 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, ...@@ -859,14 +859,14 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
struct spi_device *spi = host->spi; struct spi_device *spi = host->spi;
struct device *dma_dev = host->dma_dev; struct device *dma_dev = host->dma_dev;
struct spi_transfer *t; struct spi_transfer *t;
enum dma_data_direction direction; enum dma_data_direction direction = mmc_get_dma_dir(data);
struct scatterlist *sg; struct scatterlist *sg;
unsigned n_sg; unsigned n_sg;
int multiple = (data->blocks > 1); bool multiple = (data->blocks > 1);
const char *write_or_read = (direction == DMA_TO_DEVICE) ? "write" : "read";
u32 clock_rate; u32 clock_rate;
unsigned long timeout; unsigned long timeout;
direction = mmc_get_dma_dir(data);
mmc_spi_setup_data_message(host, multiple, direction); mmc_spi_setup_data_message(host, multiple, direction);
t = &host->t; t = &host->t;
...@@ -921,9 +921,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, ...@@ -921,9 +921,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
while (length) { while (length) {
t->len = min(length, blk_size); t->len = min(length, blk_size);
dev_dbg(&host->spi->dev, " %s block, %d bytes\n", dev_dbg(&spi->dev, " %s block, %d bytes\n", write_or_read, t->len);
(direction == DMA_TO_DEVICE) ? "write" : "read",
t->len);
if (direction == DMA_TO_DEVICE) if (direction == DMA_TO_DEVICE)
status = mmc_spi_writeblock(host, t, timeout); status = mmc_spi_writeblock(host, t, timeout);
...@@ -948,9 +946,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, ...@@ -948,9 +946,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
if (status < 0) { if (status < 0) {
data->error = status; data->error = status;
dev_dbg(&spi->dev, "%s status %d\n", dev_dbg(&spi->dev, "%s status %d\n", write_or_read, status);
(direction == DMA_TO_DEVICE) ? "write" : "read",
status);
break; break;
} }
} }
......
...@@ -280,7 +280,7 @@ static struct variant_data variant_stm32_sdmmc = { ...@@ -280,7 +280,7 @@ static struct variant_data variant_stm32_sdmmc = {
static struct variant_data variant_stm32_sdmmcv2 = { static struct variant_data variant_stm32_sdmmcv2 = {
.fifosize = 16 * 4, .fifosize = 16 * 4,
.fifohalfsize = 8 * 4, .fifohalfsize = 8 * 4,
.f_max = 208000000, .f_max = 267000000,
.stm32_clkdiv = true, .stm32_clkdiv = true,
.cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE,
.cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC,
...@@ -2435,6 +2435,11 @@ static const struct amba_id mmci_ids[] = { ...@@ -2435,6 +2435,11 @@ static const struct amba_id mmci_ids[] = {
.mask = 0xf0ffffff, .mask = 0xf0ffffff,
.data = &variant_stm32_sdmmcv2, .data = &variant_stm32_sdmmcv2,
}, },
{
.id = 0x20253180,
.mask = 0xf0ffffff,
.data = &variant_stm32_sdmmcv2,
},
/* Qualcomm variants */ /* Qualcomm variants */
{ {
.id = 0x00051180, .id = 0x00051180,
......
...@@ -241,11 +241,12 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) ...@@ -241,11 +241,12 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired)
/* /*
* SDMMC_FBCK is selected when an external Delay Block is needed * SDMMC_FBCK is selected when an external Delay Block is needed
* with SDR104. * with SDR104 or HS200.
*/ */
if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) { if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) {
clk |= MCI_STM32_CLK_BUSSPEED; clk |= MCI_STM32_CLK_BUSSPEED;
if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) { if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104 ||
host->mmc->ios.timing == MMC_TIMING_MMC_HS200) {
clk &= ~MCI_STM32_CLK_SEL_MSK; clk &= ~MCI_STM32_CLK_SEL_MSK;
clk |= MCI_STM32_CLK_SELFBCK; clk |= MCI_STM32_CLK_SELFBCK;
} }
......
This diff is collapsed.
...@@ -1499,41 +1499,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1499,41 +1499,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
omap_hsmmc_set_bus_mode(host); omap_hsmmc_set_bus_mode(host);
} }
static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) {
struct device_node *np = mmc_dev(mmc)->of_node;
/*
* REVISIT: should be moved to sdio core and made more
* general e.g. by expanding the DT bindings of child nodes
* to provide a mechanism to provide this information:
* Documentation/devicetree/bindings/mmc/mmc-card.yaml
*/
np = of_get_compatible_child(np, "ti,wl1251");
if (np) {
/*
* We have TI wl1251 attached to MMC3. Pass this
* information to the SDIO core because it can't be
* probed by normal methods.
*/
dev_info(host->dev, "found wl1251\n");
card->quirks |= MMC_QUIRK_NONSTD_SDIO;
card->cccr.wide_bus = 1;
card->cis.vendor = 0x104c;
card->cis.device = 0x9066;
card->cis.blksize = 512;
card->cis.max_dtr = 24000000;
card->ocr = 0x80;
of_node_put(np);
}
}
}
static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
{ {
struct omap_hsmmc_host *host = mmc_priv(mmc); struct omap_hsmmc_host *host = mmc_priv(mmc);
...@@ -1660,7 +1625,6 @@ static struct mmc_host_ops omap_hsmmc_ops = { ...@@ -1660,7 +1625,6 @@ static struct mmc_host_ops omap_hsmmc_ops = {
.set_ios = omap_hsmmc_set_ios, .set_ios = omap_hsmmc_set_ios,
.get_cd = mmc_gpio_get_cd, .get_cd = mmc_gpio_get_cd,
.get_ro = mmc_gpio_get_ro, .get_ro = mmc_gpio_get_ro,
.init_card = omap_hsmmc_init_card,
.enable_sdio_irq = omap_hsmmc_enable_sdio_irq, .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
}; };
......
...@@ -305,6 +305,9 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = { ...@@ -305,6 +305,9 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = {
| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
| ESDHC_FLAG_STATE_LOST_IN_LPMODE, | ESDHC_FLAG_STATE_LOST_IN_LPMODE,
}; };
static struct esdhc_soc_data usdhc_imxrt1050_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_HS200 | ESDHC_FLAG_ERR004536,
};
static struct esdhc_soc_data usdhc_imx8qxp_data = { static struct esdhc_soc_data usdhc_imx8qxp_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
...@@ -355,6 +358,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { ...@@ -355,6 +358,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 = "fsl,imxrt1050-usdhc", .data = &usdhc_imxrt1050_data, },
{ .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, }, { .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -1866,6 +1866,7 @@ static const struct pci_device_id pci_ids[] = { ...@@ -1866,6 +1866,7 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(INTEL, JSL_SD, intel_byt_sd), SDHCI_PCI_DEVICE(INTEL, JSL_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, LKF_EMMC, intel_glk_emmc), SDHCI_PCI_DEVICE(INTEL, LKF_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(INTEL, LKF_SD, intel_byt_sd), SDHCI_PCI_DEVICE(INTEL, LKF_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, ADL_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(O2, 8120, o2), SDHCI_PCI_DEVICE(O2, 8120, o2),
SDHCI_PCI_DEVICE(O2, 8220, o2), SDHCI_PCI_DEVICE(O2, 8220, o2),
SDHCI_PCI_DEVICE(O2, 8221, o2), SDHCI_PCI_DEVICE(O2, 8221, o2),
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of.h>
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-pci.h" #include "sdhci-pci.h"
#include "cqhci.h" #include "cqhci.h"
...@@ -116,6 +117,8 @@ ...@@ -116,6 +117,8 @@
#define PCI_GLI_9755_PECONF 0x44 #define PCI_GLI_9755_PECONF 0x44
#define PCI_GLI_9755_LFCLK GENMASK(14, 12) #define PCI_GLI_9755_LFCLK GENMASK(14, 12)
#define PCI_GLI_9755_DMACLK BIT(29) #define PCI_GLI_9755_DMACLK BIT(29)
#define PCI_GLI_9755_INVERT_CD BIT(30)
#define PCI_GLI_9755_INVERT_WP BIT(31)
#define PCI_GLI_9755_CFG2 0x48 #define PCI_GLI_9755_CFG2 0x48
#define PCI_GLI_9755_CFG2_L1DLY GENMASK(28, 24) #define PCI_GLI_9755_CFG2_L1DLY GENMASK(28, 24)
...@@ -570,6 +573,14 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot) ...@@ -570,6 +573,14 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
gl9755_wt_on(pdev); gl9755_wt_on(pdev);
pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value); pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value);
/*
* Apple ARM64 platforms using these chips may have
* inverted CD/WP detection.
*/
if (of_property_read_bool(pdev->dev.of_node, "cd-inverted"))
value |= PCI_GLI_9755_INVERT_CD;
if (of_property_read_bool(pdev->dev.of_node, "wp-inverted"))
value |= PCI_GLI_9755_INVERT_WP;
value &= ~PCI_GLI_9755_LFCLK; value &= ~PCI_GLI_9755_LFCLK;
value &= ~PCI_GLI_9755_DMACLK; value &= ~PCI_GLI_9755_DMACLK;
pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value); pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value);
...@@ -891,7 +902,28 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) ...@@ -891,7 +902,28 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
return 0; return 0;
} }
#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18)
static u16 sdhci_gli_readw(struct sdhci_host *host, int reg)
{
u32 val = readl(host->ioaddr + (reg & ~3));
u16 word;
word = (val >> REG_OFFSET_IN_BITS(reg)) & 0xffff;
return word;
}
static u8 sdhci_gli_readb(struct sdhci_host *host, int reg)
{
u32 val = readl(host->ioaddr + (reg & ~3));
u8 byte = (val >> REG_OFFSET_IN_BITS(reg)) & 0xff;
return byte;
}
static const struct sdhci_ops sdhci_gl9755_ops = { static const struct sdhci_ops sdhci_gl9755_ops = {
.read_w = sdhci_gli_readw,
.read_b = sdhci_gli_readb,
.set_clock = sdhci_gl9755_set_clock, .set_clock = sdhci_gl9755_set_clock,
.enable_dma = sdhci_pci_enable_dma, .enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
...@@ -911,6 +943,8 @@ const struct sdhci_pci_fixes sdhci_gl9755 = { ...@@ -911,6 +943,8 @@ const struct sdhci_pci_fixes sdhci_gl9755 = {
}; };
static const struct sdhci_ops sdhci_gl9750_ops = { static const struct sdhci_ops sdhci_gl9750_ops = {
.read_w = sdhci_gli_readw,
.read_b = sdhci_gli_readb,
.read_l = sdhci_gl9750_readl, .read_l = sdhci_gl9750_readl,
.set_clock = sdhci_gl9750_set_clock, .set_clock = sdhci_gl9750_set_clock,
.enable_dma = sdhci_pci_enable_dma, .enable_dma = sdhci_pci_enable_dma,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/bitfield.h>
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-pci.h" #include "sdhci-pci.h"
...@@ -43,12 +44,16 @@ ...@@ -43,12 +44,16 @@
#define O2_SD_CAP_REG0 0x334 #define O2_SD_CAP_REG0 0x334
#define O2_SD_UHS1_CAP_SETTING 0x33C #define O2_SD_UHS1_CAP_SETTING 0x33C
#define O2_SD_DELAY_CTRL 0x350 #define O2_SD_DELAY_CTRL 0x350
#define O2_SD_OUTPUT_CLK_SOURCE_SWITCH 0x354
#define O2_SD_UHS2_L1_CTRL 0x35C #define O2_SD_UHS2_L1_CTRL 0x35C
#define O2_SD_FUNC_REG3 0x3E0 #define O2_SD_FUNC_REG3 0x3E0
#define O2_SD_FUNC_REG4 0x3E4 #define O2_SD_FUNC_REG4 0x3E4
#define O2_SD_LED_ENABLE BIT(6) #define O2_SD_LED_ENABLE BIT(6)
#define O2_SD_FREG0_LEDOFF BIT(13) #define O2_SD_FREG0_LEDOFF BIT(13)
#define O2_SD_SEL_DLL BIT(16)
#define O2_SD_FREG4_ENABLE_CLK_SET BIT(22) #define O2_SD_FREG4_ENABLE_CLK_SET BIT(22)
#define O2_SD_PHASE_MASK GENMASK(23, 20)
#define O2_SD_FIX_PHASE FIELD_PREP(O2_SD_PHASE_MASK, 0x9)
#define O2_SD_VENDOR_SETTING 0x110 #define O2_SD_VENDOR_SETTING 0x110
#define O2_SD_VENDOR_SETTING2 0x1C8 #define O2_SD_VENDOR_SETTING2 0x1C8
...@@ -301,9 +306,13 @@ static int sdhci_o2_dll_recovery(struct sdhci_host *host) ...@@ -301,9 +306,13 @@ static int sdhci_o2_dll_recovery(struct sdhci_host *host)
static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
{ {
struct sdhci_host *host = mmc_priv(mmc); struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct sdhci_pci_chip *chip = slot->chip;
int current_bus_width = 0; int current_bus_width = 0;
u32 scratch32 = 0; u32 scratch32 = 0;
u16 scratch = 0; u16 scratch = 0;
u8 scratch_8 = 0;
u32 reg_val;
/* /*
* This handler only implements the eMMC tuning that is specific to * This handler only implements the eMMC tuning that is specific to
...@@ -322,6 +331,32 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -322,6 +331,32 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
scratch |= O2_SD_PWR_FORCE_L0; scratch |= O2_SD_PWR_FORCE_L0;
sdhci_writew(host, scratch, O2_SD_MISC_CTRL); sdhci_writew(host, scratch, O2_SD_MISC_CTRL);
/* Stop clk */
reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
reg_val &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
/* UnLock WP */
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
scratch_8 &= 0x7f;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
/* Set pcr 0x354[16] to choose dll clock, and set the default phase */
pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &reg_val);
reg_val &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK);
reg_val |= (O2_SD_SEL_DLL | O2_SD_FIX_PHASE);
pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, reg_val);
/* Lock WP */
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
scratch_8 |= 0x80;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
/* Start clk */
reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
reg_val |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
/* wait DLL lock, timeout value 5ms */ /* wait DLL lock, timeout value 5ms */
if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host, if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host,
scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000)) scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000))
...@@ -533,23 +568,32 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -533,23 +568,32 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock == 0) if (clock == 0)
return; return;
if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) { /* UnLock WP */
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
scratch &= 0x7f;
scratch &= 0x7f; pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) {
pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32); pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32);
if ((scratch_32 & 0xFFFF0000) != 0x2c280000) if ((scratch_32 & 0xFFFF0000) != 0x2c280000)
o2_pci_set_baseclk(chip, 0x2c280000); o2_pci_set_baseclk(chip, 0x2c280000);
} else {
pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32);
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch); if ((scratch_32 & 0xFFFF0000) != 0x25100000)
o2_pci_set_baseclk(chip, 0x25100000);
scratch |= 0x80;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
} }
pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &scratch_32);
scratch_32 &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK);
pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, scratch_32);
/* Lock WP */
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
scratch |= 0x80;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
sdhci_o2_enable_clk(host, clk); sdhci_o2_enable_clk(host, clk);
} }
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#define PCI_DEVICE_ID_INTEL_JSL_SD 0x4df8 #define PCI_DEVICE_ID_INTEL_JSL_SD 0x4df8
#define PCI_DEVICE_ID_INTEL_LKF_EMMC 0x98c4 #define PCI_DEVICE_ID_INTEL_LKF_EMMC 0x98c4
#define PCI_DEVICE_ID_INTEL_LKF_SD 0x98f8 #define PCI_DEVICE_ID_INTEL_LKF_SD 0x98f8
#define PCI_DEVICE_ID_INTEL_ADL_EMMC 0x54c4
#define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000 #define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000
#define PCI_DEVICE_ID_VIA_95D0 0x95d0 #define PCI_DEVICE_ID_VIA_95D0 0x95d0
......
...@@ -960,14 +960,8 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -960,14 +960,8 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
case MMC_POWER_OFF: case MMC_POWER_OFF:
tmio_mmc_power_off(host); tmio_mmc_power_off(host);
/* For R-Car Gen2+, we need to reset SDHI specific SCC */ /* For R-Car Gen2+, we need to reset SDHI specific SCC */
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) { if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
host->reset(host); tmio_mmc_reset(host);
if (host->native_hotplug)
tmio_mmc_enable_mmc_irqs(host,
TMIO_STAT_CARD_REMOVE |
TMIO_STAT_CARD_INSERT);
}
host->set_clock(host, 0); host->set_clock(host, 0);
break; break;
...@@ -1175,6 +1169,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) ...@@ -1175,6 +1169,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
if (mmc_can_gpio_cd(mmc)) if (mmc_can_gpio_cd(mmc))
_host->ops.get_cd = mmc_gpio_get_cd; _host->ops.get_cd = mmc_gpio_get_cd;
/* must be set before tmio_mmc_reset() */
_host->native_hotplug = !(mmc_can_gpio_cd(mmc) || _host->native_hotplug = !(mmc_can_gpio_cd(mmc) ||
mmc->caps & MMC_CAP_NEEDS_POLL || mmc->caps & MMC_CAP_NEEDS_POLL ||
!mmc_card_is_removable(mmc)); !mmc_card_is_removable(mmc));
...@@ -1295,10 +1290,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev) ...@@ -1295,10 +1290,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
if (host->clk_cache) if (host->clk_cache)
host->set_clock(host, host->clk_cache); host->set_clock(host, host->clk_cache);
if (host->native_hotplug)
tmio_mmc_enable_mmc_irqs(host,
TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
tmio_mmc_enable_dma(host, true); tmio_mmc_enable_dma(host, true);
return 0; return 0;
......
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