mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 23:34:05 +08:00
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 -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmHdkxQXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCkkQA//SwIMN56vM1AfsXZ+VxlTbvaI sy6OQKHiLXUWvjdDgVFP6tSQFNUYdwxLResB254VVABhq8wvuNgi4YO6TEoKgjAq QzEM6NTSBZPRn0L5tZ04lZW+JJdYfWg+xTFAxCHzgHvIIJGIWazypLNT74CLaofH 9k0GpN6SoUTXA5/zJNl5X4JIW7wQUGv6j1vhFcxCMir5OPWN6cHPzeL6cplG0OYD NllATjKw7wHdOLwfEi0TQiGnqGlyEz0bZpgqYMYVyDj9+Be8eME6Mbgn96rezyFX x5buZdv7RAaDLZzVMpYbYi0UKghDk4RkiV2CPEQ7Fvrqw1sAln1TRLQjoDWrZfJZ i94lTtKp8XSyH9LZ4en/yolNIHYqatz88k9gas6ivPG/mfUSS89iLumFbk5vn0BE 7GBOsrA3K+j6xoPRatWP8C+Nvh6sDBJKpBIEp7ZmkuRBlSCZE4iUIBLguciosghH dcgLxqBEfHxOSuXTySibAjqsAa3xcZNoUoeNmrf1eLYoH0hihScXwNmRxNEn5Hv3 RomKpnIUQ98sZ9JBuchoY9Y9GH64QyWGnnEMQ8Knm7JMDJc8FEkNcJ4Vuyhridss jh7UU4wtsAi2ljeT+8kPTtzdKHTM47PV06+aXg+zStLFGWQD05CARwKM/KrWc7Hl eh72G7TKveb2FuKRoSg= =JDAt -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
1151e3cd5a
@ -118,6 +118,9 @@ properties:
|
||||
phy-names:
|
||||
const: phy_arasan
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
arasan,soc-ctl-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
|
@ -53,6 +53,12 @@ properties:
|
||||
items:
|
||||
- const: arm,pl18x
|
||||
- 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:
|
||||
description: One or two clocks, the "apb_pclk" and the "MCLK"
|
||||
@ -60,6 +66,18 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
dmas:
|
||||
maxItems: 2
|
||||
|
||||
dma-names:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
- items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
power-domains: true
|
||||
|
||||
resets:
|
||||
@ -213,7 +231,6 @@ examples:
|
||||
arm,primecell-periphid = <0x10153180>;
|
||||
reg = <0x52007000 0x1000>;
|
||||
interrupts = <49>;
|
||||
interrupt-names = "cmd_irq";
|
||||
clocks = <&rcc 0>;
|
||||
clock-names = "apb_pclk";
|
||||
resets = <&rcc 1>;
|
||||
|
@ -1,53 +0,0 @@
|
||||
* 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";
|
||||
};
|
100
Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml
Normal file
100
Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml
Normal file
@ -0,0 +1,100 @@
|
||||
# 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:
|
||||
specific extensions.
|
||||
- "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
|
||||
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
|
||||
unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
|
||||
|
@ -34,6 +34,7 @@ properties:
|
||||
- fsl,imx6ull-usdhc
|
||||
- fsl,imx7d-usdhc
|
||||
- fsl,imx7ulp-usdhc
|
||||
- fsl,imxrt1050-usdhc
|
||||
- nxp,s32g2-usdhc
|
||||
- items:
|
||||
- enum:
|
||||
@ -44,6 +45,10 @@ properties:
|
||||
- fsl,imx8qm-usdhc
|
||||
- fsl,imx8qxp-usdhc
|
||||
- const: fsl,imx7d-usdhc
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx8ulp-usdhc
|
||||
- const: fsl,imx8mm-usdhc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -116,6 +121,9 @@ properties:
|
||||
- const: ahb
|
||||
- const: per
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
pinctrl-names:
|
||||
oneOf:
|
||||
- minItems: 3
|
||||
|
@ -1,28 +0,0 @@
|
||||
* 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:
|
||||
const: mmc
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: DMA controller phandle and request line for RX
|
||||
- description: DMA controller phandle and request line for TX
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
oneOf:
|
||||
- items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
- const: tx-rx
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -80,3 +81,27 @@ examples:
|
||||
<&dma JZ4780_DMA_MSC0_TX 0xffffffff>;
|
||||
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:
|
||||
- const: mediatek,mt8195-mmc
|
||||
- const: mediatek,mt8183-mmc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Should contain phandle for the clock feeding the MMC controller.
|
||||
@ -62,6 +65,9 @@ properties:
|
||||
- const: axi_cg
|
||||
- const: ahb_cg
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
pinctrl-names:
|
||||
items:
|
||||
- const: default
|
||||
|
@ -48,6 +48,8 @@ properties:
|
||||
- const: clk_ahb
|
||||
- const: clk_xin
|
||||
|
||||
sdhci-caps-mask: true
|
||||
|
||||
# PHY output tap delays:
|
||||
# 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
|
||||
|
@ -17,6 +17,7 @@ Required properties:
|
||||
"qcom,msm8974-sdhci", "qcom,sdhci-msm-v4"
|
||||
"qcom,msm8916-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,qcs404-sdhci", "qcom,sdhci-msm-v5"
|
||||
"qcom,sc7180-sdhci", "qcom,sdhci-msm-v5";
|
||||
|
@ -1,23 +0,0 @@
|
||||
* 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:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
maxItems: 1
|
||||
|
||||
dma-names:
|
||||
const: rx-tx
|
||||
|
||||
reset-names:
|
||||
description: |
|
||||
There are three reset signals at maximum
|
||||
|
@ -15,7 +15,10 @@ maintainers:
|
||||
# Everything else is described in the common file
|
||||
properties:
|
||||
compatible:
|
||||
const: snps,dw-mshc
|
||||
enum:
|
||||
- altr,socfpga-dw-mshc
|
||||
- img,pistachio-dw-mshc
|
||||
- snps,dw-mshc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -17251,6 +17251,13 @@ L: linux-mmc@vger.kernel.org
|
||||
S: Maintained
|
||||
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
|
||||
M: Jonathan Derrick <jonathan.derrick@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)
|
||||
|
||||
cb_data.card = card;
|
||||
cb_data.status = 0;
|
||||
err = __mmc_poll_for_busy(card, MMC_BLK_TIMEOUT_MS, &mmc_blk_busy_cb,
|
||||
&cb_data);
|
||||
err = __mmc_poll_for_busy(card->host, MMC_BLK_TIMEOUT_MS,
|
||||
&mmc_blk_busy_cb, &cb_data);
|
||||
|
||||
/*
|
||||
* Do not assume data transferred correctly if there are any error bits
|
||||
|
@ -53,16 +53,6 @@ static struct attribute *mmc_dev_attrs[] = {
|
||||
};
|
||||
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
|
||||
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 = {
|
||||
static struct bus_type mmc_bus_type = {
|
||||
.name = "mmc",
|
||||
.dev_groups = mmc_dev_groups,
|
||||
.match = mmc_bus_match,
|
||||
.uevent = mmc_bus_uevent,
|
||||
.probe = mmc_bus_probe,
|
||||
.remove = mmc_bus_remove,
|
||||
|
@ -59,6 +59,9 @@ struct mmc_fixup {
|
||||
/* for MMC cards */
|
||||
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);
|
||||
int data;
|
||||
};
|
||||
@ -119,6 +122,21 @@ struct mmc_fixup {
|
||||
_vendor, _device, \
|
||||
_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) \
|
||||
(((u64) hwrev) << 40 | \
|
||||
((u64) fwrev) << 32 | \
|
||||
@ -150,6 +168,24 @@ static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card,
|
||||
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.
|
||||
*/
|
||||
|
@ -1962,7 +1962,7 @@ static int mmc_sleep(struct mmc_host *host)
|
||||
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:
|
||||
mmc_retune_release(host);
|
||||
|
@ -58,6 +58,12 @@ struct mmc_busy_data {
|
||||
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 err;
|
||||
@ -173,43 +179,62 @@ int mmc_go_idle(struct mmc_host *host)
|
||||
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)
|
||||
{
|
||||
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.arg = mmc_host_is_spi(host) ? 0 : ocr;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
|
||||
|
||||
for (i = 100; i; i--) {
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (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);
|
||||
}
|
||||
err = __mmc_poll_for_busy(host, 1000, &__mmc_send_op_cond_cb, &cb_data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (rocr && !mmc_host_is_spi(host))
|
||||
*rocr = cmd.resp[0];
|
||||
@ -470,11 +495,10 @@ static int mmc_busy_cb(void *cb_data, bool *busy)
|
||||
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),
|
||||
void *cb_data)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
int err;
|
||||
unsigned long timeout;
|
||||
unsigned int udelay = 32, udelay_max = 32768;
|
||||
@ -515,13 +539,14 @@ EXPORT_SYMBOL_GPL(__mmc_poll_for_busy);
|
||||
int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
|
||||
bool retry_crc_err, enum mmc_busy_cmd busy_cmd)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
struct mmc_busy_data cb_data;
|
||||
|
||||
cb_data.card = card;
|
||||
cb_data.retry_crc_err = retry_crc_err;
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
bool mmc_prepare_busy_cmd(struct mmc_host *host, struct mmc_command *cmd,
|
||||
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),
|
||||
void *cb_data);
|
||||
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,
|
||||
gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc,
|
||||
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,
|
||||
enum mmc_issue_type issue_type;
|
||||
enum mmc_issued issued;
|
||||
bool get_card, cqe_retune_ok;
|
||||
int ret;
|
||||
blk_status_t ret;
|
||||
|
||||
if (mmc_card_removed(mq->card)) {
|
||||
req->rq_flags |= RQF_QUIET;
|
||||
|
@ -10,6 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
|
||||
#include "card.h"
|
||||
@ -145,6 +146,25 @@ static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = {
|
||||
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,
|
||||
const struct mmc_fixup *table)
|
||||
{
|
||||
@ -152,22 +172,32 @@ static inline void mmc_fixup_device(struct mmc_card *card,
|
||||
u64 rev = cid_rev_card(card);
|
||||
|
||||
for (f = table; f->vendor_fixup; f++) {
|
||||
if ((f->manfid == CID_MANFID_ANY ||
|
||||
f->manfid == card->cid.manfid) &&
|
||||
(f->oemid == CID_OEMID_ANY ||
|
||||
f->oemid == card->cid.oemid) &&
|
||||
(f->name == CID_NAME_ANY ||
|
||||
!strncmp(f->name, card->cid.prod_name,
|
||||
sizeof(card->cid.prod_name))) &&
|
||||
(f->cis_vendor == card->cis.vendor ||
|
||||
f->cis_vendor == (u16) SDIO_ANY_ID) &&
|
||||
(f->cis_device == card->cis.device ||
|
||||
f->cis_device == (u16) SDIO_ANY_ID) &&
|
||||
(f->ext_csd_rev == EXT_CSD_REV_ANY ||
|
||||
f->ext_csd_rev == card->ext_csd.rev) &&
|
||||
rev >= f->rev_start && rev <= f->rev_end) {
|
||||
dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup);
|
||||
f->vendor_fixup(card, f->data);
|
||||
}
|
||||
if (f->manfid != CID_MANFID_ANY &&
|
||||
f->manfid != card->cid.manfid)
|
||||
continue;
|
||||
if (f->oemid != CID_OEMID_ANY &&
|
||||
f->oemid != card->cid.oemid)
|
||||
continue;
|
||||
if (f->name != CID_NAME_ANY &&
|
||||
strncmp(f->name, card->cid.prod_name,
|
||||
sizeof(card->cid.prod_name)))
|
||||
continue;
|
||||
if (f->cis_vendor != (u16)SDIO_ANY_ID &&
|
||||
f->cis_vendor != card->cis.vendor)
|
||||
continue;
|
||||
if (f->cis_device != (u16)SDIO_ANY_ID &&
|
||||
f->cis_device != card->cis.device)
|
||||
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)
|
||||
|
||||
cb_data.card = card;
|
||||
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);
|
||||
|
||||
out:
|
||||
|
@ -707,6 +707,9 @@ try_again:
|
||||
*/
|
||||
if (host->ops->init_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
|
||||
@ -820,7 +823,7 @@ try_again:
|
||||
goto mismatch;
|
||||
}
|
||||
}
|
||||
card->ocr = ocr_card;
|
||||
|
||||
mmc_fixup_device(card, sdio_fixup_methods);
|
||||
|
||||
if (card->type == MMC_TYPE_SD_COMBO) {
|
||||
|
@ -969,8 +969,10 @@ static int au1xmmc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
if (host->irq < 0)
|
||||
if (host->irq < 0) {
|
||||
ret = host->irq;
|
||||
goto out3;
|
||||
}
|
||||
|
||||
mmc->ops = &au1xmmc_ops;
|
||||
|
||||
|
@ -28,6 +28,7 @@ enum dw_mci_exynos_type {
|
||||
DW_MCI_TYPE_EXYNOS5420_SMU,
|
||||
DW_MCI_TYPE_EXYNOS7,
|
||||
DW_MCI_TYPE_EXYNOS7_SMU,
|
||||
DW_MCI_TYPE_ARTPEC8,
|
||||
};
|
||||
|
||||
/* Exynos implementation specific driver private data */
|
||||
@ -69,6 +70,9 @@ static struct dw_mci_exynos_compatible {
|
||||
}, {
|
||||
.compatible = "samsung,exynos7-dw-mshc-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)
|
||||
else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
|
||||
return EXYNOS4210_FIXED_CIU_CLK_DIV;
|
||||
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;
|
||||
else
|
||||
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)
|
||||
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);
|
||||
|
||||
return 0;
|
||||
@ -133,7 +143,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
|
||||
u32 clksel;
|
||||
|
||||
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);
|
||||
else
|
||||
clksel = mci_readl(host, CLKSEL);
|
||||
@ -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;
|
||||
|
||||
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);
|
||||
else
|
||||
mci_writel(host, CLKSEL, clksel);
|
||||
@ -210,14 +222,16 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
|
||||
return ret;
|
||||
|
||||
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);
|
||||
else
|
||||
clksel = mci_readl(host, CLKSEL);
|
||||
|
||||
if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
|
||||
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);
|
||||
else
|
||||
mci_writel(host, CLKSEL, clksel);
|
||||
@ -238,7 +252,8 @@ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
|
||||
* Not supported to configure register
|
||||
* 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)
|
||||
dev_warn(host->dev,
|
||||
"cannot configure HS400, unsupported chipset\n");
|
||||
@ -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;
|
||||
|
||||
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));
|
||||
else
|
||||
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)
|
||||
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||||
|
||||
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);
|
||||
else
|
||||
clksel = mci_readl(host, CLKSEL);
|
||||
clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
|
||||
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);
|
||||
else
|
||||
mci_writel(host, CLKSEL, clksel);
|
||||
@ -425,7 +443,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
|
||||
u8 sample;
|
||||
|
||||
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);
|
||||
else
|
||||
clksel = mci_readl(host, CLKSEL);
|
||||
@ -434,7 +453,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
|
||||
clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
|
||||
|
||||
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);
|
||||
else
|
||||
mci_writel(host, CLKSEL, clksel);
|
||||
@ -524,17 +544,65 @@ static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
|
||||
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 */
|
||||
static unsigned long exynos_dwmmc_caps[4] = {
|
||||
MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
|
||||
MMC_CAP_CMD23,
|
||||
MMC_CAP_CMD23,
|
||||
MMC_CAP_CMD23,
|
||||
MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
static const struct dw_mci_drv_data exynos_drv_data = {
|
||||
.caps = exynos_dwmmc_caps,
|
||||
.num_caps = ARRAY_SIZE(exynos_dwmmc_caps),
|
||||
.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,
|
||||
@ -542,6 +610,16 @@ static const struct dw_mci_drv_data exynos_drv_data = {
|
||||
.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[] = {
|
||||
{ .compatible = "samsung,exynos4412-dw-mshc",
|
||||
.data = &exynos_drv_data, },
|
||||
@ -555,6 +633,8 @@ static const struct of_device_id dw_mci_exynos_match[] = {
|
||||
.data = &exynos_drv_data, },
|
||||
{ .compatible = "samsung,exynos7-dw-mshc-smu",
|
||||
.data = &exynos_drv_data, },
|
||||
{ .compatible = "axis,artpec8-dw-mshc",
|
||||
.data = &artpec_drv_data, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
|
||||
|
@ -23,12 +23,6 @@ struct hi3798cv200_priv {
|
||||
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)
|
||||
{
|
||||
struct hi3798cv200_priv *priv = host->priv;
|
||||
@ -166,8 +160,7 @@ disable_sample_clk:
|
||||
}
|
||||
|
||||
static const struct dw_mci_drv_data hi3798cv200_data = {
|
||||
.caps = dw_mci_hi3798cv200_caps,
|
||||
.num_caps = ARRAY_SIZE(dw_mci_hi3798cv200_caps),
|
||||
.common_caps = MMC_CAP_CMD23,
|
||||
.init = dw_mci_hi3798cv200_init,
|
||||
.set_ios = dw_mci_hi3798cv200_set_ios,
|
||||
.execute_tuning = dw_mci_hi3798cv200_execute_tuning,
|
||||
|
@ -300,21 +300,12 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
|
||||
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 = {
|
||||
.init = dw_mci_rockchip_init,
|
||||
};
|
||||
|
||||
static const struct dw_mci_drv_data rk3288_drv_data = {
|
||||
.caps = dw_mci_rk3288_dwmmc_caps,
|
||||
.num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps),
|
||||
.common_caps = MMC_CAP_CMD23,
|
||||
.set_ios = dw_mci_rk3288_set_ios,
|
||||
.execute_tuning = dw_mci_rk3288_execute_tuning,
|
||||
.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)
|
||||
cmdr == MMC_WRITE_BLOCK ||
|
||||
cmdr == MMC_WRITE_MULTIPLE_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->arg = 0;
|
||||
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)
|
||||
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,
|
||||
struct dw_mci_slot *slot,
|
||||
struct mmc_command *cmd)
|
||||
@ -1303,7 +1335,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
|
||||
|
||||
data = cmd->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, BLKSIZ, data->blksz);
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
const struct dw_mci_drv_data *drv_data = host->drv_data;
|
||||
unsigned int drto_clks;
|
||||
unsigned int drto_div;
|
||||
unsigned int drto_ms;
|
||||
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;
|
||||
if (drto_div == 0)
|
||||
drto_div = 1;
|
||||
@ -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,
|
||||
host->bus_hz);
|
||||
|
||||
dev_dbg(host->dev, "drto_ms: %u\n", drto_ms);
|
||||
|
||||
/* add a bit spare time */
|
||||
drto_ms += 10;
|
||||
|
||||
@ -2724,11 +2762,20 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
||||
if (pending & DW_MCI_DATA_ERROR_FLAGS) {
|
||||
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 */
|
||||
mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
|
||||
host->data_status = pending;
|
||||
smp_wmb(); /* drain writebuffer */
|
||||
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);
|
||||
|
||||
spin_unlock(&host->irq_lock);
|
||||
@ -2828,6 +2875,9 @@ static int dw_mci_init_slot_caps(struct dw_mci_slot *slot)
|
||||
if (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) {
|
||||
ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
|
||||
if (ctrl_id < 0)
|
||||
|
@ -118,6 +118,7 @@ struct dw_mci_dma_slave {
|
||||
* @part_buf: Simple buffer for partial fifo reads/writes.
|
||||
* @push_data: Pointer to FIFO push 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.
|
||||
* @irq_flags: The flags to be passed to request_irq.
|
||||
* @irq: The irq value to be passed to request_irq.
|
||||
@ -223,6 +224,7 @@ struct dw_mci {
|
||||
void (*push_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;
|
||||
unsigned long irq_flags; /* IRQ flags */
|
||||
int irq;
|
||||
@ -274,6 +276,9 @@ struct dw_mci_board {
|
||||
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_280A 0x280a
|
||||
|
||||
@ -550,10 +555,14 @@ struct dw_mci_slot {
|
||||
* dw_mci driver data - dw-mshc implementation specific driver data.
|
||||
* @caps: mmc subsystem specified capabilities of the controller(s).
|
||||
* @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.
|
||||
* @set_ios: handle bus specific extensions.
|
||||
* @parse_dt: parse implementation specific device tree properties.
|
||||
* @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
|
||||
* data structure is fully optional and usage of each member in this structure
|
||||
@ -562,6 +571,7 @@ struct dw_mci_slot {
|
||||
struct dw_mci_drv_data {
|
||||
unsigned long *caps;
|
||||
u32 num_caps;
|
||||
u32 common_caps;
|
||||
int (*init)(struct dw_mci *host);
|
||||
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
|
||||
int (*parse_dt)(struct dw_mci *host);
|
||||
@ -570,5 +580,8 @@ struct dw_mci_drv_data {
|
||||
struct mmc_ios *ios);
|
||||
int (*switch_voltage)(struct mmc_host *mmc,
|
||||
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_ */
|
||||
|
@ -217,11 +217,23 @@ static void jz4740_mmc_release_dma_channels(struct jz4740_mmc_host *host)
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
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");
|
||||
if (IS_ERR(host->dma_tx)) {
|
||||
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)
|
||||
static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host,
|
||||
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,
|
||||
|
@ -12,8 +12,6 @@
|
||||
|
||||
#include "meson-mx-sdhc.h"
|
||||
|
||||
#define MESON_SDHC_NUM_BUILTIN_CLKS 6
|
||||
|
||||
struct meson_mx_sdhc_clkc {
|
||||
struct clk_mux src_sel;
|
||||
struct clk_divider div;
|
||||
|
@ -854,6 +854,11 @@ static int meson_mx_sdhc_probe(struct platform_device *pdev)
|
||||
goto err_disable_pclk;
|
||||
|
||||
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,
|
||||
meson_mx_sdhc_irq_thread, IRQF_ONESHOT,
|
||||
NULL, host);
|
||||
|
@ -662,6 +662,11 @@ static int meson_mx_mmc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto error_free_mmc;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(host->controller_dev, irq,
|
||||
meson_mx_mmc_irq,
|
||||
meson_mx_mmc_irq_thread, IRQF_ONESHOT,
|
||||
|
@ -547,7 +547,7 @@ mmc_spi_command_send(struct mmc_spi_host *host,
|
||||
static void
|
||||
mmc_spi_setup_data_message(
|
||||
struct mmc_spi_host *host,
|
||||
int multiple,
|
||||
bool multiple,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct spi_transfer *t;
|
||||
@ -859,14 +859,14 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
|
||||
struct spi_device *spi = host->spi;
|
||||
struct device *dma_dev = host->dma_dev;
|
||||
struct spi_transfer *t;
|
||||
enum dma_data_direction direction;
|
||||
enum dma_data_direction direction = mmc_get_dma_dir(data);
|
||||
struct scatterlist *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;
|
||||
unsigned long timeout;
|
||||
|
||||
direction = mmc_get_dma_dir(data);
|
||||
mmc_spi_setup_data_message(host, multiple, direction);
|
||||
t = &host->t;
|
||||
|
||||
@ -921,9 +921,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
|
||||
while (length) {
|
||||
t->len = min(length, blk_size);
|
||||
|
||||
dev_dbg(&host->spi->dev, " %s block, %d bytes\n",
|
||||
(direction == DMA_TO_DEVICE) ? "write" : "read",
|
||||
t->len);
|
||||
dev_dbg(&spi->dev, " %s block, %d bytes\n", write_or_read, t->len);
|
||||
|
||||
if (direction == DMA_TO_DEVICE)
|
||||
status = mmc_spi_writeblock(host, t, timeout);
|
||||
@ -948,9 +946,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
|
||||
|
||||
if (status < 0) {
|
||||
data->error = status;
|
||||
dev_dbg(&spi->dev, "%s status %d\n",
|
||||
(direction == DMA_TO_DEVICE) ? "write" : "read",
|
||||
status);
|
||||
dev_dbg(&spi->dev, "%s status %d\n", write_or_read, status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ static struct variant_data variant_stm32_sdmmc = {
|
||||
static struct variant_data variant_stm32_sdmmcv2 = {
|
||||
.fifosize = 16 * 4,
|
||||
.fifohalfsize = 8 * 4,
|
||||
.f_max = 208000000,
|
||||
.f_max = 267000000,
|
||||
.stm32_clkdiv = true,
|
||||
.cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE,
|
||||
.cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC,
|
||||
@ -2435,6 +2435,11 @@ static const struct amba_id mmci_ids[] = {
|
||||
.mask = 0xf0ffffff,
|
||||
.data = &variant_stm32_sdmmcv2,
|
||||
},
|
||||
{
|
||||
.id = 0x20253180,
|
||||
.mask = 0xf0ffffff,
|
||||
.data = &variant_stm32_sdmmcv2,
|
||||
},
|
||||
/* Qualcomm variants */
|
||||
{
|
||||
.id = 0x00051180,
|
||||
|
@ -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
|
||||
* with SDR104.
|
||||
* with SDR104 or HS200.
|
||||
*/
|
||||
if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) {
|
||||
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_SELFBCK;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
@ -98,226 +99,226 @@
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/* MSDC_CFG mask */
|
||||
#define MSDC_CFG_MODE (0x1 << 0) /* RW */
|
||||
#define MSDC_CFG_CKPDN (0x1 << 1) /* RW */
|
||||
#define MSDC_CFG_RST (0x1 << 2) /* RW */
|
||||
#define MSDC_CFG_PIO (0x1 << 3) /* RW */
|
||||
#define MSDC_CFG_CKDRVEN (0x1 << 4) /* RW */
|
||||
#define MSDC_CFG_BV18SDT (0x1 << 5) /* RW */
|
||||
#define MSDC_CFG_BV18PSS (0x1 << 6) /* R */
|
||||
#define MSDC_CFG_CKSTB (0x1 << 7) /* R */
|
||||
#define MSDC_CFG_CKDIV (0xff << 8) /* RW */
|
||||
#define MSDC_CFG_CKMOD (0x3 << 16) /* RW */
|
||||
#define MSDC_CFG_HS400_CK_MODE (0x1 << 18) /* RW */
|
||||
#define MSDC_CFG_HS400_CK_MODE_EXTRA (0x1 << 22) /* RW */
|
||||
#define MSDC_CFG_CKDIV_EXTRA (0xfff << 8) /* RW */
|
||||
#define MSDC_CFG_CKMOD_EXTRA (0x3 << 20) /* RW */
|
||||
#define MSDC_CFG_MODE BIT(0) /* RW */
|
||||
#define MSDC_CFG_CKPDN BIT(1) /* RW */
|
||||
#define MSDC_CFG_RST BIT(2) /* RW */
|
||||
#define MSDC_CFG_PIO BIT(3) /* RW */
|
||||
#define MSDC_CFG_CKDRVEN BIT(4) /* RW */
|
||||
#define MSDC_CFG_BV18SDT BIT(5) /* RW */
|
||||
#define MSDC_CFG_BV18PSS BIT(6) /* R */
|
||||
#define MSDC_CFG_CKSTB BIT(7) /* R */
|
||||
#define MSDC_CFG_CKDIV GENMASK(15, 8) /* RW */
|
||||
#define MSDC_CFG_CKMOD GENMASK(17, 16) /* RW */
|
||||
#define MSDC_CFG_HS400_CK_MODE BIT(18) /* RW */
|
||||
#define MSDC_CFG_HS400_CK_MODE_EXTRA BIT(22) /* RW */
|
||||
#define MSDC_CFG_CKDIV_EXTRA GENMASK(19, 8) /* RW */
|
||||
#define MSDC_CFG_CKMOD_EXTRA GENMASK(21, 20) /* RW */
|
||||
|
||||
/* MSDC_IOCON mask */
|
||||
#define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */
|
||||
#define MSDC_IOCON_RSPL (0x1 << 1) /* RW */
|
||||
#define MSDC_IOCON_DSPL (0x1 << 2) /* RW */
|
||||
#define MSDC_IOCON_DDLSEL (0x1 << 3) /* RW */
|
||||
#define MSDC_IOCON_DDR50CKD (0x1 << 4) /* RW */
|
||||
#define MSDC_IOCON_DSPLSEL (0x1 << 5) /* RW */
|
||||
#define MSDC_IOCON_W_DSPL (0x1 << 8) /* RW */
|
||||
#define MSDC_IOCON_D0SPL (0x1 << 16) /* RW */
|
||||
#define MSDC_IOCON_D1SPL (0x1 << 17) /* RW */
|
||||
#define MSDC_IOCON_D2SPL (0x1 << 18) /* RW */
|
||||
#define MSDC_IOCON_D3SPL (0x1 << 19) /* RW */
|
||||
#define MSDC_IOCON_D4SPL (0x1 << 20) /* RW */
|
||||
#define MSDC_IOCON_D5SPL (0x1 << 21) /* RW */
|
||||
#define MSDC_IOCON_D6SPL (0x1 << 22) /* RW */
|
||||
#define MSDC_IOCON_D7SPL (0x1 << 23) /* RW */
|
||||
#define MSDC_IOCON_RISCSZ (0x3 << 24) /* RW */
|
||||
#define MSDC_IOCON_SDR104CKS BIT(0) /* RW */
|
||||
#define MSDC_IOCON_RSPL BIT(1) /* RW */
|
||||
#define MSDC_IOCON_DSPL BIT(2) /* RW */
|
||||
#define MSDC_IOCON_DDLSEL BIT(3) /* RW */
|
||||
#define MSDC_IOCON_DDR50CKD BIT(4) /* RW */
|
||||
#define MSDC_IOCON_DSPLSEL BIT(5) /* RW */
|
||||
#define MSDC_IOCON_W_DSPL BIT(8) /* RW */
|
||||
#define MSDC_IOCON_D0SPL BIT(16) /* RW */
|
||||
#define MSDC_IOCON_D1SPL BIT(17) /* RW */
|
||||
#define MSDC_IOCON_D2SPL BIT(18) /* RW */
|
||||
#define MSDC_IOCON_D3SPL BIT(19) /* RW */
|
||||
#define MSDC_IOCON_D4SPL BIT(20) /* RW */
|
||||
#define MSDC_IOCON_D5SPL BIT(21) /* RW */
|
||||
#define MSDC_IOCON_D6SPL BIT(22) /* RW */
|
||||
#define MSDC_IOCON_D7SPL BIT(23) /* RW */
|
||||
#define MSDC_IOCON_RISCSZ GENMASK(25, 24) /* RW */
|
||||
|
||||
/* MSDC_PS mask */
|
||||
#define MSDC_PS_CDEN (0x1 << 0) /* RW */
|
||||
#define MSDC_PS_CDSTS (0x1 << 1) /* R */
|
||||
#define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */
|
||||
#define MSDC_PS_DAT (0xff << 16) /* R */
|
||||
#define MSDC_PS_DATA1 (0x1 << 17) /* R */
|
||||
#define MSDC_PS_CMD (0x1 << 24) /* R */
|
||||
#define MSDC_PS_WP (0x1 << 31) /* R */
|
||||
#define MSDC_PS_CDEN BIT(0) /* RW */
|
||||
#define MSDC_PS_CDSTS BIT(1) /* R */
|
||||
#define MSDC_PS_CDDEBOUNCE GENMASK(15, 12) /* RW */
|
||||
#define MSDC_PS_DAT GENMASK(23, 16) /* R */
|
||||
#define MSDC_PS_DATA1 BIT(17) /* R */
|
||||
#define MSDC_PS_CMD BIT(24) /* R */
|
||||
#define MSDC_PS_WP BIT(31) /* R */
|
||||
|
||||
/* MSDC_INT mask */
|
||||
#define MSDC_INT_MMCIRQ (0x1 << 0) /* W1C */
|
||||
#define MSDC_INT_CDSC (0x1 << 1) /* W1C */
|
||||
#define MSDC_INT_ACMDRDY (0x1 << 3) /* W1C */
|
||||
#define MSDC_INT_ACMDTMO (0x1 << 4) /* W1C */
|
||||
#define MSDC_INT_ACMDCRCERR (0x1 << 5) /* W1C */
|
||||
#define MSDC_INT_DMAQ_EMPTY (0x1 << 6) /* W1C */
|
||||
#define MSDC_INT_SDIOIRQ (0x1 << 7) /* W1C */
|
||||
#define MSDC_INT_CMDRDY (0x1 << 8) /* W1C */
|
||||
#define MSDC_INT_CMDTMO (0x1 << 9) /* W1C */
|
||||
#define MSDC_INT_RSPCRCERR (0x1 << 10) /* W1C */
|
||||
#define MSDC_INT_CSTA (0x1 << 11) /* R */
|
||||
#define MSDC_INT_XFER_COMPL (0x1 << 12) /* W1C */
|
||||
#define MSDC_INT_DXFER_DONE (0x1 << 13) /* W1C */
|
||||
#define MSDC_INT_DATTMO (0x1 << 14) /* W1C */
|
||||
#define MSDC_INT_DATCRCERR (0x1 << 15) /* W1C */
|
||||
#define MSDC_INT_ACMD19_DONE (0x1 << 16) /* W1C */
|
||||
#define MSDC_INT_DMA_BDCSERR (0x1 << 17) /* W1C */
|
||||
#define MSDC_INT_DMA_GPDCSERR (0x1 << 18) /* W1C */
|
||||
#define MSDC_INT_DMA_PROTECT (0x1 << 19) /* W1C */
|
||||
#define MSDC_INT_CMDQ (0x1 << 28) /* W1C */
|
||||
#define MSDC_INT_MMCIRQ BIT(0) /* W1C */
|
||||
#define MSDC_INT_CDSC BIT(1) /* W1C */
|
||||
#define MSDC_INT_ACMDRDY BIT(3) /* W1C */
|
||||
#define MSDC_INT_ACMDTMO BIT(4) /* W1C */
|
||||
#define MSDC_INT_ACMDCRCERR BIT(5) /* W1C */
|
||||
#define MSDC_INT_DMAQ_EMPTY BIT(6) /* W1C */
|
||||
#define MSDC_INT_SDIOIRQ BIT(7) /* W1C */
|
||||
#define MSDC_INT_CMDRDY BIT(8) /* W1C */
|
||||
#define MSDC_INT_CMDTMO BIT(9) /* W1C */
|
||||
#define MSDC_INT_RSPCRCERR BIT(10) /* W1C */
|
||||
#define MSDC_INT_CSTA BIT(11) /* R */
|
||||
#define MSDC_INT_XFER_COMPL BIT(12) /* W1C */
|
||||
#define MSDC_INT_DXFER_DONE BIT(13) /* W1C */
|
||||
#define MSDC_INT_DATTMO BIT(14) /* W1C */
|
||||
#define MSDC_INT_DATCRCERR BIT(15) /* W1C */
|
||||
#define MSDC_INT_ACMD19_DONE BIT(16) /* W1C */
|
||||
#define MSDC_INT_DMA_BDCSERR BIT(17) /* W1C */
|
||||
#define MSDC_INT_DMA_GPDCSERR BIT(18) /* W1C */
|
||||
#define MSDC_INT_DMA_PROTECT BIT(19) /* W1C */
|
||||
#define MSDC_INT_CMDQ BIT(28) /* W1C */
|
||||
|
||||
/* MSDC_INTEN mask */
|
||||
#define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */
|
||||
#define MSDC_INTEN_CDSC (0x1 << 1) /* RW */
|
||||
#define MSDC_INTEN_ACMDRDY (0x1 << 3) /* RW */
|
||||
#define MSDC_INTEN_ACMDTMO (0x1 << 4) /* RW */
|
||||
#define MSDC_INTEN_ACMDCRCERR (0x1 << 5) /* RW */
|
||||
#define MSDC_INTEN_DMAQ_EMPTY (0x1 << 6) /* RW */
|
||||
#define MSDC_INTEN_SDIOIRQ (0x1 << 7) /* RW */
|
||||
#define MSDC_INTEN_CMDRDY (0x1 << 8) /* RW */
|
||||
#define MSDC_INTEN_CMDTMO (0x1 << 9) /* RW */
|
||||
#define MSDC_INTEN_RSPCRCERR (0x1 << 10) /* RW */
|
||||
#define MSDC_INTEN_CSTA (0x1 << 11) /* RW */
|
||||
#define MSDC_INTEN_XFER_COMPL (0x1 << 12) /* RW */
|
||||
#define MSDC_INTEN_DXFER_DONE (0x1 << 13) /* RW */
|
||||
#define MSDC_INTEN_DATTMO (0x1 << 14) /* RW */
|
||||
#define MSDC_INTEN_DATCRCERR (0x1 << 15) /* RW */
|
||||
#define MSDC_INTEN_ACMD19_DONE (0x1 << 16) /* RW */
|
||||
#define MSDC_INTEN_DMA_BDCSERR (0x1 << 17) /* RW */
|
||||
#define MSDC_INTEN_DMA_GPDCSERR (0x1 << 18) /* RW */
|
||||
#define MSDC_INTEN_DMA_PROTECT (0x1 << 19) /* RW */
|
||||
#define MSDC_INTEN_MMCIRQ BIT(0) /* RW */
|
||||
#define MSDC_INTEN_CDSC BIT(1) /* RW */
|
||||
#define MSDC_INTEN_ACMDRDY BIT(3) /* RW */
|
||||
#define MSDC_INTEN_ACMDTMO BIT(4) /* RW */
|
||||
#define MSDC_INTEN_ACMDCRCERR BIT(5) /* RW */
|
||||
#define MSDC_INTEN_DMAQ_EMPTY BIT(6) /* RW */
|
||||
#define MSDC_INTEN_SDIOIRQ BIT(7) /* RW */
|
||||
#define MSDC_INTEN_CMDRDY BIT(8) /* RW */
|
||||
#define MSDC_INTEN_CMDTMO BIT(9) /* RW */
|
||||
#define MSDC_INTEN_RSPCRCERR BIT(10) /* RW */
|
||||
#define MSDC_INTEN_CSTA BIT(11) /* RW */
|
||||
#define MSDC_INTEN_XFER_COMPL BIT(12) /* RW */
|
||||
#define MSDC_INTEN_DXFER_DONE BIT(13) /* RW */
|
||||
#define MSDC_INTEN_DATTMO BIT(14) /* RW */
|
||||
#define MSDC_INTEN_DATCRCERR BIT(15) /* RW */
|
||||
#define MSDC_INTEN_ACMD19_DONE BIT(16) /* RW */
|
||||
#define MSDC_INTEN_DMA_BDCSERR BIT(17) /* RW */
|
||||
#define MSDC_INTEN_DMA_GPDCSERR BIT(18) /* RW */
|
||||
#define MSDC_INTEN_DMA_PROTECT BIT(19) /* RW */
|
||||
|
||||
/* MSDC_FIFOCS mask */
|
||||
#define MSDC_FIFOCS_RXCNT (0xff << 0) /* R */
|
||||
#define MSDC_FIFOCS_TXCNT (0xff << 16) /* R */
|
||||
#define MSDC_FIFOCS_CLR (0x1 << 31) /* RW */
|
||||
#define MSDC_FIFOCS_RXCNT GENMASK(7, 0) /* R */
|
||||
#define MSDC_FIFOCS_TXCNT GENMASK(23, 16) /* R */
|
||||
#define MSDC_FIFOCS_CLR BIT(31) /* RW */
|
||||
|
||||
/* SDC_CFG mask */
|
||||
#define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */
|
||||
#define SDC_CFG_INSWKUP (0x1 << 1) /* RW */
|
||||
#define SDC_CFG_WRDTOC (0x1fff << 2) /* RW */
|
||||
#define SDC_CFG_BUSWIDTH (0x3 << 16) /* RW */
|
||||
#define SDC_CFG_SDIO (0x1 << 19) /* RW */
|
||||
#define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */
|
||||
#define SDC_CFG_INTATGAP (0x1 << 21) /* RW */
|
||||
#define SDC_CFG_DTOC (0xff << 24) /* RW */
|
||||
#define SDC_CFG_SDIOINTWKUP BIT(0) /* RW */
|
||||
#define SDC_CFG_INSWKUP BIT(1) /* RW */
|
||||
#define SDC_CFG_WRDTOC GENMASK(14, 2) /* RW */
|
||||
#define SDC_CFG_BUSWIDTH GENMASK(17, 16) /* RW */
|
||||
#define SDC_CFG_SDIO BIT(19) /* RW */
|
||||
#define SDC_CFG_SDIOIDE BIT(20) /* RW */
|
||||
#define SDC_CFG_INTATGAP BIT(21) /* RW */
|
||||
#define SDC_CFG_DTOC GENMASK(31, 24) /* RW */
|
||||
|
||||
/* SDC_STS mask */
|
||||
#define SDC_STS_SDCBUSY (0x1 << 0) /* RW */
|
||||
#define SDC_STS_CMDBUSY (0x1 << 1) /* RW */
|
||||
#define SDC_STS_SWR_COMPL (0x1 << 31) /* RW */
|
||||
#define SDC_STS_SDCBUSY BIT(0) /* RW */
|
||||
#define SDC_STS_CMDBUSY BIT(1) /* RW */
|
||||
#define SDC_STS_SWR_COMPL BIT(31) /* RW */
|
||||
|
||||
#define SDC_DAT1_IRQ_TRIGGER (0x1 << 19) /* RW */
|
||||
#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */
|
||||
/* SDC_ADV_CFG0 mask */
|
||||
#define SDC_RX_ENHANCE_EN (0x1 << 20) /* RW */
|
||||
#define SDC_RX_ENHANCE_EN BIT(20) /* RW */
|
||||
|
||||
/* DMA_SA_H4BIT mask */
|
||||
#define DMA_ADDR_HIGH_4BIT (0xf << 0) /* RW */
|
||||
#define DMA_ADDR_HIGH_4BIT GENMASK(3, 0) /* RW */
|
||||
|
||||
/* MSDC_DMA_CTRL mask */
|
||||
#define MSDC_DMA_CTRL_START (0x1 << 0) /* W */
|
||||
#define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */
|
||||
#define MSDC_DMA_CTRL_RESUME (0x1 << 2) /* W */
|
||||
#define MSDC_DMA_CTRL_MODE (0x1 << 8) /* RW */
|
||||
#define MSDC_DMA_CTRL_LASTBUF (0x1 << 10) /* RW */
|
||||
#define MSDC_DMA_CTRL_BRUSTSZ (0x7 << 12) /* RW */
|
||||
#define MSDC_DMA_CTRL_START BIT(0) /* W */
|
||||
#define MSDC_DMA_CTRL_STOP BIT(1) /* W */
|
||||
#define MSDC_DMA_CTRL_RESUME BIT(2) /* W */
|
||||
#define MSDC_DMA_CTRL_MODE BIT(8) /* RW */
|
||||
#define MSDC_DMA_CTRL_LASTBUF BIT(10) /* RW */
|
||||
#define MSDC_DMA_CTRL_BRUSTSZ GENMASK(14, 12) /* RW */
|
||||
|
||||
/* MSDC_DMA_CFG mask */
|
||||
#define MSDC_DMA_CFG_STS (0x1 << 0) /* R */
|
||||
#define MSDC_DMA_CFG_DECSEN (0x1 << 1) /* RW */
|
||||
#define MSDC_DMA_CFG_AHBHPROT2 (0x2 << 8) /* RW */
|
||||
#define MSDC_DMA_CFG_ACTIVEEN (0x2 << 12) /* RW */
|
||||
#define MSDC_DMA_CFG_CS12B16B (0x1 << 16) /* RW */
|
||||
#define MSDC_DMA_CFG_STS BIT(0) /* R */
|
||||
#define MSDC_DMA_CFG_DECSEN BIT(1) /* RW */
|
||||
#define MSDC_DMA_CFG_AHBHPROT2 BIT(9) /* RW */
|
||||
#define MSDC_DMA_CFG_ACTIVEEN BIT(13) /* RW */
|
||||
#define MSDC_DMA_CFG_CS12B16B BIT(16) /* RW */
|
||||
|
||||
/* MSDC_PATCH_BIT mask */
|
||||
#define MSDC_PATCH_BIT_ODDSUPP (0x1 << 1) /* RW */
|
||||
#define MSDC_INT_DAT_LATCH_CK_SEL (0x7 << 7)
|
||||
#define MSDC_CKGEN_MSDC_DLY_SEL (0x1f << 10)
|
||||
#define MSDC_PATCH_BIT_IODSSEL (0x1 << 16) /* RW */
|
||||
#define MSDC_PATCH_BIT_IOINTSEL (0x1 << 17) /* RW */
|
||||
#define MSDC_PATCH_BIT_BUSYDLY (0xf << 18) /* RW */
|
||||
#define MSDC_PATCH_BIT_WDOD (0xf << 22) /* RW */
|
||||
#define MSDC_PATCH_BIT_IDRTSEL (0x1 << 26) /* RW */
|
||||
#define MSDC_PATCH_BIT_CMDFSEL (0x1 << 27) /* RW */
|
||||
#define MSDC_PATCH_BIT_INTDLSEL (0x1 << 28) /* RW */
|
||||
#define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */
|
||||
#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */
|
||||
#define MSDC_PATCH_BIT_ODDSUPP BIT(1) /* RW */
|
||||
#define MSDC_INT_DAT_LATCH_CK_SEL GENMASK(9, 7)
|
||||
#define MSDC_CKGEN_MSDC_DLY_SEL GENMASK(14, 10)
|
||||
#define MSDC_PATCH_BIT_IODSSEL BIT(16) /* RW */
|
||||
#define MSDC_PATCH_BIT_IOINTSEL BIT(17) /* RW */
|
||||
#define MSDC_PATCH_BIT_BUSYDLY GENMASK(21, 18) /* RW */
|
||||
#define MSDC_PATCH_BIT_WDOD GENMASK(25, 22) /* RW */
|
||||
#define MSDC_PATCH_BIT_IDRTSEL BIT(26) /* RW */
|
||||
#define MSDC_PATCH_BIT_CMDFSEL BIT(27) /* RW */
|
||||
#define MSDC_PATCH_BIT_INTDLSEL BIT(28) /* RW */
|
||||
#define MSDC_PATCH_BIT_SPCPUSH BIT(29) /* RW */
|
||||
#define MSDC_PATCH_BIT_DECRCTMO BIT(30) /* RW */
|
||||
|
||||
#define MSDC_PATCH_BIT1_CMDTA (0x7 << 3) /* RW */
|
||||
#define MSDC_PB1_BUSY_CHECK_SEL (0x1 << 7) /* RW */
|
||||
#define MSDC_PATCH_BIT1_STOP_DLY (0xf << 8) /* RW */
|
||||
#define MSDC_PATCH_BIT1_CMDTA GENMASK(5, 3) /* RW */
|
||||
#define MSDC_PB1_BUSY_CHECK_SEL BIT(7) /* RW */
|
||||
#define MSDC_PATCH_BIT1_STOP_DLY GENMASK(11, 8) /* RW */
|
||||
|
||||
#define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */
|
||||
#define MSDC_PATCH_BIT2_CFGCRCSTS (0x1 << 28) /* RW */
|
||||
#define MSDC_PB2_SUPPORT_64G (0x1 << 1) /* RW */
|
||||
#define MSDC_PB2_RESPWAIT (0x3 << 2) /* RW */
|
||||
#define MSDC_PB2_RESPSTSENSEL (0x7 << 16) /* RW */
|
||||
#define MSDC_PB2_CRCSTSENSEL (0x7 << 29) /* RW */
|
||||
#define MSDC_PATCH_BIT2_CFGRESP BIT(15) /* RW */
|
||||
#define MSDC_PATCH_BIT2_CFGCRCSTS BIT(28) /* RW */
|
||||
#define MSDC_PB2_SUPPORT_64G BIT(1) /* RW */
|
||||
#define MSDC_PB2_RESPWAIT GENMASK(3, 2) /* RW */
|
||||
#define MSDC_PB2_RESPSTSENSEL GENMASK(18, 16) /* RW */
|
||||
#define MSDC_PB2_CRCSTSENSEL GENMASK(31, 29) /* RW */
|
||||
|
||||
#define MSDC_PAD_TUNE_DATWRDLY (0x1f << 0) /* RW */
|
||||
#define MSDC_PAD_TUNE_DATRRDLY (0x1f << 8) /* RW */
|
||||
#define MSDC_PAD_TUNE_CMDRDLY (0x1f << 16) /* RW */
|
||||
#define MSDC_PAD_TUNE_CMDRRDLY (0x1f << 22) /* RW */
|
||||
#define MSDC_PAD_TUNE_CLKTDLY (0x1f << 27) /* RW */
|
||||
#define MSDC_PAD_TUNE_RXDLYSEL (0x1 << 15) /* RW */
|
||||
#define MSDC_PAD_TUNE_RD_SEL (0x1 << 13) /* RW */
|
||||
#define MSDC_PAD_TUNE_CMD_SEL (0x1 << 21) /* RW */
|
||||
#define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* RW */
|
||||
#define MSDC_PAD_TUNE_DATRRDLY GENMASK(12, 8) /* RW */
|
||||
#define MSDC_PAD_TUNE_CMDRDLY GENMASK(20, 16) /* RW */
|
||||
#define MSDC_PAD_TUNE_CMDRRDLY GENMASK(26, 22) /* RW */
|
||||
#define MSDC_PAD_TUNE_CLKTDLY GENMASK(31, 27) /* RW */
|
||||
#define MSDC_PAD_TUNE_RXDLYSEL BIT(15) /* RW */
|
||||
#define MSDC_PAD_TUNE_RD_SEL BIT(13) /* RW */
|
||||
#define MSDC_PAD_TUNE_CMD_SEL BIT(21) /* RW */
|
||||
|
||||
#define PAD_DS_TUNE_DLY_SEL (0x1 << 0) /* RW */
|
||||
#define PAD_DS_TUNE_DLY1 (0x1f << 2) /* RW */
|
||||
#define PAD_DS_TUNE_DLY2 (0x1f << 7) /* RW */
|
||||
#define PAD_DS_TUNE_DLY3 (0x1f << 12) /* RW */
|
||||
#define PAD_DS_TUNE_DLY_SEL BIT(0) /* RW */
|
||||
#define PAD_DS_TUNE_DLY1 GENMASK(6, 2) /* RW */
|
||||
#define PAD_DS_TUNE_DLY2 GENMASK(11, 7) /* RW */
|
||||
#define PAD_DS_TUNE_DLY3 GENMASK(16, 12) /* RW */
|
||||
|
||||
#define PAD_CMD_TUNE_RX_DLY3 (0x1f << 1) /* RW */
|
||||
#define PAD_CMD_TUNE_RX_DLY3 GENMASK(5, 1) /* RW */
|
||||
|
||||
/* EMMC51_CFG0 mask */
|
||||
#define CMDQ_RDAT_CNT (0x3ff << 12) /* RW */
|
||||
#define CMDQ_RDAT_CNT GENMASK(21, 12) /* RW */
|
||||
|
||||
#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0) /* RW */
|
||||
#define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3) /* RW */
|
||||
#define EMMC50_CFG_CFCSTS_SEL (0x1 << 4) /* RW */
|
||||
#define EMMC50_CFG_CMD_RESP_SEL (0x1 << 9) /* RW */
|
||||
#define EMMC50_CFG_PADCMD_LATCHCK BIT(0) /* RW */
|
||||
#define EMMC50_CFG_CRCSTS_EDGE BIT(3) /* RW */
|
||||
#define EMMC50_CFG_CFCSTS_SEL BIT(4) /* RW */
|
||||
#define EMMC50_CFG_CMD_RESP_SEL BIT(9) /* RW */
|
||||
|
||||
/* EMMC50_CFG1 mask */
|
||||
#define EMMC50_CFG1_DS_CFG (0x1 << 28) /* RW */
|
||||
#define EMMC50_CFG1_DS_CFG BIT(28) /* RW */
|
||||
|
||||
#define EMMC50_CFG3_OUTS_WR (0x1f << 0) /* RW */
|
||||
#define EMMC50_CFG3_OUTS_WR GENMASK(4, 0) /* RW */
|
||||
|
||||
#define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */
|
||||
#define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */
|
||||
#define SDC_FIFO_CFG_WRVALIDSEL BIT(24) /* RW */
|
||||
#define SDC_FIFO_CFG_RDVALIDSEL BIT(25) /* RW */
|
||||
|
||||
/* CQHCI_SETTING */
|
||||
#define CQHCI_RD_CMD_WND_SEL (0x1 << 14) /* RW */
|
||||
#define CQHCI_WR_CMD_WND_SEL (0x1 << 15) /* RW */
|
||||
#define CQHCI_RD_CMD_WND_SEL BIT(14) /* RW */
|
||||
#define CQHCI_WR_CMD_WND_SEL BIT(15) /* RW */
|
||||
|
||||
/* EMMC_TOP_CONTROL mask */
|
||||
#define PAD_RXDLY_SEL (0x1 << 0) /* RW */
|
||||
#define DELAY_EN (0x1 << 1) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY2 (0x1f << 2) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY (0x1f << 7) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY2_SEL (0x1 << 12) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY_SEL (0x1 << 13) /* RW */
|
||||
#define DATA_K_VALUE_SEL (0x1 << 14) /* RW */
|
||||
#define SDC_RX_ENH_EN (0x1 << 15) /* TW */
|
||||
#define PAD_RXDLY_SEL BIT(0) /* RW */
|
||||
#define DELAY_EN BIT(1) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY2 GENMASK(6, 2) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY GENMASK(11, 7) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY2_SEL BIT(12) /* RW */
|
||||
#define PAD_DAT_RD_RXDLY_SEL BIT(13) /* RW */
|
||||
#define DATA_K_VALUE_SEL BIT(14) /* RW */
|
||||
#define SDC_RX_ENH_EN BIT(15) /* TW */
|
||||
|
||||
/* EMMC_TOP_CMD mask */
|
||||
#define PAD_CMD_RXDLY2 (0x1f << 0) /* RW */
|
||||
#define PAD_CMD_RXDLY (0x1f << 5) /* RW */
|
||||
#define PAD_CMD_RD_RXDLY2_SEL (0x1 << 10) /* RW */
|
||||
#define PAD_CMD_RD_RXDLY_SEL (0x1 << 11) /* RW */
|
||||
#define PAD_CMD_TX_DLY (0x1f << 12) /* RW */
|
||||
#define PAD_CMD_RXDLY2 GENMASK(4, 0) /* RW */
|
||||
#define PAD_CMD_RXDLY GENMASK(9, 5) /* RW */
|
||||
#define PAD_CMD_RD_RXDLY2_SEL BIT(10) /* RW */
|
||||
#define PAD_CMD_RD_RXDLY_SEL BIT(11) /* RW */
|
||||
#define PAD_CMD_TX_DLY GENMASK(16, 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 PAD_DS_DLY_SEL BIT(16) /* RW */
|
||||
#define PAD_DS_DLY1 GENMASK(14, 10) /* RW */
|
||||
#define PAD_DS_DLY3 GENMASK(4, 0) /* RW */
|
||||
|
||||
#define REQ_CMD_EIO (0x1 << 0)
|
||||
#define REQ_CMD_TMO (0x1 << 1)
|
||||
#define REQ_DAT_ERR (0x1 << 2)
|
||||
#define REQ_STOP_EIO (0x1 << 3)
|
||||
#define REQ_STOP_TMO (0x1 << 4)
|
||||
#define REQ_CMD_BUSY (0x1 << 5)
|
||||
#define REQ_CMD_EIO BIT(0)
|
||||
#define REQ_CMD_TMO BIT(1)
|
||||
#define REQ_DAT_ERR BIT(2)
|
||||
#define REQ_STOP_EIO BIT(3)
|
||||
#define REQ_STOP_TMO BIT(4)
|
||||
#define REQ_CMD_BUSY BIT(5)
|
||||
|
||||
#define MSDC_PREPARE_FLAG (0x1 << 0)
|
||||
#define MSDC_ASYNC_FLAG (0x1 << 1)
|
||||
#define MSDC_MMAP_FLAG (0x1 << 2)
|
||||
#define MSDC_PREPARE_FLAG BIT(0)
|
||||
#define MSDC_ASYNC_FLAG BIT(1)
|
||||
#define MSDC_MMAP_FLAG BIT(2)
|
||||
|
||||
#define MTK_MMC_AUTOSUSPEND_DELAY 50
|
||||
#define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */
|
||||
@ -331,17 +332,17 @@
|
||||
/*--------------------------------------------------------------------------*/
|
||||
struct mt_gpdma_desc {
|
||||
u32 gpd_info;
|
||||
#define GPDMA_DESC_HWO (0x1 << 0)
|
||||
#define GPDMA_DESC_BDP (0x1 << 1)
|
||||
#define GPDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */
|
||||
#define GPDMA_DESC_INT (0x1 << 16)
|
||||
#define GPDMA_DESC_NEXT_H4 (0xf << 24)
|
||||
#define GPDMA_DESC_PTR_H4 (0xf << 28)
|
||||
#define GPDMA_DESC_HWO BIT(0)
|
||||
#define GPDMA_DESC_BDP BIT(1)
|
||||
#define GPDMA_DESC_CHECKSUM GENMASK(15, 8)
|
||||
#define GPDMA_DESC_INT BIT(16)
|
||||
#define GPDMA_DESC_NEXT_H4 GENMASK(27, 24)
|
||||
#define GPDMA_DESC_PTR_H4 GENMASK(31, 28)
|
||||
u32 next;
|
||||
u32 ptr;
|
||||
u32 gpd_data_len;
|
||||
#define GPDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */
|
||||
#define GPDMA_DESC_EXTLEN (0xff << 16) /* bit16 ~ bit23 */
|
||||
#define GPDMA_DESC_BUFLEN GENMASK(15, 0)
|
||||
#define GPDMA_DESC_EXTLEN GENMASK(23, 16)
|
||||
u32 arg;
|
||||
u32 blknum;
|
||||
u32 cmd;
|
||||
@ -349,17 +350,17 @@ struct mt_gpdma_desc {
|
||||
|
||||
struct mt_bdma_desc {
|
||||
u32 bd_info;
|
||||
#define BDMA_DESC_EOL (0x1 << 0)
|
||||
#define BDMA_DESC_CHECKSUM (0xff << 8) /* bit8 ~ bit15 */
|
||||
#define BDMA_DESC_BLKPAD (0x1 << 17)
|
||||
#define BDMA_DESC_DWPAD (0x1 << 18)
|
||||
#define BDMA_DESC_NEXT_H4 (0xf << 24)
|
||||
#define BDMA_DESC_PTR_H4 (0xf << 28)
|
||||
#define BDMA_DESC_EOL BIT(0)
|
||||
#define BDMA_DESC_CHECKSUM GENMASK(15, 8)
|
||||
#define BDMA_DESC_BLKPAD BIT(17)
|
||||
#define BDMA_DESC_DWPAD BIT(18)
|
||||
#define BDMA_DESC_NEXT_H4 GENMASK(27, 24)
|
||||
#define BDMA_DESC_PTR_H4 GENMASK(31, 28)
|
||||
u32 next;
|
||||
u32 ptr;
|
||||
u32 bd_data_len;
|
||||
#define BDMA_DESC_BUFLEN (0xffff) /* bit0 ~ bit15 */
|
||||
#define BDMA_DESC_BUFLEN_EXT (0xffffff) /* bit0 ~ bit23 */
|
||||
#define BDMA_DESC_BUFLEN GENMASK(15, 0)
|
||||
#define BDMA_DESC_BUFLEN_EXT GENMASK(23, 0)
|
||||
};
|
||||
|
||||
struct msdc_dma {
|
||||
@ -636,12 +637,11 @@ static void msdc_reset_hw(struct msdc_host *host)
|
||||
u32 val;
|
||||
|
||||
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_RST);
|
||||
while (readl(host->base + MSDC_CFG) & MSDC_CFG_RST)
|
||||
cpu_relax();
|
||||
readl_poll_timeout(host->base + MSDC_CFG, val, !(val & MSDC_CFG_RST), 0, 0);
|
||||
|
||||
sdr_set_bits(host->base + MSDC_FIFOCS, MSDC_FIFOCS_CLR);
|
||||
while (readl(host->base + MSDC_FIFOCS) & MSDC_FIFOCS_CLR)
|
||||
cpu_relax();
|
||||
readl_poll_timeout(host->base + MSDC_FIFOCS, val,
|
||||
!(val & MSDC_FIFOCS_CLR), 0, 0);
|
||||
|
||||
val = readl(host->base + MSDC_INT);
|
||||
writel(val, host->base + MSDC_INT);
|
||||
@ -725,7 +725,7 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
|
||||
sdr_set_field(host->base + MSDC_DMA_CFG, MSDC_DMA_CFG_DECSEN, 1);
|
||||
dma_ctrl = readl_relaxed(host->base + MSDC_DMA_CTRL);
|
||||
dma_ctrl &= ~(MSDC_DMA_CTRL_BRUSTSZ | MSDC_DMA_CTRL_MODE);
|
||||
dma_ctrl |= (MSDC_BURST_64B << 12 | 1 << 8);
|
||||
dma_ctrl |= (MSDC_BURST_64B << 12 | BIT(8));
|
||||
writel_relaxed(dma_ctrl, host->base + MSDC_DMA_CTRL);
|
||||
if (host->dev_comp->support_64g)
|
||||
sdr_set_field(host->base + DMA_SA_H4BIT, DMA_ADDR_HIGH_4BIT,
|
||||
@ -769,7 +769,7 @@ static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks)
|
||||
do_div(timeout, clk_ns);
|
||||
timeout += clks;
|
||||
/* in 1048576 sclk cycle unit */
|
||||
timeout = DIV_ROUND_UP(timeout, (0x1 << 20));
|
||||
timeout = DIV_ROUND_UP(timeout, BIT(20));
|
||||
if (host->dev_comp->clk_div_bits == 8)
|
||||
sdr_get_field(host->base + MSDC_CFG,
|
||||
MSDC_CFG_CKMOD, &mode);
|
||||
@ -814,8 +814,9 @@ static void msdc_gate_clock(struct msdc_host *host)
|
||||
clk_disable_unprepare(host->h_clk);
|
||||
}
|
||||
|
||||
static void msdc_ungate_clock(struct msdc_host *host)
|
||||
static int msdc_ungate_clock(struct msdc_host *host)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
clk_prepare_enable(host->h_clk);
|
||||
@ -825,11 +826,11 @@ static void msdc_ungate_clock(struct msdc_host *host)
|
||||
ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n");
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
|
||||
cpu_relax();
|
||||
return readl_poll_timeout(host->base + MSDC_CFG, val,
|
||||
(val & MSDC_CFG_CKSTB), 1, 20000);
|
||||
}
|
||||
|
||||
static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
@ -840,6 +841,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
u32 div;
|
||||
u32 sclk;
|
||||
u32 tune_reg = host->dev_comp->pad_tune_reg;
|
||||
u32 val;
|
||||
|
||||
if (!hz) {
|
||||
dev_dbg(host->dev, "set mclk to 0\n");
|
||||
@ -899,14 +901,8 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
}
|
||||
}
|
||||
sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
|
||||
/*
|
||||
* As src_clk/HCLK use the same bit to gate/ungate,
|
||||
* So if want to only gate src_clk, need gate its parent(mux).
|
||||
*/
|
||||
if (host->src_clk_cg)
|
||||
clk_disable_unprepare(host->src_clk_cg);
|
||||
else
|
||||
clk_disable_unprepare(clk_get_parent(host->src_clk));
|
||||
|
||||
clk_disable_unprepare(host->src_clk_cg);
|
||||
if (host->dev_comp->clk_div_bits == 8)
|
||||
sdr_set_field(host->base + MSDC_CFG,
|
||||
MSDC_CFG_CKMOD | MSDC_CFG_CKDIV,
|
||||
@ -915,13 +911,9 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
sdr_set_field(host->base + MSDC_CFG,
|
||||
MSDC_CFG_CKMOD_EXTRA | MSDC_CFG_CKDIV_EXTRA,
|
||||
(mode << 12) | div);
|
||||
if (host->src_clk_cg)
|
||||
clk_prepare_enable(host->src_clk_cg);
|
||||
else
|
||||
clk_prepare_enable(clk_get_parent(host->src_clk));
|
||||
|
||||
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
|
||||
cpu_relax();
|
||||
clk_prepare_enable(host->src_clk_cg);
|
||||
readl_poll_timeout(host->base + MSDC_CFG, val, (val & MSDC_CFG_CKSTB), 0, 0);
|
||||
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
|
||||
mmc->actual_clock = sclk;
|
||||
host->mclk = hz;
|
||||
@ -1013,15 +1005,15 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
|
||||
|
||||
if ((opcode == SD_IO_RW_DIRECT && cmd->flags == (unsigned int) -1) ||
|
||||
opcode == MMC_STOP_TRANSMISSION)
|
||||
rawcmd |= (0x1 << 14);
|
||||
rawcmd |= BIT(14);
|
||||
else if (opcode == SD_SWITCH_VOLTAGE)
|
||||
rawcmd |= (0x1 << 30);
|
||||
rawcmd |= BIT(30);
|
||||
else if (opcode == SD_APP_SEND_SCR ||
|
||||
opcode == SD_APP_SEND_NUM_WR_BLKS ||
|
||||
(opcode == SD_SWITCH && mmc_cmd_type(cmd) == MMC_CMD_ADTC) ||
|
||||
(opcode == SD_APP_SD_STATUS && mmc_cmd_type(cmd) == MMC_CMD_ADTC) ||
|
||||
(opcode == MMC_SEND_EXT_CSD && mmc_cmd_type(cmd) == MMC_CMD_ADTC))
|
||||
rawcmd |= (0x1 << 11);
|
||||
rawcmd |= BIT(11);
|
||||
|
||||
if (cmd->data) {
|
||||
struct mmc_data *data = cmd->data;
|
||||
@ -1029,16 +1021,16 @@ static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
|
||||
if (mmc_op_multi(opcode)) {
|
||||
if (mmc_card_mmc(mmc->card) && mrq->sbc &&
|
||||
!(mrq->sbc->arg & 0xFFFF0000))
|
||||
rawcmd |= 0x2 << 28; /* AutoCMD23 */
|
||||
rawcmd |= BIT(29); /* AutoCMD23 */
|
||||
}
|
||||
|
||||
rawcmd |= ((data->blksz & 0xFFF) << 16);
|
||||
if (data->flags & MMC_DATA_WRITE)
|
||||
rawcmd |= (0x1 << 13);
|
||||
rawcmd |= BIT(13);
|
||||
if (data->blocks > 1)
|
||||
rawcmd |= (0x2 << 11);
|
||||
rawcmd |= BIT(12);
|
||||
else
|
||||
rawcmd |= (0x1 << 11);
|
||||
rawcmd |= BIT(11);
|
||||
/* Always use dma mode */
|
||||
sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_PIO);
|
||||
|
||||
@ -1231,13 +1223,13 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
|
||||
static inline bool msdc_cmd_is_ready(struct msdc_host *host,
|
||||
struct mmc_request *mrq, struct mmc_command *cmd)
|
||||
{
|
||||
/* The max busy time we can endure is 20ms */
|
||||
unsigned long tmo = jiffies + msecs_to_jiffies(20);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
while ((readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) &&
|
||||
time_before(jiffies, tmo))
|
||||
cpu_relax();
|
||||
if (readl(host->base + SDC_STS) & SDC_STS_CMDBUSY) {
|
||||
/* The max busy time we can endure is 20ms */
|
||||
ret = readl_poll_timeout_atomic(host->base + SDC_STS, val,
|
||||
!(val & SDC_STS_CMDBUSY), 1, 20000);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "CMD bus busy detected\n");
|
||||
host->error |= REQ_CMD_BUSY;
|
||||
msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd);
|
||||
@ -1245,12 +1237,10 @@ static inline bool msdc_cmd_is_ready(struct msdc_host *host,
|
||||
}
|
||||
|
||||
if (mmc_resp_type(cmd) == MMC_RSP_R1B || cmd->data) {
|
||||
tmo = jiffies + msecs_to_jiffies(20);
|
||||
/* R1B or with data, should check SDCBUSY */
|
||||
while ((readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) &&
|
||||
time_before(jiffies, tmo))
|
||||
cpu_relax();
|
||||
if (readl(host->base + SDC_STS) & SDC_STS_SDCBUSY) {
|
||||
ret = readl_poll_timeout_atomic(host->base + SDC_STS, val,
|
||||
!(val & SDC_STS_SDCBUSY), 1, 20000);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "Controller busy detected\n");
|
||||
host->error |= REQ_CMD_BUSY;
|
||||
msdc_cmd_done(host, MSDC_INT_CMDTMO, mrq, cmd);
|
||||
@ -1376,6 +1366,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
|
||||
(MSDC_INT_XFER_COMPL | MSDC_INT_DATCRCERR | MSDC_INT_DATTMO
|
||||
| MSDC_INT_DMA_BDCSERR | MSDC_INT_DMA_GPDCSERR
|
||||
| MSDC_INT_DMA_PROTECT);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
done = !host->data;
|
||||
@ -1392,8 +1384,14 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
|
||||
readl(host->base + MSDC_DMA_CFG));
|
||||
sdr_set_field(host->base + MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP,
|
||||
1);
|
||||
while (readl(host->base + MSDC_DMA_CFG) & MSDC_DMA_CFG_STS)
|
||||
cpu_relax();
|
||||
|
||||
ret = readl_poll_timeout_atomic(host->base + MSDC_DMA_CFG, val,
|
||||
!(val & MSDC_DMA_CFG_STS), 1, 20000);
|
||||
if (ret) {
|
||||
dev_dbg(host->dev, "DMA stop timed out\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sdr_clr_bits(host->base + MSDC_INTEN, data_ints_mask);
|
||||
dev_dbg(host->dev, "DMA stop\n");
|
||||
|
||||
@ -1631,6 +1629,7 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
{
|
||||
u32 val;
|
||||
u32 tune_reg = host->dev_comp->pad_tune_reg;
|
||||
struct mmc_host *mmc = mmc_from_priv(host);
|
||||
|
||||
if (host->reset) {
|
||||
reset_control_assert(host->reset);
|
||||
@ -1685,7 +1684,7 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
}
|
||||
|
||||
if (host->dev_comp->busy_check)
|
||||
sdr_clr_bits(host->base + MSDC_PATCH_BIT1, (1 << 7));
|
||||
sdr_clr_bits(host->base + MSDC_PATCH_BIT1, BIT(7));
|
||||
|
||||
if (host->dev_comp->async_fifo) {
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT2,
|
||||
@ -1736,14 +1735,18 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
MSDC_PAD_TUNE_RXDLYSEL);
|
||||
}
|
||||
|
||||
/* Configure to enable SDIO mode.
|
||||
* it's must otherwise sdio cmd5 failed
|
||||
*/
|
||||
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
|
||||
if (mmc->caps2 & MMC_CAP2_NO_SDIO) {
|
||||
sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
|
||||
sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
|
||||
sdr_clr_bits(host->base + SDC_ADV_CFG0, SDC_DAT1_IRQ_TRIGGER);
|
||||
} else {
|
||||
/* Configure to enable SDIO mode, otherwise SDIO CMD5 fails */
|
||||
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
|
||||
|
||||
/* Config SDIO device detect interrupt function */
|
||||
sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
|
||||
sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_DAT1_IRQ_TRIGGER);
|
||||
/* Config SDIO device detect interrupt function */
|
||||
sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
|
||||
sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_DAT1_IRQ_TRIGGER);
|
||||
}
|
||||
|
||||
/* Configure to default data timeout */
|
||||
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
|
||||
@ -1865,7 +1868,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
static u32 test_delay_bit(u32 delay, u32 bit)
|
||||
{
|
||||
bit %= PAD_DELAY_MAX;
|
||||
return delay & (1 << bit);
|
||||
return delay & BIT(bit);
|
||||
}
|
||||
|
||||
static int get_delay_len(u32 delay, u32 start_bit)
|
||||
@ -1970,9 +1973,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
|
||||
for (j = 0; j < 3; j++) {
|
||||
mmc_send_tuning(mmc, opcode, &cmd_err);
|
||||
if (!cmd_err) {
|
||||
rise_delay |= (1 << i);
|
||||
rise_delay |= BIT(i);
|
||||
} else {
|
||||
rise_delay &= ~(1 << i);
|
||||
rise_delay &= ~BIT(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1994,9 +1997,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
|
||||
for (j = 0; j < 3; j++) {
|
||||
mmc_send_tuning(mmc, opcode, &cmd_err);
|
||||
if (!cmd_err) {
|
||||
fall_delay |= (1 << i);
|
||||
fall_delay |= BIT(i);
|
||||
} else {
|
||||
fall_delay &= ~(1 << i);
|
||||
fall_delay &= ~BIT(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2024,7 +2027,7 @@ skip_fall:
|
||||
MSDC_PAD_TUNE_CMDRRDLY, i);
|
||||
mmc_send_tuning(mmc, opcode, &cmd_err);
|
||||
if (!cmd_err)
|
||||
internal_delay |= (1 << i);
|
||||
internal_delay |= BIT(i);
|
||||
}
|
||||
dev_dbg(host->dev, "Final internal delay: 0x%x\n", internal_delay);
|
||||
internal_delay_phase = get_best_delay(host, internal_delay);
|
||||
@ -2069,9 +2072,9 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode)
|
||||
for (j = 0; j < 3; j++) {
|
||||
mmc_send_tuning(mmc, opcode, &cmd_err);
|
||||
if (!cmd_err) {
|
||||
cmd_delay |= (1 << i);
|
||||
cmd_delay |= BIT(i);
|
||||
} else {
|
||||
cmd_delay &= ~(1 << i);
|
||||
cmd_delay &= ~BIT(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2101,7 +2104,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
|
||||
msdc_set_data_delay(host, i);
|
||||
ret = mmc_send_tuning(mmc, opcode, NULL);
|
||||
if (!ret)
|
||||
rise_delay |= (1 << i);
|
||||
rise_delay |= BIT(i);
|
||||
}
|
||||
final_rise_delay = get_best_delay(host, rise_delay);
|
||||
/* if rising edge has enough margin, then do not scan falling edge */
|
||||
@ -2115,7 +2118,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
|
||||
msdc_set_data_delay(host, i);
|
||||
ret = mmc_send_tuning(mmc, opcode, NULL);
|
||||
if (!ret)
|
||||
fall_delay |= (1 << i);
|
||||
fall_delay |= BIT(i);
|
||||
}
|
||||
final_fall_delay = get_best_delay(host, fall_delay);
|
||||
|
||||
@ -2159,7 +2162,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
|
||||
msdc_set_data_delay(host, i);
|
||||
ret = mmc_send_tuning(mmc, opcode, NULL);
|
||||
if (!ret)
|
||||
rise_delay |= (1 << i);
|
||||
rise_delay |= BIT(i);
|
||||
}
|
||||
final_rise_delay = get_best_delay(host, rise_delay);
|
||||
/* if rising edge has enough margin, then do not scan falling edge */
|
||||
@ -2175,7 +2178,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
|
||||
msdc_set_data_delay(host, i);
|
||||
ret = mmc_send_tuning(mmc, opcode, NULL);
|
||||
if (!ret)
|
||||
fall_delay |= (1 << i);
|
||||
fall_delay |= BIT(i);
|
||||
}
|
||||
final_fall_delay = get_best_delay(host, fall_delay);
|
||||
|
||||
@ -2292,7 +2295,7 @@ static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card
|
||||
PAD_DS_TUNE_DLY1, i);
|
||||
ret = mmc_get_ext_csd(card, &ext_csd);
|
||||
if (!ret) {
|
||||
result_dly1 |= (1 << i);
|
||||
result_dly1 |= BIT(i);
|
||||
kfree(ext_csd);
|
||||
}
|
||||
}
|
||||
@ -2516,7 +2519,20 @@ static int msdc_of_clock_parse(struct platform_device *pdev,
|
||||
/*source clock control gate is optional clock*/
|
||||
host->src_clk_cg = devm_clk_get_optional(&pdev->dev, "source_cg");
|
||||
if (IS_ERR(host->src_clk_cg))
|
||||
host->src_clk_cg = NULL;
|
||||
return PTR_ERR(host->src_clk_cg);
|
||||
|
||||
/*
|
||||
* Fallback for legacy device-trees: src_clk and HCLK use the same
|
||||
* bit to control gating but they are parented to a different mux,
|
||||
* hence if our intention is to gate only the source, required
|
||||
* during a clk mode switch to avoid hw hangs, we need to gate
|
||||
* its parent (specified as a different clock only on new DTs).
|
||||
*/
|
||||
if (!host->src_clk_cg) {
|
||||
host->src_clk_cg = clk_get_parent(host->src_clk);
|
||||
if (IS_ERR(host->src_clk_cg))
|
||||
return PTR_ERR(host->src_clk_cg);
|
||||
}
|
||||
|
||||
host->sys_clk_cg = devm_clk_get_optional(&pdev->dev, "sys_cg");
|
||||
if (IS_ERR(host->sys_clk_cg))
|
||||
@ -2674,7 +2690,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&host->lock);
|
||||
|
||||
platform_set_drvdata(pdev, mmc);
|
||||
msdc_ungate_clock(host);
|
||||
ret = msdc_ungate_clock(host);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Cannot ungate clocks!\n");
|
||||
goto release_mem;
|
||||
}
|
||||
msdc_init_hw(host);
|
||||
|
||||
if (mmc->caps2 & MMC_CAP2_CQE) {
|
||||
@ -2833,8 +2853,12 @@ static int __maybe_unused msdc_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
int ret;
|
||||
|
||||
ret = msdc_ungate_clock(host);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msdc_ungate_clock(host);
|
||||
msdc_restore_reg(host);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1499,41 +1499,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
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)
|
||||
{
|
||||
struct omap_hsmmc_host *host = mmc_priv(mmc);
|
||||
@ -1660,7 +1625,6 @@ static struct mmc_host_ops omap_hsmmc_ops = {
|
||||
.set_ios = omap_hsmmc_set_ios,
|
||||
.get_cd = mmc_gpio_get_cd,
|
||||
.get_ro = mmc_gpio_get_ro,
|
||||
.init_card = omap_hsmmc_init_card,
|
||||
.enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
|
||||
};
|
||||
|
||||
|
@ -305,6 +305,9 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = {
|
||||
| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
|
||||
| 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 = {
|
||||
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
|
||||
@ -355,6 +358,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, },
|
||||
{ .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_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, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
@ -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, LKF_EMMC, intel_glk_emmc),
|
||||
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, 8220, o2),
|
||||
SDHCI_PCI_DEVICE(O2, 8221, o2),
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include "sdhci.h"
|
||||
#include "sdhci-pci.h"
|
||||
#include "cqhci.h"
|
||||
@ -116,6 +117,8 @@
|
||||
#define PCI_GLI_9755_PECONF 0x44
|
||||
#define PCI_GLI_9755_LFCLK GENMASK(14, 12)
|
||||
#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_L1DLY GENMASK(28, 24)
|
||||
@ -570,6 +573,14 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
|
||||
gl9755_wt_on(pdev);
|
||||
|
||||
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_DMACLK;
|
||||
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)
|
||||
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 = {
|
||||
.read_w = sdhci_gli_readw,
|
||||
.read_b = sdhci_gli_readb,
|
||||
.set_clock = sdhci_gl9755_set_clock,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
@ -911,6 +943,8 @@ const struct sdhci_pci_fixes sdhci_gl9755 = {
|
||||
};
|
||||
|
||||
static const struct sdhci_ops sdhci_gl9750_ops = {
|
||||
.read_w = sdhci_gli_readw,
|
||||
.read_b = sdhci_gli_readb,
|
||||
.read_l = sdhci_gl9750_readl,
|
||||
.set_clock = sdhci_gl9750_set_clock,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
#include "sdhci.h"
|
||||
#include "sdhci-pci.h"
|
||||
@ -43,12 +44,16 @@
|
||||
#define O2_SD_CAP_REG0 0x334
|
||||
#define O2_SD_UHS1_CAP_SETTING 0x33C
|
||||
#define O2_SD_DELAY_CTRL 0x350
|
||||
#define O2_SD_OUTPUT_CLK_SOURCE_SWITCH 0x354
|
||||
#define O2_SD_UHS2_L1_CTRL 0x35C
|
||||
#define O2_SD_FUNC_REG3 0x3E0
|
||||
#define O2_SD_FUNC_REG4 0x3E4
|
||||
#define O2_SD_LED_ENABLE BIT(6)
|
||||
#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_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_SETTING2 0x1C8
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
u32 scratch32 = 0;
|
||||
u16 scratch = 0;
|
||||
u8 scratch_8 = 0;
|
||||
u32 reg_val;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
scratch |= O2_SD_PWR_FORCE_L0;
|
||||
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, ®_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 */
|
||||
if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host,
|
||||
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)
|
||||
if (clock == 0)
|
||||
return;
|
||||
|
||||
/* UnLock WP */
|
||||
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
|
||||
scratch &= 0x7f;
|
||||
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
|
||||
|
||||
if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) {
|
||||
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
|
||||
|
||||
scratch &= 0x7f;
|
||||
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
|
||||
|
||||
pci_read_config_dword(chip->pdev, O2_SD_PLL_SETTING, &scratch_32);
|
||||
|
||||
if ((scratch_32 & 0xFFFF0000) != 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);
|
||||
|
||||
scratch |= 0x80;
|
||||
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
|
||||
if ((scratch_32 & 0xFFFF0000) != 0x25100000)
|
||||
o2_pci_set_baseclk(chip, 0x25100000);
|
||||
}
|
||||
|
||||
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);
|
||||
sdhci_o2_enable_clk(host, clk);
|
||||
}
|
||||
|
@ -59,6 +59,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_JSL_SD 0x4df8
|
||||
#define PCI_DEVICE_ID_INTEL_LKF_EMMC 0x98c4
|
||||
#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_VIA_95D0 0x95d0
|
||||
|
@ -960,14 +960,8 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
case MMC_POWER_OFF:
|
||||
tmio_mmc_power_off(host);
|
||||
/* For R-Car Gen2+, we need to reset SDHI specific SCC */
|
||||
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) {
|
||||
host->reset(host);
|
||||
|
||||
if (host->native_hotplug)
|
||||
tmio_mmc_enable_mmc_irqs(host,
|
||||
TMIO_STAT_CARD_REMOVE |
|
||||
TMIO_STAT_CARD_INSERT);
|
||||
}
|
||||
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
|
||||
tmio_mmc_reset(host);
|
||||
|
||||
host->set_clock(host, 0);
|
||||
break;
|
||||
@ -1175,6 +1169,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
|
||||
if (mmc_can_gpio_cd(mmc))
|
||||
_host->ops.get_cd = mmc_gpio_get_cd;
|
||||
|
||||
/* must be set before tmio_mmc_reset() */
|
||||
_host->native_hotplug = !(mmc_can_gpio_cd(mmc) ||
|
||||
mmc->caps & MMC_CAP_NEEDS_POLL ||
|
||||
!mmc_card_is_removable(mmc));
|
||||
@ -1295,10 +1290,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
|
||||
if (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);
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user