mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-07 14:32:23 +00:00
MMC core:
- Add a new host cap bit and a corresponding DT property, to support power cycling of the card by FW at system suspend/resume. - Fix clock rate setting for SDIO in SDR12/SDR25 speed-mode - Fix switch to 1/4-bit mode at system suspend/resume for SD-combo cards - Convert the mmc-pwrseq DT bindings to the json-schema - Always allow the card detect uevent to be consumed by userspace MMC host: - Convert a few DT bindings to the json-schema - mtk-sd: Add support for command queue through cqhci - mtk-sd: Add support for the MT6779 variant - renesas_sdhi_internal_dmac: Fix dma unmapping in the error path - sdhci_am654: Add support for the AM65x PG2.0 variant - sdhci_am654: Extend support for phys/clocks - sdhci-cadence: Drop incorrect HW tuning for SD mode - sdhci-msm: Add support for interconnect bandwidth scaling - sdhci-msm: Enable internal voltage control - sdhci-msm: Enable low power state for pinctrls - sdhci-of-at91: Ludovic Desroches handovers maintenance to Eugen Hristev - sdhci-pci-gli: Improve clock handling for GL975x - sdhci-pci-o2micro: Add HW tuning for SDR104 mode - sdhci-pci-o2micro: Fix support for O2 host controller Seabird1 -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAl8qX5kXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCkaURAAwjmHPGx+bc8By0y6FRDrm67S e1WFLTaFf6NuyjhxJRndmEvNUQIbvJVQ5NNBvzsmXzFC5BWQnAcmf3OATvTbTJ5B KSMf6ZqaZXDDlrSxve6l10e0/7cI+jb9LsEkPkV2Xk7Cr5Gx+/7+2UPRqtSr4WPE eMKGBOZYw3R2TaVB3qmf3Icj9IEhMJiou1NxTmR0370+SD8dtV2SwV42lMVuM9N5 Re4u3BhLaej970mKJxSZUAmtKKPzVkvHAUe2lzPwrPS4a7pzj3naWLyJsdhiclIq pwzyUYysRzIX4t/AbkyFfeBvR+E4mxmQciRilnJy4rZY7csSdYsvg0jZS30UANMn 21REkHlpE/7gfVx+pX8Q+Q/4XirJuL1jJJglWEoWqrx+sdpMnIa7NXowLmknG5vM fz2wS9cIfI82XK/ISzTRe6WWK3B/JftDLfNTQCDu2StE4Dr32Qjmt1ijtiJiSBTx +fCfKHWhmVaww5oFZ6RBCP1vdc4GW9SQvvj10O1QiRDiFXYASGxq7wrf6GLNwECn h7z5imBgSQrAdqyxAmX7E7R1g7Xv/jnqEAxxqtv3oA82RbmARe3lIQhnjemmtzU6 yD2qboc5cHdp7D2AB4TaN5qqFbrqMxLyRMknPnukAf2MwouGkiuBGG3mxRpy1Bpo MZBNyieX2erDT4hZDI8= =AwwR -----END PGP SIGNATURE----- Merge tag 'mmc-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC updates from Ulf Hansson: "MMC core: - Add a new host cap bit and a corresponding DT property, to support power cycling of the card by FW at system suspend/resume. - Fix clock rate setting for SDIO in SDR12/SDR25 speed-mode - Fix switch to 1/4-bit mode at system suspend/resume for SD-combo cards - Convert the mmc-pwrseq DT bindings to the json-schema - Always allow the card detect uevent to be consumed by userspace MMC host controllers: - Convert a few DT bindings to the json-schema - mtk-sd: - Add support for command queue through cqhci - Add support for the MT6779 variant - renesas_sdhi_internal_dmac: - Fix dma unmapping in the error path - sdhci_am654: - Add support for the AM65x PG2.0 variant - Extend support for phys/clocks - sdhci-cadence: - Drop incorrect HW tuning for SD mode - sdhci-msm: - Add support for interconnect bandwidth scaling - Enable internal voltage control - Enable low power state for pinctrls - sdhci-of-at91: - Ludovic Desroches handovers maintenance to Eugen Hristev - sdhci-pci-gli: - Improve clock handling for GL975x - sdhci-pci-o2micro: - Add HW tuning for SDR104 mode - Fix support for O2 host controller Seabird1" * tag 'mmc-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (66 commits) mmc: mediatek: make function msdc_cqe_disable() static MAINTAINERS: mmc: sdhci-of-at91: handover maintenance to Eugen Hristev dt-bindings: mmc: mediatek: Add document for mt6779 mmc: mediatek: command queue support mmc: mediatek: refine msdc timeout api mmc: mediatek: add MT6779 MMC driver support mmc: sdhci-pci-o2micro: Add HW tuning for SDR104 mode mmc: sdhci-pci-o2micro: Bug fix for O2 host controller Seabird1 mmc: via-sdmmc: use generic power management memstick: jmb38x_ms: use generic power management mmc: sdhci-cadence: do not use hardware tuning for SD mode mmc: sdhci-pci-gli: Set SDR104's clock to 205MHz and enable SSC for GL975x mmc: cqhci: Fix a print format for the task descriptor mmc: sdhci-of-arasan: fix timings allocation code mmc: sdhci: Fix a potential uninitialized variable dt-bindings: mmc: renesas,sdhi: convert to YAML dt-bindings: mmc: convert arasan sdhci bindings to yaml mmc: sdhci: Fix potential null pointer access while accessing vqmmc mmc: core: Add MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND dt-bindings: mmc: Add full-pwr-cycle-in-suspend property ...
This commit is contained in:
commit
8f7be62915
@ -1,192 +0,0 @@
|
||||
Device Tree Bindings for the Arasan SDHCI Controller
|
||||
|
||||
The bindings follow the mmc[1], clock[2], interrupt[3] and phy[4] bindings.
|
||||
Only deviations are documented here.
|
||||
|
||||
[1] Documentation/devicetree/bindings/mmc/mmc.txt
|
||||
[2] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
[4] Documentation/devicetree/bindings/phy/phy-bindings.txt
|
||||
|
||||
Required Properties:
|
||||
- compatible: Compatibility string. One of:
|
||||
- "arasan,sdhci-8.9a": generic Arasan SDHCI 8.9a PHY
|
||||
- "arasan,sdhci-4.9a": generic Arasan SDHCI 4.9a PHY
|
||||
- "arasan,sdhci-5.1": generic Arasan SDHCI 5.1 PHY
|
||||
- "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY
|
||||
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
|
||||
- "xlnx,zynqmp-8.9a": ZynqMP SDHCI 8.9a PHY
|
||||
For this device it is strongly suggested to include clock-output-names and
|
||||
#clock-cells.
|
||||
- "xlnx,versal-8.9a": Versal SDHCI 8.9a PHY
|
||||
For this device it is strongly suggested to include clock-output-names and
|
||||
#clock-cells.
|
||||
- "ti,am654-sdhci-5.1", "arasan,sdhci-5.1": TI AM654 MMC PHY
|
||||
Note: This binding has been deprecated and moved to [5].
|
||||
- "intel,lgm-sdhci-5.1-emmc", "arasan,sdhci-5.1": Intel LGM eMMC PHY
|
||||
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
|
||||
- "intel,lgm-sdhci-5.1-sdxc", "arasan,sdhci-5.1": Intel LGM SDXC PHY
|
||||
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
|
||||
- "intel,keembay-sdhci-5.1-emmc", "arasan,sdhci-5.1": Intel Keem Bay eMMC
|
||||
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
|
||||
- "intel,keembay-sdhci-5.1-sd": Intel Keem Bay SD controller
|
||||
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
|
||||
- "intel,keembay-sdhci-5.1-sdio": Intel Keem Bay SDIO controller
|
||||
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
|
||||
|
||||
[5] Documentation/devicetree/bindings/mmc/sdhci-am654.txt
|
||||
|
||||
- reg: From mmc bindings: Register location and length.
|
||||
- clocks: From clock bindings: Handles to clock inputs.
|
||||
- clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
|
||||
- interrupts: Interrupt specifier
|
||||
|
||||
Required Properties for "arasan,sdhci-5.1":
|
||||
- phys: From PHY bindings: Phandle for the Generic PHY for arasan.
|
||||
- phy-names: MUST be "phy_arasan".
|
||||
|
||||
Optional Properties:
|
||||
- arasan,soc-ctl-syscon: A phandle to a syscon device (see ../mfd/syscon.txt)
|
||||
used to access core corecfg registers. Offsets of registers in this
|
||||
syscon are determined based on the main compatible string for the device.
|
||||
- clock-output-names: If specified, this will be the name of the card clock
|
||||
which will be exposed by this device. Required if #clock-cells is
|
||||
specified.
|
||||
- #clock-cells: If specified this should be the value <0> or <1>. With this
|
||||
property in place we will export one or two clocks representing the Card
|
||||
Clock. These clocks are expected to be consumed by our PHY.
|
||||
- xlnx,fails-without-test-cd: when present, the controller doesn't work when
|
||||
the CD line is not connected properly, and the line is not connected
|
||||
properly. Test mode can be used to force the controller to function.
|
||||
- xlnx,int-clock-stable-broken: when present, the controller always reports
|
||||
that the internal clock is stable even when it is not.
|
||||
|
||||
- xlnx,mio-bank: When specified, this will indicate the MIO bank number in
|
||||
which the command and data lines are configured. If not specified, driver
|
||||
will assume this as 0.
|
||||
|
||||
Example:
|
||||
sdhci@e0100000 {
|
||||
compatible = "arasan,sdhci-8.9a";
|
||||
reg = <0xe0100000 0x1000>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&clkc 21>, <&clkc 32>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 24 4>;
|
||||
} ;
|
||||
|
||||
sdhci@e2800000 {
|
||||
compatible = "arasan,sdhci-5.1";
|
||||
reg = <0xe2800000 0x1000>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&cru 8>, <&cru 18>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 24 4>;
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
} ;
|
||||
|
||||
sdhci: sdhci@fe330000 {
|
||||
compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
|
||||
reg = <0x0 0xfe330000 0x0 0x10000>;
|
||||
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
arasan,soc-ctl-syscon = <&grf>;
|
||||
assigned-clocks = <&cru SCLK_EMMC>;
|
||||
assigned-clock-rates = <200000000>;
|
||||
clock-output-names = "emmc_cardclock";
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
sdhci: mmc@ff160000 {
|
||||
compatible = "xlnx,zynqmp-8.9a", "arasan,sdhci-8.9a";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 48 4>;
|
||||
reg = <0x0 0xff160000 0x0 0x1000>;
|
||||
clocks = <&clk200>, <&clk200>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clock-output-names = "clk_out_sd0", "clk_in_sd0";
|
||||
#clock-cells = <1>;
|
||||
clk-phase-sd-hs = <63>, <72>;
|
||||
};
|
||||
|
||||
sdhci: mmc@f1040000 {
|
||||
compatible = "xlnx,versal-8.9a", "arasan,sdhci-8.9a";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 126 4>;
|
||||
reg = <0x0 0xf1040000 0x0 0x10000>;
|
||||
clocks = <&clk200>, <&clk200>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clock-output-names = "clk_out_sd0", "clk_in_sd0";
|
||||
#clock-cells = <1>;
|
||||
clk-phase-sd-hs = <132>, <60>;
|
||||
};
|
||||
|
||||
emmc: sdhci@ec700000 {
|
||||
compatible = "intel,lgm-sdhci-5.1-emmc", "arasan,sdhci-5.1";
|
||||
reg = <0xec700000 0x300>;
|
||||
interrupt-parent = <&ioapic1>;
|
||||
interrupts = <44 1>;
|
||||
clocks = <&cgu0 LGM_CLK_EMMC5>, <&cgu0 LGM_CLK_NGI>,
|
||||
<&cgu0 LGM_GCLK_EMMC>;
|
||||
clock-names = "clk_xin", "clk_ahb", "gate";
|
||||
clock-output-names = "emmc_cardclock";
|
||||
#clock-cells = <0>;
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
arasan,soc-ctl-syscon = <&sysconf>;
|
||||
};
|
||||
|
||||
sdxc: sdhci@ec600000 {
|
||||
compatible = "arasan,sdhci-5.1", "intel,lgm-sdhci-5.1-sdxc";
|
||||
reg = <0xec600000 0x300>;
|
||||
interrupt-parent = <&ioapic1>;
|
||||
interrupts = <43 1>;
|
||||
clocks = <&cgu0 LGM_CLK_SDIO>, <&cgu0 LGM_CLK_NGI>,
|
||||
<&cgu0 LGM_GCLK_SDXC>;
|
||||
clock-names = "clk_xin", "clk_ahb", "gate";
|
||||
clock-output-names = "sdxc_cardclock";
|
||||
#clock-cells = <0>;
|
||||
phys = <&sdxc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
arasan,soc-ctl-syscon = <&sysconf>;
|
||||
};
|
||||
|
||||
mmc: mmc@33000000 {
|
||||
compatible = "intel,keembay-sdhci-5.1-emmc", "arasan,sdhci-5.1";
|
||||
interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg = <0x0 0x33000000 0x0 0x300>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&scmi_clk KEEM_BAY_PSS_AUX_EMMC>,
|
||||
<&scmi_clk KEEM_BAY_PSS_EMMC>;
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
assigned-clocks = <&scmi_clk KEEM_BAY_PSS_AUX_EMMC>;
|
||||
assigned-clock-rates = <200000000>;
|
||||
clock-output-names = "emmc_cardclock";
|
||||
#clock-cells = <0>;
|
||||
arasan,soc-ctl-syscon = <&mmc_phy_syscon>;
|
||||
};
|
||||
|
||||
sd0: mmc@31000000 {
|
||||
compatible = "intel,keembay-sdhci-5.1-sd";
|
||||
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg = <0x0 0x31000000 0x0 0x300>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&scmi_clk KEEM_BAY_PSS_AUX_SD0>,
|
||||
<&scmi_clk KEEM_BAY_PSS_SD0>;
|
||||
arasan,soc-ctl-syscon = <&sd0_phy_syscon>;
|
||||
};
|
||||
|
||||
sd1: mmc@32000000 {
|
||||
compatible = "intel,keembay-sdhci-5.1-sdio";
|
||||
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg = <0x0 0x32000000 0x0 0x300>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&scmi_clk KEEM_BAY_PSS_AUX_SD1>,
|
||||
<&scmi_clk KEEM_BAY_PSS_SD1>;
|
||||
arasan,soc-ctl-syscon = <&sd1_phy_syscon>;
|
||||
};
|
299
Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
Normal file
299
Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
Normal file
@ -0,0 +1,299 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/mmc/arasan,sdhci.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Device Tree Bindings for the Arasan SDHCI Controller
|
||||
|
||||
maintainers:
|
||||
- Adrian Hunter <adrian.hunter@intel.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "mmc-controller.yaml#"
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: arasan,sdhci-5.1
|
||||
then:
|
||||
required:
|
||||
- phys
|
||||
- phy-names
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- xlnx,zynqmp-8.9a
|
||||
- xlnx,versal-8.9a
|
||||
then:
|
||||
properties:
|
||||
clock-output-names:
|
||||
items:
|
||||
- const: clk_out_sd0
|
||||
- const: clk_in_sd0
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: arasan,sdhci-8.9a # generic Arasan SDHCI 8.9a PHY
|
||||
- const: arasan,sdhci-4.9a # generic Arasan SDHCI 4.9a PHY
|
||||
- const: arasan,sdhci-5.1 # generic Arasan SDHCI 5.1 PHY
|
||||
- items:
|
||||
- const: rockchip,rk3399-sdhci-5.1 # rk3399 eMMC PHY
|
||||
- const: arasan,sdhci-5.1
|
||||
description:
|
||||
For this device it is strongly suggested to include
|
||||
arasan,soc-ctl-syscon.
|
||||
- items:
|
||||
- const: xlnx,zynqmp-8.9a # ZynqMP SDHCI 8.9a PHY
|
||||
- const: arasan,sdhci-8.9a
|
||||
description:
|
||||
For this device it is strongly suggested to include
|
||||
clock-output-names and '#clock-cells'.
|
||||
- items:
|
||||
- const: xlnx,versal-8.9a # Versal SDHCI 8.9a PHY
|
||||
- const: arasan,sdhci-8.9a
|
||||
description:
|
||||
For this device it is strongly suggested to include
|
||||
clock-output-names and '#clock-cells'.
|
||||
- items:
|
||||
- const: intel,lgm-sdhci-5.1-emmc # Intel LGM eMMC PHY
|
||||
- const: arasan,sdhci-5.1
|
||||
description:
|
||||
For this device it is strongly suggested to include
|
||||
arasan,soc-ctl-syscon.
|
||||
- items:
|
||||
- const: intel,lgm-sdhci-5.1-sdxc # Intel LGM SDXC PHY
|
||||
- const: arasan,sdhci-5.1
|
||||
description:
|
||||
For this device it is strongly suggested to include
|
||||
arasan,soc-ctl-syscon.
|
||||
- items:
|
||||
- const: intel,keembay-sdhci-5.1-emmc # Intel Keem Bay eMMC PHY
|
||||
- const: arasan,sdhci-5.1
|
||||
description:
|
||||
For this device it is strongly suggested to include
|
||||
arasan,soc-ctl-syscon.
|
||||
- const: intel,keembay-sdhci-5.1-sd # Intel Keem Bay SD controller
|
||||
description:
|
||||
For this device it is strongly suggested to include
|
||||
arasan,soc-ctl-syscon.
|
||||
- const: intel,keembay-sdhci-5.1-sdio # Intel Keem Bay SDIO controller
|
||||
description:
|
||||
For this device it is strongly suggested to include
|
||||
arasan,soc-ctl-syscon.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: clk_xin
|
||||
- const: clk_ahb
|
||||
- const: gate
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
const: phy_arasan
|
||||
|
||||
arasan,soc-ctl-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
A phandle to a syscon device (see ../mfd/syscon.txt) used to access
|
||||
core corecfg registers. Offsets of registers in this syscon are
|
||||
determined based on the main compatible string for the device.
|
||||
|
||||
clock-output-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description:
|
||||
Name of the card clock which will be exposed by this device.
|
||||
|
||||
'#clock-cells':
|
||||
enum: [0, 1]
|
||||
description:
|
||||
With this property in place we will export one or two clocks
|
||||
representing the Card Clock. These clocks are expected to be
|
||||
consumed by our PHY.
|
||||
|
||||
xlnx,fails-without-test-cd:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
When present, the controller doesn't work when the CD line is not
|
||||
connected properly, and the line is not connected properly.
|
||||
Test mode can be used to force the controller to function.
|
||||
|
||||
xlnx,int-clock-stable-broken:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
When present, the controller always reports that the internal clock
|
||||
is stable even when it is not.
|
||||
|
||||
xlnx,mio-bank:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 2]
|
||||
default: 0
|
||||
description:
|
||||
The MIO bank number in which the command and data lines are configured.
|
||||
|
||||
dependencies:
|
||||
clock-output-names: [ '#clock-cells' ]
|
||||
'#clock-cells': [ clock-output-names ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mmc@e0100000 {
|
||||
compatible = "arasan,sdhci-8.9a";
|
||||
reg = <0xe0100000 0x1000>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&clkc 21>, <&clkc 32>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 24 4>;
|
||||
};
|
||||
|
||||
- |
|
||||
mmc@e2800000 {
|
||||
compatible = "arasan,sdhci-5.1";
|
||||
reg = <0xe2800000 0x1000>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&cru 8>, <&cru 18>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 24 4>;
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/clock/rk3399-cru.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
mmc@fe330000 {
|
||||
compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
|
||||
reg = <0xfe330000 0x10000>;
|
||||
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
arasan,soc-ctl-syscon = <&grf>;
|
||||
assigned-clocks = <&cru SCLK_EMMC>;
|
||||
assigned-clock-rates = <200000000>;
|
||||
clock-output-names = "emmc_cardclock";
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
- |
|
||||
mmc@ff160000 {
|
||||
compatible = "xlnx,zynqmp-8.9a", "arasan,sdhci-8.9a";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 48 4>;
|
||||
reg = <0xff160000 0x1000>;
|
||||
clocks = <&clk200>, <&clk200>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clock-output-names = "clk_out_sd0", "clk_in_sd0";
|
||||
#clock-cells = <1>;
|
||||
clk-phase-sd-hs = <63>, <72>;
|
||||
};
|
||||
|
||||
- |
|
||||
mmc@f1040000 {
|
||||
compatible = "xlnx,versal-8.9a", "arasan,sdhci-8.9a";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 126 4>;
|
||||
reg = <0xf1040000 0x10000>;
|
||||
clocks = <&clk200>, <&clk200>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clock-output-names = "clk_out_sd0", "clk_in_sd0";
|
||||
#clock-cells = <1>;
|
||||
clk-phase-sd-hs = <132>, <60>;
|
||||
};
|
||||
|
||||
- |
|
||||
#define LGM_CLK_EMMC5
|
||||
#define LGM_CLK_NGI
|
||||
#define LGM_GCLK_EMMC
|
||||
mmc@ec700000 {
|
||||
compatible = "intel,lgm-sdhci-5.1-emmc", "arasan,sdhci-5.1";
|
||||
reg = <0xec700000 0x300>;
|
||||
interrupt-parent = <&ioapic1>;
|
||||
interrupts = <44 1>;
|
||||
clocks = <&cgu0 LGM_CLK_EMMC5>, <&cgu0 LGM_CLK_NGI>,
|
||||
<&cgu0 LGM_GCLK_EMMC>;
|
||||
clock-names = "clk_xin", "clk_ahb", "gate";
|
||||
clock-output-names = "emmc_cardclock";
|
||||
#clock-cells = <0>;
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
arasan,soc-ctl-syscon = <&sysconf>;
|
||||
};
|
||||
|
||||
- |
|
||||
#define LGM_CLK_SDIO
|
||||
#define LGM_GCLK_SDXC
|
||||
mmc@ec600000 {
|
||||
compatible = "intel,lgm-sdhci-5.1-sdxc", "arasan,sdhci-5.1";
|
||||
reg = <0xec600000 0x300>;
|
||||
interrupt-parent = <&ioapic1>;
|
||||
interrupts = <43 1>;
|
||||
clocks = <&cgu0 LGM_CLK_SDIO>, <&cgu0 LGM_CLK_NGI>,
|
||||
<&cgu0 LGM_GCLK_SDXC>;
|
||||
clock-names = "clk_xin", "clk_ahb", "gate";
|
||||
clock-output-names = "sdxc_cardclock";
|
||||
#clock-cells = <0>;
|
||||
phys = <&sdxc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
arasan,soc-ctl-syscon = <&sysconf>;
|
||||
};
|
||||
|
||||
- |
|
||||
#define KEEM_BAY_PSS_AUX_EMMC
|
||||
#define KEEM_BAY_PSS_EMMC
|
||||
mmc@33000000 {
|
||||
compatible = "intel,keembay-sdhci-5.1-emmc", "arasan,sdhci-5.1";
|
||||
interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg = <0x33000000 0x300>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&scmi_clk KEEM_BAY_PSS_AUX_EMMC>,
|
||||
<&scmi_clk KEEM_BAY_PSS_EMMC>;
|
||||
phys = <&emmc_phy>;
|
||||
phy-names = "phy_arasan";
|
||||
assigned-clocks = <&scmi_clk KEEM_BAY_PSS_AUX_EMMC>;
|
||||
assigned-clock-rates = <200000000>;
|
||||
clock-output-names = "emmc_cardclock";
|
||||
#clock-cells = <0>;
|
||||
arasan,soc-ctl-syscon = <&mmc_phy_syscon>;
|
||||
};
|
||||
|
||||
- |
|
||||
#define KEEM_BAY_PSS_AUX_SD0
|
||||
#define KEEM_BAY_PSS_SD0
|
||||
mmc@31000000 {
|
||||
compatible = "intel,keembay-sdhci-5.1-sd";
|
||||
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg = <0x31000000 0x300>;
|
||||
clock-names = "clk_xin", "clk_ahb";
|
||||
clocks = <&scmi_clk KEEM_BAY_PSS_AUX_SD0>,
|
||||
<&scmi_clk KEEM_BAY_PSS_SD0>;
|
||||
arasan,soc-ctl-syscon = <&sd0_phy_syscon>;
|
||||
};
|
@ -169,6 +169,11 @@ properties:
|
||||
description:
|
||||
Full power cycle of the card is supported.
|
||||
|
||||
full-pwr-cycle-in-suspend:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Full power cycle of the card in suspend is supported.
|
||||
|
||||
mmc-ddr-1_2v:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
|
@ -1,25 +0,0 @@
|
||||
* The simple eMMC hardware reset provider
|
||||
|
||||
The purpose of this driver is to perform standard eMMC hw reset
|
||||
procedure, as described by Jedec 4.4 specification. This procedure is
|
||||
performed just after MMC core enabled power to the given mmc host (to
|
||||
fix possible issues if bootloader has left eMMC card in initialized or
|
||||
unknown state), and before performing complete system reboot (also in
|
||||
case of emergency reboot call). The latter is needed on boards, which
|
||||
doesn't have hardware reset logic connected to emmc card and (limited or
|
||||
broken) ROM bootloaders are unable to read second stage from the emmc
|
||||
card if the card is left in unknown or already initialized state.
|
||||
|
||||
Required properties:
|
||||
- compatible : contains "mmc-pwrseq-emmc".
|
||||
- reset-gpios : contains a GPIO specifier. The reset GPIO is asserted
|
||||
and then deasserted to perform eMMC card reset. To perform
|
||||
reset procedure as described in Jedec 4.4 specification, the
|
||||
gpio line should be defined as GPIO_ACTIVE_LOW.
|
||||
|
||||
Example:
|
||||
|
||||
sdhci0_pwrseq {
|
||||
compatible = "mmc-pwrseq-emmc";
|
||||
reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
|
||||
}
|
46
Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.yaml
Normal file
46
Documentation/devicetree/bindings/mmc/mmc-pwrseq-emmc.yaml
Normal file
@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/mmc-pwrseq-emmc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Simple eMMC hardware reset provider binding
|
||||
|
||||
maintainers:
|
||||
- Ulf Hansson <ulf.hansson@linaro.org>
|
||||
|
||||
description:
|
||||
The purpose of this driver is to perform standard eMMC hw reset
|
||||
procedure, as described by Jedec 4.4 specification. This procedure is
|
||||
performed just after MMC core enabled power to the given mmc host (to
|
||||
fix possible issues if bootloader has left eMMC card in initialized or
|
||||
unknown state), and before performing complete system reboot (also in
|
||||
case of emergency reboot call). The latter is needed on boards, which
|
||||
doesn't have hardware reset logic connected to emmc card and (limited or
|
||||
broken) ROM bootloaders are unable to read second stage from the emmc
|
||||
card if the card is left in unknown or already initialized state.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mmc-pwrseq-emmc
|
||||
|
||||
reset-gpios:
|
||||
minItems: 1
|
||||
description:
|
||||
contains a GPIO specifier. The reset GPIO is asserted
|
||||
and then deasserted to perform eMMC card reset. To perform
|
||||
reset procedure as described in Jedec 4.4 specification, the
|
||||
gpio line should be defined as GPIO_ACTIVE_LOW.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reset-gpios
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
sdhci0_pwrseq {
|
||||
compatible = "mmc-pwrseq-emmc";
|
||||
reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
...
|
@ -1,16 +0,0 @@
|
||||
* Marvell SD8787 power sequence provider
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "mmc-pwrseq-sd8787".
|
||||
- powerdown-gpios: contains a power down GPIO specifier with the
|
||||
default active state
|
||||
- reset-gpios: contains a reset GPIO specifier with the default
|
||||
active state
|
||||
|
||||
Example:
|
||||
|
||||
wifi_pwrseq: wifi_pwrseq {
|
||||
compatible = "mmc-pwrseq-sd8787";
|
||||
powerdown-gpios = <&twl_gpio 0 GPIO_ACTIVE_LOW>;
|
||||
reset-gpios = <&twl_gpio 1 GPIO_ACTIVE_LOW>;
|
||||
}
|
39
Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.yaml
Normal file
39
Documentation/devicetree/bindings/mmc/mmc-pwrseq-sd8787.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/mmc-pwrseq-sd8787.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Marvell SD8787 power sequence provider binding
|
||||
|
||||
maintainers:
|
||||
- Ulf Hansson <ulf.hansson@linaro.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mmc-pwrseq-sd8787
|
||||
|
||||
powerdown-gpios:
|
||||
minItems: 1
|
||||
description:
|
||||
contains a power down GPIO specifier with the default active state
|
||||
|
||||
reset-gpios:
|
||||
minItems: 1
|
||||
description:
|
||||
contains a reset GPIO specifier with the default active state
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- powerdown-gpios
|
||||
- reset-gpios
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
wifi_pwrseq: wifi_pwrseq {
|
||||
compatible = "mmc-pwrseq-sd8787";
|
||||
powerdown-gpios = <&twl_gpio 0 GPIO_ACTIVE_LOW>;
|
||||
reset-gpios = <&twl_gpio 1 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
...
|
@ -1,31 +0,0 @@
|
||||
* The simple MMC power sequence provider
|
||||
|
||||
The purpose of the simple MMC power sequence provider is to supports a set of
|
||||
common properties between various SOC designs. It thus enables us to use the
|
||||
same provider for several SOC designs.
|
||||
|
||||
Required properties:
|
||||
- compatible : contains "mmc-pwrseq-simple".
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios : contains a list of GPIO specifiers. The reset GPIOs are asserted
|
||||
at initialization and prior we start the power up procedure of the card.
|
||||
They will be de-asserted right after the power has been provided to the
|
||||
card.
|
||||
- clocks : Must contain an entry for the entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names : Must include the following entry:
|
||||
"ext_clock" (External clock provided to the card).
|
||||
- post-power-on-delay-ms : Delay in ms after powering the card and
|
||||
de-asserting the reset-gpios (if any)
|
||||
- power-off-delay-us : Delay in us after asserting the reset-gpios (if any)
|
||||
during power off of the card.
|
||||
|
||||
Example:
|
||||
|
||||
sdhci0_pwrseq {
|
||||
compatible = "mmc-pwrseq-simple";
|
||||
reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
|
||||
clocks = <&clk_32768_ck>;
|
||||
clock-names = "ext_clock";
|
||||
}
|
62
Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.yaml
Normal file
62
Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.yaml
Normal file
@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/mmc-pwrseq-simple.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Simple MMC power sequence provider binding
|
||||
|
||||
maintainers:
|
||||
- Ulf Hansson <ulf.hansson@linaro.org>
|
||||
|
||||
description:
|
||||
The purpose of the simple MMC power sequence provider is to supports a set
|
||||
of common properties between various SOC designs. It thus enables us to use
|
||||
the same provider for several SOC designs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mmc-pwrseq-simple
|
||||
|
||||
reset-gpios:
|
||||
minItems: 1
|
||||
description:
|
||||
contains a list of GPIO specifiers. The reset GPIOs are asserted
|
||||
at initialization and prior we start the power up procedure of the card.
|
||||
They will be de-asserted right after the power has been provided to the
|
||||
card.
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
description: Handle for the entry in clock-names.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ext_clock
|
||||
description: External clock provided to the card.
|
||||
|
||||
post-power-on-delay-ms:
|
||||
description:
|
||||
Delay in ms after powering the card and de-asserting the
|
||||
reset-gpios (if any).
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
power-off-delay-us:
|
||||
description:
|
||||
Delay in us after asserting the reset-gpios (if any)
|
||||
during power off of the card.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
sdhci0_pwrseq {
|
||||
compatible = "mmc-pwrseq-simple";
|
||||
reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
|
||||
clocks = <&clk_32768_ck>;
|
||||
clock-names = "ext_clock";
|
||||
};
|
||||
...
|
@ -12,6 +12,7 @@ Required properties:
|
||||
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
|
||||
"mediatek,mt8183-mmc": for mmc host ip compatible with mt8183
|
||||
"mediatek,mt8516-mmc": for mmc host ip compatible with mt8516
|
||||
"mediatek,mt6779-mmc": for mmc host ip compatible with mt6779
|
||||
"mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
|
||||
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
|
||||
"mediatek,mt7622-mmc": for MT7622 SoC
|
||||
|
@ -1,114 +0,0 @@
|
||||
* Renesas SDHI SD/MMC controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should contain one or more of the following:
|
||||
"renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
|
||||
"renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
|
||||
"renesas,sdhi-r7s9210" - SDHI IP on R7S9210 SoC
|
||||
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
|
||||
"renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
|
||||
"renesas,sdhi-r8a7742" - SDHI IP on R8A7742 SoC
|
||||
"renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC
|
||||
"renesas,sdhi-r8a7744" - SDHI IP on R8A7744 SoC
|
||||
"renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC
|
||||
"renesas,sdhi-r8a774a1" - SDHI IP on R8A774A1 SoC
|
||||
"renesas,sdhi-r8a774b1" - SDHI IP on R8A774B1 SoC
|
||||
"renesas,sdhi-r8a774c0" - SDHI IP on R8A774C0 SoC
|
||||
"renesas,sdhi-r8a77470" - SDHI IP on R8A77470 SoC
|
||||
"renesas,sdhi-mmc-r8a77470" - SDHI/MMC IP on R8A77470 SoC
|
||||
"renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
|
||||
"renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
|
||||
"renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
|
||||
"renesas,sdhi-r8a7791" - SDHI IP on R8A7791 SoC
|
||||
"renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC
|
||||
"renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
|
||||
"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
|
||||
"renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
|
||||
"renesas,sdhi-r8a7796" - SDHI IP on R8A77960 SoC
|
||||
"renesas,sdhi-r8a77961" - SDHI IP on R8A77961 SoC
|
||||
"renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC
|
||||
"renesas,sdhi-r8a77970" - SDHI IP on R8A77970 SoC
|
||||
"renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC
|
||||
"renesas,sdhi-r8a77990" - SDHI IP on R8A77990 SoC
|
||||
"renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC
|
||||
"renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
|
||||
"renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
|
||||
"renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 and RZ/G1 SDHI
|
||||
(not SDHI/MMC) controller
|
||||
"renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 or RZ/G2
|
||||
SDHI controller
|
||||
|
||||
|
||||
When compatible with the generic version, nodes must list
|
||||
the SoC-specific version corresponding to the platform
|
||||
first followed by the generic version.
|
||||
|
||||
- clocks: Most controllers only have 1 clock source per channel. However, on
|
||||
some variations of this controller, the internal card detection
|
||||
logic that exists in this controller is sectioned off to be run by a
|
||||
separate second clock source to allow the main core clock to be turned
|
||||
off to save power.
|
||||
If 2 clocks are specified by the hardware, you must name them as
|
||||
"core" and "cd". If the controller only has 1 clock, naming is not
|
||||
required.
|
||||
Devices which have more than 1 clock are listed below:
|
||||
2: R7S72100, R7S9210
|
||||
|
||||
Optional properties:
|
||||
- pinctrl-names: should be "default", "state_uhs"
|
||||
- pinctrl-0: should contain default/high speed pin ctrl
|
||||
- pinctrl-1: should contain uhs mode pin ctrl
|
||||
|
||||
Example: R8A7790 (R-Car H2) SDHI controller nodes
|
||||
|
||||
sdhi0: sd@ee100000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0 0xee100000 0 0x328>;
|
||||
interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 314>;
|
||||
dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
|
||||
<&dmac1 0xcd>, <&dmac1 0xce>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <195000000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 314>;
|
||||
};
|
||||
|
||||
sdhi1: sd@ee120000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0 0xee120000 0 0x328>;
|
||||
interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 313>;
|
||||
dmas = <&dmac0 0xc9>, <&dmac0 0xca>,
|
||||
<&dmac1 0xc9>, <&dmac1 0xca>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <195000000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 313>;
|
||||
};
|
||||
|
||||
sdhi2: sd@ee140000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0 0xee140000 0 0x100>;
|
||||
interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 312>;
|
||||
dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
|
||||
<&dmac1 0xc1>, <&dmac1 0xc2>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <97500000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 312>;
|
||||
};
|
||||
|
||||
sdhi3: sd@ee160000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0 0xee160000 0 0x100>;
|
||||
interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 311>;
|
||||
dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
|
||||
<&dmac1 0xd3>, <&dmac1 0xd4>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <97500000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 311>;
|
||||
};
|
191
Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml
Normal file
191
Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml
Normal file
@ -0,0 +1,191 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/mmc/renesas,sdhi.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Renesas SDHI SD/MMC controller
|
||||
|
||||
maintainers:
|
||||
- Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "mmc-controller.yaml"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: renesas,sdhi-sh73a0 # R-Mobile APE6
|
||||
- items:
|
||||
- const: renesas,sdhi-r7s72100 # RZ/A1H
|
||||
- items:
|
||||
- const: renesas,sdhi-r7s9210 # SH-Mobile AG5
|
||||
- items:
|
||||
- const: renesas,sdhi-r8a73a4 # R-Mobile APE6
|
||||
- items:
|
||||
- const: renesas,sdhi-r8a7740 # R-Mobile A1
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,sdhi-r8a7778 # R-Car M1
|
||||
- renesas,sdhi-r8a7779 # R-Car H1
|
||||
- const: renesas,rcar-gen1-sdhi # R-Car Gen1
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,sdhi-r8a7742 # RZ/G1H
|
||||
- renesas,sdhi-r8a7743 # RZ/G1M
|
||||
- renesas,sdhi-r8a7744 # RZ/G1N
|
||||
- renesas,sdhi-r8a7745 # RZ/G1E
|
||||
- renesas,sdhi-r8a77470 # RZ/G1C
|
||||
- renesas,sdhi-r8a7790 # R-Car H2
|
||||
- renesas,sdhi-r8a7791 # R-Car M2-W
|
||||
- renesas,sdhi-r8a7792 # R-Car V2H
|
||||
- renesas,sdhi-r8a7793 # R-Car M2-N
|
||||
- renesas,sdhi-r8a7794 # R-Car E2
|
||||
- const: renesas,rcar-gen2-sdhi # R-Car Gen2 and RZ/G1
|
||||
- items:
|
||||
- const: renesas,sdhi-mmc-r8a77470 # RZ/G1C (SDHI/MMC IP)
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,sdhi-r8a774a1 # RZ/G2M
|
||||
- renesas,sdhi-r8a774b1 # RZ/G2N
|
||||
- renesas,sdhi-r8a774c0 # RZ/G2E
|
||||
- renesas,sdhi-r8a7795 # R-Car H3
|
||||
- renesas,sdhi-r8a7796 # R-Car M3-W
|
||||
- renesas,sdhi-r8a77961 # R-Car M3-W+
|
||||
- renesas,sdhi-r8a77965 # R-Car M3-N
|
||||
- renesas,sdhi-r8a77970 # R-Car V3M
|
||||
- renesas,sdhi-r8a77980 # R-Car V3H
|
||||
- renesas,sdhi-r8a77990 # R-Car E3
|
||||
- renesas,sdhi-r8a77995 # R-Car D3
|
||||
- const: renesas,rcar-gen3-sdhi # R-Car Gen3 or RZ/G2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: core
|
||||
- const: cd
|
||||
|
||||
dmas:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
|
||||
dma-names:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
items:
|
||||
enum:
|
||||
- tx
|
||||
- rx
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
pinctrl-0:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
pinctrl-1:
|
||||
maxItems: 1
|
||||
|
||||
pinctrl-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: default
|
||||
- const: state_uhs
|
||||
|
||||
max-frequency: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- power-domains
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
enum:
|
||||
- renesas,sdhi-r7s72100
|
||||
- renesas,sdhi-r7s9210
|
||||
then:
|
||||
required:
|
||||
- clock-names
|
||||
description:
|
||||
The internal card detection logic that exists in these controllers is
|
||||
sectioned off to be run by a separate second clock source to allow
|
||||
the main core clock to be turned off to save power.
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7790-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a7790-sysc.h>
|
||||
|
||||
sdhi0: mmc@ee100000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0xee100000 0x328>;
|
||||
interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 314>;
|
||||
dmas = <&dmac0 0xcd>, <&dmac0 0xce>, <&dmac1 0xcd>, <&dmac1 0xce>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <195000000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 314>;
|
||||
};
|
||||
|
||||
sdhi1: mmc@ee120000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0xee120000 0x328>;
|
||||
interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 313>;
|
||||
dmas = <&dmac0 0xc9>, <&dmac0 0xca>, <&dmac1 0xc9>, <&dmac1 0xca>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <195000000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 313>;
|
||||
};
|
||||
|
||||
sdhi2: mmc@ee140000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0xee140000 0x100>;
|
||||
interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 312>;
|
||||
dmas = <&dmac0 0xc1>, <&dmac0 0xc2>, <&dmac1 0xc1>, <&dmac1 0xc2>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <97500000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 312>;
|
||||
};
|
||||
|
||||
sdhi3: mmc@ee160000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0xee160000 0x100>;
|
||||
interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 311>;
|
||||
dmas = <&dmac0 0xd3>, <&dmac0 0xd4>, <&dmac1 0xd3>, <&dmac1 0xd4>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <97500000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 311>;
|
||||
};
|
@ -39,6 +39,7 @@ Optional Properties (Required for ti,am654-sdhci-5.1 and ti,j721e-sdhci-8bit):
|
||||
Valid values are 33, 40, 50, 66 and 100 ohms.
|
||||
Optional Properties:
|
||||
- ti,strobe-sel: strobe select delay for HS400 speed mode. Default value: 0x0.
|
||||
- ti,clkbuf-sel: Clock Delay Buffer Select
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -54,6 +54,21 @@ Required properties:
|
||||
- qcom,dll-config: Chipset and Platform specific value. Use this field to
|
||||
specify the DLL_CONFIG register value as per Hardware Programming Guide.
|
||||
|
||||
Optional Properties:
|
||||
* Following bus parameters are required for interconnect bandwidth scaling:
|
||||
- interconnects: Pairs of phandles and interconnect provider specifier
|
||||
to denote the edge source and destination ports of
|
||||
the interconnect path.
|
||||
|
||||
- interconnect-names: For sdhc, we have two main paths.
|
||||
1. Data path : sdhc to ddr
|
||||
2. Config path : cpu to sdhc
|
||||
For Data interconnect path the name supposed to be
|
||||
is "sdhc-ddr" and for config interconnect path it is
|
||||
"cpu-sdhc".
|
||||
Please refer to Documentation/devicetree/bindings/
|
||||
interconnect/ for more details.
|
||||
|
||||
Example:
|
||||
|
||||
sdhc_1: sdhci@f9824900 {
|
||||
@ -71,6 +86,9 @@ Example:
|
||||
|
||||
clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>;
|
||||
clock-names = "core", "iface";
|
||||
interconnects = <&qnoc MASTER_SDCC_ID &qnoc SLAVE_DDR_ID>,
|
||||
<&qnoc MASTER_CPU_ID &qnoc SLAVE_SDCC_ID>;
|
||||
interconnect-names = "sdhc-ddr","cpu-sdhc";
|
||||
|
||||
qcom,dll-config = <0x000f642c>;
|
||||
qcom,ddr-config = <0x80040868>;
|
||||
|
@ -15383,7 +15383,7 @@ F: drivers/mmc/host/sdhci*
|
||||
F: include/linux/mmc/sdhci*
|
||||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
|
||||
M: Ludovic Desroches <ludovic.desroches@microchip.com>
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/mmc/host/sdhci-of-at91.c
|
||||
|
@ -16,7 +16,3 @@ static inline int omap_msdi_reset(struct omap_hwmod *oh)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* called from board-specific card detection service routine */
|
||||
extern void omap_mmc_notify_cover_event(struct device *dev, int slot,
|
||||
int is_closed);
|
||||
|
@ -793,11 +793,10 @@ static int jmb38x_ms_pmos(struct pci_dev *pdev, int flag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state)
|
||||
static int __maybe_unused jmb38x_ms_suspend(struct device *dev)
|
||||
{
|
||||
struct jmb38x_ms *jm = pci_get_drvdata(dev);
|
||||
struct jmb38x_ms *jm = dev_get_drvdata(dev);
|
||||
|
||||
int cnt;
|
||||
|
||||
for (cnt = 0; cnt < jm->host_cnt; ++cnt) {
|
||||
@ -806,26 +805,17 @@ static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state)
|
||||
memstick_suspend_host(jm->hosts[cnt]);
|
||||
}
|
||||
|
||||
pci_save_state(dev);
|
||||
pci_enable_wake(dev, pci_choose_state(dev, state), 0);
|
||||
pci_disable_device(dev);
|
||||
pci_set_power_state(dev, pci_choose_state(dev, state));
|
||||
device_wakeup_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jmb38x_ms_resume(struct pci_dev *dev)
|
||||
static int __maybe_unused jmb38x_ms_resume(struct device *dev)
|
||||
{
|
||||
struct jmb38x_ms *jm = pci_get_drvdata(dev);
|
||||
struct jmb38x_ms *jm = dev_get_drvdata(dev);
|
||||
int rc;
|
||||
|
||||
pci_set_power_state(dev, PCI_D0);
|
||||
pci_restore_state(dev);
|
||||
rc = pci_enable_device(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
pci_set_master(dev);
|
||||
|
||||
jmb38x_ms_pmos(dev, 1);
|
||||
jmb38x_ms_pmos(to_pci_dev(dev), 1);
|
||||
|
||||
for (rc = 0; rc < jm->host_cnt; ++rc) {
|
||||
if (!jm->hosts[rc])
|
||||
@ -837,13 +827,6 @@ static int jmb38x_ms_resume(struct pci_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define jmb38x_ms_suspend NULL
|
||||
#define jmb38x_ms_resume NULL
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static int jmb38x_ms_count_slots(struct pci_dev *pdev)
|
||||
{
|
||||
int cnt, rc = 0;
|
||||
@ -1030,13 +1013,14 @@ static struct pci_device_id jmb38x_ms_id_tbl [] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(jmb38x_ms_pm_ops, jmb38x_ms_suspend, jmb38x_ms_resume);
|
||||
|
||||
static struct pci_driver jmb38x_ms_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = jmb38x_ms_id_tbl,
|
||||
.probe = jmb38x_ms_probe,
|
||||
.remove = jmb38x_ms_remove,
|
||||
.suspend = jmb38x_ms_suspend,
|
||||
.resume = jmb38x_ms_resume
|
||||
.driver.pm = &jmb38x_ms_pm_ops,
|
||||
};
|
||||
|
||||
module_pci_driver(jmb38x_ms_driver);
|
||||
|
@ -1455,12 +1455,12 @@ void mmc_detach_bus(struct mmc_host *host)
|
||||
void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq)
|
||||
{
|
||||
/*
|
||||
* If the device is configured as wakeup, we prevent a new sleep for
|
||||
* 5 s to give provision for user space to consume the event.
|
||||
* Prevent system sleep for 5s to allow user space to consume the
|
||||
* corresponding uevent. This is especially useful, when CD irq is used
|
||||
* as a system wakeup, but doesn't hurt in other cases.
|
||||
*/
|
||||
if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
|
||||
device_can_wakeup(mmc_dev(host)))
|
||||
pm_wakeup_event(mmc_dev(host), 5000);
|
||||
if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL))
|
||||
__pm_wakeup_event(host->ws, 5000);
|
||||
|
||||
host->detect_change = 1;
|
||||
mmc_schedule_delayed_work(&host->detect, delay);
|
||||
@ -2303,7 +2303,6 @@ void mmc_start_host(struct mmc_host *host)
|
||||
{
|
||||
host->f_init = max(min(freqs[0], host->f_max), host->f_min);
|
||||
host->rescan_disable = 0;
|
||||
host->ios.power_mode = MMC_POWER_UNDEFINED;
|
||||
|
||||
if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
|
||||
mmc_claim_host(host);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/pm_wakeup.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
@ -36,6 +37,7 @@ static DEFINE_IDA(mmc_host_ida);
|
||||
static void mmc_host_classdev_release(struct device *dev)
|
||||
{
|
||||
struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
||||
wakeup_source_unregister(host->ws);
|
||||
ida_simple_remove(&mmc_host_ida, host->index);
|
||||
kfree(host);
|
||||
}
|
||||
@ -275,6 +277,8 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
host->caps |= MMC_CAP_SDIO_IRQ;
|
||||
if (device_property_read_bool(dev, "full-pwr-cycle"))
|
||||
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
|
||||
if (device_property_read_bool(dev, "full-pwr-cycle-in-suspend"))
|
||||
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND;
|
||||
if (device_property_read_bool(dev, "keep-power-in-suspend"))
|
||||
host->pm_caps |= MMC_PM_KEEP_POWER;
|
||||
if (device_property_read_bool(dev, "wakeup-source") ||
|
||||
@ -400,6 +404,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
||||
host->index = err;
|
||||
|
||||
dev_set_name(&host->class_dev, "mmc%d", host->index);
|
||||
host->ws = wakeup_source_register(NULL, dev_name(&host->class_dev));
|
||||
|
||||
host->parent = dev;
|
||||
host->class_dev.parent = dev;
|
||||
@ -431,6 +436,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
||||
|
||||
host->fixed_drv_type = -EINVAL;
|
||||
host->ios.power_delay_ms = 10;
|
||||
host->ios.power_mode = MMC_POWER_UNDEFINED;
|
||||
|
||||
return host;
|
||||
}
|
||||
|
@ -2038,7 +2038,8 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
|
||||
goto out;
|
||||
|
||||
if (mmc_can_poweroff_notify(host->card) &&
|
||||
((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
|
||||
((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend ||
|
||||
(host->caps2 & MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND)))
|
||||
err = mmc_poweroff_notify(host->card, notify_type);
|
||||
else if (mmc_can_sleep(host->card))
|
||||
err = mmc_sleep(host);
|
||||
|
@ -203,7 +203,7 @@ static unsigned int mmc_get_max_segments(struct mmc_host *host)
|
||||
|
||||
/**
|
||||
* mmc_init_request() - initialize the MMC-specific per-request data
|
||||
* @q: the request queue
|
||||
* @mq: the request queue
|
||||
* @req: the request
|
||||
* @gfp: memory allocation policy
|
||||
*/
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include "card.h"
|
||||
|
||||
static const struct mmc_fixup mmc_blk_fixups[] = {
|
||||
static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
|
||||
#define INAND_CMD38_ARG_EXT_CSD 113
|
||||
#define INAND_CMD38_ARG_ERASE 0x00
|
||||
#define INAND_CMD38_ARG_TRIM 0x01
|
||||
@ -102,7 +102,7 @@ static const struct mmc_fixup mmc_blk_fixups[] = {
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
static const struct mmc_fixup mmc_ext_csd_fixups[] = {
|
||||
static const struct mmc_fixup __maybe_unused mmc_ext_csd_fixups[] = {
|
||||
/*
|
||||
* Certain Hynix eMMC 4.41 cards might get broken when HPI feature
|
||||
* is used so disable the HPI feature for such buggy cards.
|
||||
@ -120,7 +120,7 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = {
|
||||
};
|
||||
|
||||
|
||||
static const struct mmc_fixup sdio_fixup_methods[] = {
|
||||
static const struct mmc_fixup __maybe_unused sdio_fixup_methods[] = {
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251,
|
||||
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
|
||||
|
||||
|
@ -159,6 +159,8 @@ static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator,
|
||||
|
||||
/**
|
||||
* mmc_regulator_set_vqmmc - Set VQMMC as per the ios
|
||||
* @mmc: the host to regulate
|
||||
* @ios: io bus settings
|
||||
*
|
||||
* For 3.3V signaling, we try to match VQMMC to VMMC as closely as possible.
|
||||
* That will match the behavior of old boards where VQMMC and VMMC were supplied
|
||||
|
@ -176,15 +176,18 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
|
||||
if (mmc_host_uhs(card->host)) {
|
||||
if (data & SDIO_UHS_DDR50)
|
||||
card->sw_caps.sd3_bus_mode
|
||||
|= SD_MODE_UHS_DDR50;
|
||||
|= SD_MODE_UHS_DDR50 | SD_MODE_UHS_SDR50
|
||||
| SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12;
|
||||
|
||||
if (data & SDIO_UHS_SDR50)
|
||||
card->sw_caps.sd3_bus_mode
|
||||
|= SD_MODE_UHS_SDR50;
|
||||
|= SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR25
|
||||
| SD_MODE_UHS_SDR12;
|
||||
|
||||
if (data & SDIO_UHS_SDR104)
|
||||
card->sw_caps.sd3_bus_mode
|
||||
|= SD_MODE_UHS_SDR104;
|
||||
|= SD_MODE_UHS_SDR104 | SD_MODE_UHS_SDR50
|
||||
| SD_MODE_UHS_SDR25 | SD_MODE_UHS_SDR12;
|
||||
}
|
||||
|
||||
ret = mmc_io_rw_direct(card, 0, 0,
|
||||
@ -303,30 +306,49 @@ static int sdio_disable_wide(struct mmc_card *card)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdio_disable_4bit_bus(struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (card->type == MMC_TYPE_SDIO)
|
||||
goto out;
|
||||
|
||||
if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
|
||||
return 0;
|
||||
|
||||
if (!(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4))
|
||||
return 0;
|
||||
|
||||
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
out:
|
||||
return sdio_disable_wide(card);
|
||||
}
|
||||
|
||||
|
||||
static int sdio_enable_4bit_bus(struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = sdio_enable_wide(card);
|
||||
if (err <= 0)
|
||||
return err;
|
||||
if (card->type == MMC_TYPE_SDIO)
|
||||
err = sdio_enable_wide(card);
|
||||
else if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
|
||||
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
||||
goto out;
|
||||
|
||||
if (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) {
|
||||
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
|
||||
if (err)
|
||||
if (err) {
|
||||
sdio_disable_wide(card);
|
||||
return err;
|
||||
err = sdio_enable_wide(card);
|
||||
if (err <= 0)
|
||||
mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (err > 0) {
|
||||
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
out:
|
||||
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -518,10 +540,8 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
max_rate = min_not_zero(card->quirk_max_rate,
|
||||
card->sw_caps.uhs_max_dtr);
|
||||
|
||||
if (bus_speed) {
|
||||
mmc_set_timing(card->host, timing);
|
||||
mmc_set_clock(card->host, max_rate);
|
||||
}
|
||||
mmc_set_timing(card->host, timing);
|
||||
mmc_set_clock(card->host, max_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -972,7 +992,7 @@ static int mmc_sdio_suspend(struct mmc_host *host)
|
||||
mmc_claim_host(host);
|
||||
|
||||
if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host))
|
||||
sdio_disable_wide(host->card);
|
||||
sdio_disable_4bit_bus(host->card);
|
||||
|
||||
if (!mmc_card_keep_power(host)) {
|
||||
mmc_power_off(host);
|
||||
|
@ -133,7 +133,7 @@ int sdio_disable_func(struct sdio_func *func)
|
||||
|
||||
err:
|
||||
pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func));
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdio_disable_func);
|
||||
|
||||
@ -709,6 +709,7 @@ EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps);
|
||||
/**
|
||||
* sdio_set_host_pm_flags - set wanted host power management capabilities
|
||||
* @func: SDIO function attached to host
|
||||
* @flags: Power Management flags to set
|
||||
*
|
||||
* Set a capability bitmask corresponding to wanted host controller
|
||||
* power management features for the upcoming suspend state.
|
||||
|
@ -1009,6 +1009,7 @@ config MMC_MTK
|
||||
tristate "MediaTek SD/MMC Card Interface support"
|
||||
depends on HAS_DMA
|
||||
select REGULATOR
|
||||
select MMC_CQHCI
|
||||
help
|
||||
This selects the MediaTek(R) Secure digital and Multimedia card Interface.
|
||||
If you have a machine with a integrated SD/MMC card reader, say Y or M here.
|
||||
|
@ -225,12 +225,13 @@ struct atmel_mci_dma {
|
||||
* @lock: Spinlock protecting the queue and associated data.
|
||||
* @regs: Pointer to MMIO registers.
|
||||
* @sg: Scatterlist entry currently being processed by PIO or PDC code.
|
||||
* @sg_len: Size of the scatterlist
|
||||
* @pio_offset: Offset into the current scatterlist entry.
|
||||
* @buffer: Buffer used if we don't have the r/w proof capability. We
|
||||
* don't have the time to switch pdc buffers so we have to use only
|
||||
* one buffer for the full transaction.
|
||||
* @buf_size: size of the buffer.
|
||||
* @phys_buf_addr: buffer address needed for pdc.
|
||||
* @buf_phys_addr: buffer address needed for pdc.
|
||||
* @cur_slot: The slot which is currently using the controller.
|
||||
* @mrq: The request currently being processed on @cur_slot,
|
||||
* or NULL if the controller is idle.
|
||||
@ -240,6 +241,7 @@ struct atmel_mci_dma {
|
||||
* @data_size: just data->blocks * data->blksz.
|
||||
* @dma: DMA client state.
|
||||
* @data_chan: DMA channel being used for the current data transfer.
|
||||
* @dma_conf: Configuration for the DMA slave
|
||||
* @cmd_status: Snapshot of SR taken upon completion of the current
|
||||
* command. Only valid when EVENT_CMD_COMPLETE is pending.
|
||||
* @data_status: Snapshot of SR taken upon completion of the current
|
||||
|
@ -144,7 +144,7 @@ static void cqhci_dumpregs(struct cqhci_host *cq_host)
|
||||
CQHCI_DUMP(": ===========================================\n");
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* The allocated descriptor table for task, link & transfer descritors
|
||||
* looks like:
|
||||
* |----------|
|
||||
@ -422,7 +422,7 @@ static void cqhci_prep_task_desc(struct mmc_request *mrq,
|
||||
CQHCI_BLK_COUNT(mrq->data->blocks) |
|
||||
CQHCI_BLK_ADDR((u64)mrq->data->blk_addr);
|
||||
|
||||
pr_debug("%s: cqhci: tag %d task descriptor 0x016%llx\n",
|
||||
pr_debug("%s: cqhci: tag %d task descriptor 0x%016llx\n",
|
||||
mmc_hostname(mrq->host), mrq->tag, (unsigned long long)*data);
|
||||
}
|
||||
|
||||
|
@ -176,6 +176,7 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/**
|
||||
* dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
|
||||
* @dev: Device to suspend (this device)
|
||||
*
|
||||
* This ensures that device will be in runtime active state in
|
||||
* dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume()
|
||||
@ -188,6 +189,7 @@ static int dw_mci_exynos_suspend_noirq(struct device *dev)
|
||||
|
||||
/**
|
||||
* dw_mci_exynos_resume_noirq - Exynos-specific resume code
|
||||
* @dev: Device to resume (this device)
|
||||
*
|
||||
* On exynos5420 there is a silicon errata that will sometimes leave the
|
||||
* WAKEUP_INT bit in the CLKSEL register asserted. This bit is 1 to indicate
|
||||
@ -472,7 +474,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
|
||||
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||||
struct mmc_host *mmc = slot->mmc;
|
||||
u8 start_smpl, smpl, candiates = 0;
|
||||
s8 found = -1;
|
||||
s8 found;
|
||||
int ret = 0;
|
||||
|
||||
start_smpl = dw_mci_exynos_get_clksmpl(host);
|
||||
|
@ -267,6 +267,7 @@ static struct variant_data variant_stm32_sdmmc = {
|
||||
.datalength_bits = 25,
|
||||
.datactrl_blocksz = 14,
|
||||
.datactrl_any_blocksz = true,
|
||||
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
|
||||
.stm32_idmabsize_mask = GENMASK(12, 5),
|
||||
.busy_timeout = true,
|
||||
.busy_detect = true,
|
||||
@ -292,6 +293,7 @@ static struct variant_data variant_stm32_sdmmcv2 = {
|
||||
.datalength_bits = 25,
|
||||
.datactrl_blocksz = 14,
|
||||
.datactrl_any_blocksz = true,
|
||||
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
|
||||
.stm32_idmabsize_mask = GENMASK(16, 5),
|
||||
.dma_lli = true,
|
||||
.busy_timeout = true,
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
|
||||
#include "cqhci.h"
|
||||
|
||||
#define MAX_BD_NUM 1024
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -152,6 +154,7 @@
|
||||
#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 */
|
||||
|
||||
/* MSDC_INTEN mask */
|
||||
#define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */
|
||||
@ -182,6 +185,7 @@
|
||||
/* 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 */
|
||||
@ -230,6 +234,7 @@
|
||||
#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 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_BIT2_CFGRESP (0x1 << 15) /* RW */
|
||||
@ -431,9 +436,11 @@ struct msdc_host {
|
||||
/* cmd response sample selection for HS400 */
|
||||
bool hs400_mode; /* current eMMC will run at hs400 mode */
|
||||
bool internal_cd; /* Use internal card-detect logic */
|
||||
bool cqhci; /* support eMMC hw cmdq */
|
||||
struct msdc_save_para save_para; /* used when gate HCLK */
|
||||
struct msdc_tune_para def_tune_para; /* default tune setting */
|
||||
struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
|
||||
struct cqhci_host *cq_host;
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt8135_compat = {
|
||||
@ -538,6 +545,18 @@ static const struct mtk_mmc_compatible mt7620_compat = {
|
||||
.use_internal_cd = true,
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt6779_compat = {
|
||||
.clk_div_bits = 12,
|
||||
.hs400_tune = false,
|
||||
.pad_tune_reg = MSDC_PAD_TUNE0,
|
||||
.async_fifo = true,
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.enhance_rx = true,
|
||||
.support_64g = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id msdc_of_ids[] = {
|
||||
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
|
||||
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
|
||||
@ -547,6 +566,7 @@ static const struct of_device_id msdc_of_ids[] = {
|
||||
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
|
||||
{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
|
||||
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
|
||||
{ .compatible = "mediatek,mt6779-mmc", .data = &mt6779_compat},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, msdc_of_ids);
|
||||
@ -710,21 +730,21 @@ static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq)
|
||||
}
|
||||
}
|
||||
|
||||
/* clock control primitives */
|
||||
static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
|
||||
static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks)
|
||||
{
|
||||
u32 timeout, clk_ns;
|
||||
u64 timeout, clk_ns;
|
||||
u32 mode = 0;
|
||||
|
||||
host->timeout_ns = ns;
|
||||
host->timeout_clks = clks;
|
||||
if (host->mmc->actual_clock == 0) {
|
||||
timeout = 0;
|
||||
} else {
|
||||
clk_ns = 1000000000UL / host->mmc->actual_clock;
|
||||
timeout = (ns + clk_ns - 1) / clk_ns + clks;
|
||||
clk_ns = 1000000000ULL;
|
||||
do_div(clk_ns, host->mmc->actual_clock);
|
||||
timeout = ns + clk_ns - 1;
|
||||
do_div(timeout, clk_ns);
|
||||
timeout += clks;
|
||||
/* in 1048576 sclk cycle unit */
|
||||
timeout = (timeout + (0x1 << 20) - 1) >> 20;
|
||||
timeout = DIV_ROUND_UP(timeout, (0x1 << 20));
|
||||
if (host->dev_comp->clk_div_bits == 8)
|
||||
sdr_get_field(host->base + MSDC_CFG,
|
||||
MSDC_CFG_CKMOD, &mode);
|
||||
@ -734,9 +754,30 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
|
||||
/*DDR mode will double the clk cycles for data timeout */
|
||||
timeout = mode >= 2 ? timeout * 2 : timeout;
|
||||
timeout = timeout > 1 ? timeout - 1 : 0;
|
||||
timeout = timeout > 255 ? 255 : timeout;
|
||||
}
|
||||
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, timeout);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/* clock control primitives */
|
||||
static void msdc_set_timeout(struct msdc_host *host, u64 ns, u64 clks)
|
||||
{
|
||||
u64 timeout;
|
||||
|
||||
host->timeout_ns = ns;
|
||||
host->timeout_clks = clks;
|
||||
|
||||
timeout = msdc_timeout_cal(host, ns, clks);
|
||||
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC,
|
||||
(u32)(timeout > 255 ? 255 : timeout));
|
||||
}
|
||||
|
||||
static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks)
|
||||
{
|
||||
u64 timeout;
|
||||
|
||||
timeout = msdc_timeout_cal(host, ns, clks);
|
||||
sdr_set_field(host->base + SDC_CFG, SDC_CFG_WRDTOC,
|
||||
(u32)(timeout > 8191 ? 8191 : timeout));
|
||||
}
|
||||
|
||||
static void msdc_gate_clock(struct msdc_host *host)
|
||||
@ -1018,13 +1059,12 @@ static int msdc_auto_cmd_done(struct msdc_host *host, int events,
|
||||
return cmd->error;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* msdc_recheck_sdio_irq - recheck whether the SDIO irq is lost
|
||||
*
|
||||
* Host controller may lost interrupt in some special case.
|
||||
* Add SDIO irq recheck mechanism to make sure all interrupts
|
||||
* can be processed immediately
|
||||
*
|
||||
*/
|
||||
static void msdc_recheck_sdio_irq(struct msdc_host *host)
|
||||
{
|
||||
@ -1456,6 +1496,34 @@ static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
|
||||
pm_runtime_put_noidle(host->dev);
|
||||
}
|
||||
|
||||
static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts)
|
||||
{
|
||||
int cmd_err = 0, dat_err = 0;
|
||||
|
||||
if (intsts & MSDC_INT_RSPCRCERR) {
|
||||
cmd_err = -EILSEQ;
|
||||
dev_err(host->dev, "%s: CMD CRC ERR", __func__);
|
||||
} else if (intsts & MSDC_INT_CMDTMO) {
|
||||
cmd_err = -ETIMEDOUT;
|
||||
dev_err(host->dev, "%s: CMD TIMEOUT ERR", __func__);
|
||||
}
|
||||
|
||||
if (intsts & MSDC_INT_DATCRCERR) {
|
||||
dat_err = -EILSEQ;
|
||||
dev_err(host->dev, "%s: DATA CRC ERR", __func__);
|
||||
} else if (intsts & MSDC_INT_DATTMO) {
|
||||
dat_err = -ETIMEDOUT;
|
||||
dev_err(host->dev, "%s: DATA TIMEOUT ERR", __func__);
|
||||
}
|
||||
|
||||
if (cmd_err || dat_err) {
|
||||
dev_err(host->dev, "cmd_err = %d, dat_err =%d, intsts = 0x%x",
|
||||
cmd_err, dat_err, intsts);
|
||||
}
|
||||
|
||||
return cqhci_irq(host->mmc, 0, cmd_err, dat_err);
|
||||
}
|
||||
|
||||
static irqreturn_t msdc_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct msdc_host *host = (struct msdc_host *) dev_id;
|
||||
@ -1492,6 +1560,14 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
|
||||
if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
|
||||
break;
|
||||
|
||||
if ((host->mmc->caps2 & MMC_CAP2_CQE) &&
|
||||
(events & MSDC_INT_CMDQ)) {
|
||||
msdc_cmdq_irq(host, events);
|
||||
/* clear interrupts */
|
||||
writel(events, host->base + MSDC_INT);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (!mrq) {
|
||||
dev_err(host->dev,
|
||||
"%s: MRQ=NULL; events=%08X; event_mask=%08X\n",
|
||||
@ -2176,6 +2252,36 @@ static int msdc_get_cd(struct mmc_host *mmc)
|
||||
return !val;
|
||||
}
|
||||
|
||||
static void msdc_cqe_enable(struct mmc_host *mmc)
|
||||
{
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
||||
/* enable cmdq irq */
|
||||
writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN);
|
||||
/* enable busy check */
|
||||
sdr_set_bits(host->base + MSDC_PATCH_BIT1, MSDC_PB1_BUSY_CHECK_SEL);
|
||||
/* default write data / busy timeout 20s */
|
||||
msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0);
|
||||
/* default read data timeout 1s */
|
||||
msdc_set_timeout(host, 1000000000ULL, 0);
|
||||
}
|
||||
|
||||
static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
|
||||
{
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
||||
/* disable cmdq irq */
|
||||
sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INT_CMDQ);
|
||||
/* disable busy check */
|
||||
sdr_clr_bits(host->base + MSDC_PATCH_BIT1, MSDC_PB1_BUSY_CHECK_SEL);
|
||||
|
||||
if (recovery) {
|
||||
sdr_set_field(host->base + MSDC_DMA_CTRL,
|
||||
MSDC_DMA_CTRL_STOP, 1);
|
||||
msdc_reset_hw(host);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct mmc_host_ops mt_msdc_ops = {
|
||||
.post_req = msdc_post_req,
|
||||
.pre_req = msdc_pre_req,
|
||||
@ -2192,6 +2298,11 @@ static const struct mmc_host_ops mt_msdc_ops = {
|
||||
.hw_reset = msdc_hw_reset,
|
||||
};
|
||||
|
||||
static const struct cqhci_host_ops msdc_cmdq_ops = {
|
||||
.enable = msdc_cqe_enable,
|
||||
.disable = msdc_cqe_disable,
|
||||
};
|
||||
|
||||
static void msdc_of_property_parse(struct platform_device *pdev,
|
||||
struct msdc_host *host)
|
||||
{
|
||||
@ -2212,6 +2323,12 @@ static void msdc_of_property_parse(struct platform_device *pdev,
|
||||
host->hs400_cmd_resp_sel_rising = true;
|
||||
else
|
||||
host->hs400_cmd_resp_sel_rising = false;
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node,
|
||||
"supports-cqe"))
|
||||
host->cqhci = true;
|
||||
else
|
||||
host->cqhci = false;
|
||||
}
|
||||
|
||||
static int msdc_drv_probe(struct platform_device *pdev)
|
||||
@ -2327,6 +2444,8 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
|
||||
|
||||
mmc->caps |= MMC_CAP_CMD23;
|
||||
if (host->cqhci)
|
||||
mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
|
||||
/* MMC core transfer sizes tunable parameters */
|
||||
mmc->max_segs = MAX_BD_NUM;
|
||||
if (host->dev_comp->support_64g)
|
||||
@ -2342,6 +2461,26 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
host->dma_mask = DMA_BIT_MASK(32);
|
||||
mmc_dev(mmc)->dma_mask = &host->dma_mask;
|
||||
|
||||
if (mmc->caps2 & MMC_CAP2_CQE) {
|
||||
host->cq_host = devm_kzalloc(host->mmc->parent,
|
||||
sizeof(*host->cq_host),
|
||||
GFP_KERNEL);
|
||||
if (!host->cq_host) {
|
||||
ret = -ENOMEM;
|
||||
goto host_free;
|
||||
}
|
||||
host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
|
||||
host->cq_host->mmio = host->base + 0x800;
|
||||
host->cq_host->ops = &msdc_cmdq_ops;
|
||||
ret = cqhci_init(host->cq_host, mmc, true);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
mmc->max_segs = 128;
|
||||
/* cqhci 16bit length */
|
||||
/* 0 size, means 65536 so we don't have to -1 here */
|
||||
mmc->max_seg_size = 64 * 1024;
|
||||
}
|
||||
|
||||
host->timeout_clks = 3 * 1048576;
|
||||
host->dma.gpd = dma_alloc_coherent(&pdev->dev,
|
||||
2 * sizeof(struct mt_gpdma_desc),
|
||||
|
@ -229,15 +229,15 @@ static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
|
||||
DTRAN_CTRL_DM_START);
|
||||
}
|
||||
|
||||
static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
|
||||
static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
|
||||
enum dma_data_direction dir;
|
||||
|
||||
spin_lock_irq(&host->lock);
|
||||
if (!host->dma_on)
|
||||
return false;
|
||||
|
||||
if (!host->data)
|
||||
goto out;
|
||||
return false;
|
||||
|
||||
if (host->data->flags & MMC_DATA_READ)
|
||||
dir = DMA_FROM_DEVICE;
|
||||
@ -250,11 +250,30 @@ static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
|
||||
if (dir == DMA_FROM_DEVICE)
|
||||
clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
|
||||
|
||||
host->dma_on = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
|
||||
{
|
||||
struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
|
||||
|
||||
spin_lock_irq(&host->lock);
|
||||
if (!renesas_sdhi_internal_dmac_complete(host))
|
||||
goto out;
|
||||
|
||||
tmio_mmc_do_data_irq(host);
|
||||
out:
|
||||
spin_unlock_irq(&host->lock);
|
||||
}
|
||||
|
||||
static void renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host *host)
|
||||
{
|
||||
if (host->data)
|
||||
renesas_sdhi_internal_dmac_complete(host);
|
||||
}
|
||||
|
||||
static void
|
||||
renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
|
||||
struct tmio_mmc_data *pdata)
|
||||
@ -292,6 +311,7 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
|
||||
.release = renesas_sdhi_internal_dmac_release_dma,
|
||||
.abort = renesas_sdhi_internal_dmac_abort_dma,
|
||||
.dataend = renesas_sdhi_internal_dmac_dataend_dma,
|
||||
.end = renesas_sdhi_internal_dmac_end_dma,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -675,11 +675,11 @@ static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map)
|
||||
|
||||
static void sd_wait_data_idle(struct realtek_pci_sdmmc *host)
|
||||
{
|
||||
int err, i;
|
||||
int i;
|
||||
u8 val = 0;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
err = rtsx_pci_read_register(host->pcr, SD_DATA_STATE, &val);
|
||||
rtsx_pci_read_register(host->pcr, SD_DATA_STATE, &val);
|
||||
if (val & SD_DATA_IDLE)
|
||||
return;
|
||||
|
||||
|
@ -654,12 +654,11 @@ static u8 sd_search_final_phase(struct rtsx_usb_sdmmc *host, u32 phase_map)
|
||||
|
||||
static void sd_wait_data_idle(struct rtsx_usb_sdmmc *host)
|
||||
{
|
||||
int err, i;
|
||||
int i;
|
||||
u8 val = 0;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
err = rtsx_usb_ep0_read_register(host->ucr,
|
||||
SD_DATA_STATE, &val);
|
||||
rtsx_usb_ep0_read_register(host->ucr, SD_DATA_STATE, &val);
|
||||
if (val & SD_DATA_IDLE)
|
||||
return;
|
||||
|
||||
|
@ -542,6 +542,7 @@ static int amd_select_drive_strength(struct mmc_card *card,
|
||||
unsigned int max_dtr, int host_drv,
|
||||
int card_drv, int *drv_type)
|
||||
{
|
||||
*drv_type = MMC_SET_DRIVER_TYPE_A;
|
||||
return MMC_SET_DRIVER_TYPE_A;
|
||||
}
|
||||
|
||||
|
@ -202,6 +202,79 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
|
||||
return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
|
||||
}
|
||||
|
||||
static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
|
||||
{
|
||||
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
|
||||
void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
|
||||
u32 tmp;
|
||||
int i, ret;
|
||||
|
||||
if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = readl(reg);
|
||||
tmp &= ~SDHCI_CDNS_HRS06_TUNE;
|
||||
tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
|
||||
|
||||
/*
|
||||
* Workaround for IP errata:
|
||||
* The IP6116 SD/eMMC PHY design has a timing issue on receive data
|
||||
* path. Send tune request twice.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
|
||||
writel(tmp, reg);
|
||||
|
||||
ret = readl_poll_timeout(reg, tmp,
|
||||
!(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
|
||||
0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In SD mode, software must not use the hardware tuning and instead perform
|
||||
* an almost identical procedure to eMMC.
|
||||
*/
|
||||
static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
|
||||
{
|
||||
int cur_streak = 0;
|
||||
int max_streak = 0;
|
||||
int end_of_streak = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Do not execute tuning for UHS_SDR50 or UHS_DDR50.
|
||||
* The delay is set by probe, based on the DT properties.
|
||||
*/
|
||||
if (host->timing != MMC_TIMING_MMC_HS200 &&
|
||||
host->timing != MMC_TIMING_UHS_SDR104)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
|
||||
if (sdhci_cdns_set_tune_val(host, i) ||
|
||||
mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
|
||||
cur_streak = 0;
|
||||
} else { /* good */
|
||||
cur_streak++;
|
||||
if (cur_streak > max_streak) {
|
||||
max_streak = cur_streak;
|
||||
end_of_streak = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!max_streak) {
|
||||
dev_err(mmc_dev(host->mmc), "no tuning point found\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
|
||||
}
|
||||
|
||||
static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
|
||||
unsigned int timing)
|
||||
{
|
||||
@ -241,6 +314,7 @@ static const struct sdhci_ops sdhci_cdns_ops = {
|
||||
.get_timeout_clock = sdhci_cdns_get_timeout_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_reset,
|
||||
.platform_execute_tuning = sdhci_cdns_execute_tuning,
|
||||
.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
|
||||
};
|
||||
|
||||
@ -253,78 +327,6 @@ static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
|
||||
.ops = &sdhci_cdns_ops,
|
||||
};
|
||||
|
||||
static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
|
||||
{
|
||||
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
|
||||
void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
|
||||
u32 tmp;
|
||||
int i, ret;
|
||||
|
||||
if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = readl(reg);
|
||||
tmp &= ~SDHCI_CDNS_HRS06_TUNE;
|
||||
tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
|
||||
|
||||
/*
|
||||
* Workaround for IP errata:
|
||||
* The IP6116 SD/eMMC PHY design has a timing issue on receive data
|
||||
* path. Send tune request twice.
|
||||
*/
|
||||
for (i = 0; i < 2; i++) {
|
||||
tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
|
||||
writel(tmp, reg);
|
||||
|
||||
ret = readl_poll_timeout(reg, tmp,
|
||||
!(tmp & SDHCI_CDNS_HRS06_TUNE_UP),
|
||||
0, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
int cur_streak = 0;
|
||||
int max_streak = 0;
|
||||
int end_of_streak = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* This handler only implements the eMMC tuning that is specific to
|
||||
* this controller. Fall back to the standard method for SD timing.
|
||||
*/
|
||||
if (host->timing != MMC_TIMING_MMC_HS200)
|
||||
return sdhci_execute_tuning(mmc, opcode);
|
||||
|
||||
if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
|
||||
if (sdhci_cdns_set_tune_val(host, i) ||
|
||||
mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
|
||||
cur_streak = 0;
|
||||
} else { /* good */
|
||||
cur_streak++;
|
||||
if (cur_streak > max_streak) {
|
||||
max_streak = cur_streak;
|
||||
end_of_streak = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!max_streak) {
|
||||
dev_err(mmc_dev(host->mmc), "no tuning point found\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
|
||||
}
|
||||
|
||||
static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios)
|
||||
{
|
||||
@ -385,7 +387,6 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
|
||||
priv->hrs_addr = host->ioaddr;
|
||||
priv->enhanced_strobe = false;
|
||||
host->ioaddr += SDHCI_CDNS_SRS_BASE;
|
||||
host->mmc_host_ops.execute_tuning = sdhci_cdns_execute_tuning;
|
||||
host->mmc_host_ops.hs400_enhanced_strobe =
|
||||
sdhci_cdns_hs400_enhanced_strobe;
|
||||
sdhci_enable_v4_mode(host);
|
||||
|
@ -38,6 +38,16 @@
|
||||
#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1)
|
||||
#define ESDHC_VENDOR_SPEC_VSELECT (1 << 1)
|
||||
#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8)
|
||||
#define ESDHC_DEBUG_SEL_AND_STATUS_REG 0xc2
|
||||
#define ESDHC_DEBUG_SEL_REG 0xc3
|
||||
#define ESDHC_DEBUG_SEL_MASK 0xf
|
||||
#define ESDHC_DEBUG_SEL_CMD_STATE 1
|
||||
#define ESDHC_DEBUG_SEL_DATA_STATE 2
|
||||
#define ESDHC_DEBUG_SEL_TRANS_STATE 3
|
||||
#define ESDHC_DEBUG_SEL_DMA_STATE 4
|
||||
#define ESDHC_DEBUG_SEL_ADMA_STATE 5
|
||||
#define ESDHC_DEBUG_SEL_FIFO_STATE 6
|
||||
#define ESDHC_DEBUG_SEL_ASYNC_FIFO_STATE 7
|
||||
#define ESDHC_WTMK_LVL 0x44
|
||||
#define ESDHC_WTMK_DEFAULT_VAL 0x10401040
|
||||
#define ESDHC_WTMK_LVL_RD_WML_MASK 0x000000FF
|
||||
@ -348,6 +358,34 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
|
||||
writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
|
||||
}
|
||||
|
||||
#define DRIVER_NAME "sdhci-esdhc-imx"
|
||||
#define ESDHC_IMX_DUMP(f, x...) \
|
||||
pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
|
||||
static void esdhc_dump_debug_regs(struct sdhci_host *host)
|
||||
{
|
||||
int i;
|
||||
char *debug_status[7] = {
|
||||
"cmd debug status",
|
||||
"data debug status",
|
||||
"trans debug status",
|
||||
"dma debug status",
|
||||
"adma debug status",
|
||||
"fifo debug status",
|
||||
"async fifo debug status"
|
||||
};
|
||||
|
||||
ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n");
|
||||
for (i = 0; i < 7; i++) {
|
||||
esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK,
|
||||
ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG);
|
||||
ESDHC_IMX_DUMP("%s: 0x%04x\n", debug_status[i],
|
||||
readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG));
|
||||
}
|
||||
|
||||
esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG);
|
||||
|
||||
}
|
||||
|
||||
static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
|
||||
{
|
||||
u32 present_state;
|
||||
@ -1237,6 +1275,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
|
||||
.set_uhs_signaling = esdhc_set_uhs_signaling,
|
||||
.reset = esdhc_reset,
|
||||
.irq = esdhc_cqhci_irq,
|
||||
.dump_vendor_regs = esdhc_dump_debug_regs,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
|
||||
|
@ -294,12 +294,14 @@ static const struct of_device_id sdhci_iproc_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id sdhci_iproc_acpi_ids[] = {
|
||||
{ .id = "BRCM5871", .driver_data = (kernel_ulong_t)&iproc_cygnus_data },
|
||||
{ .id = "BRCM5872", .driver_data = (kernel_ulong_t)&iproc_data },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, sdhci_iproc_acpi_ids);
|
||||
#endif
|
||||
|
||||
static int sdhci_iproc_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/interconnect.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "cqhci.h"
|
||||
@ -36,7 +38,9 @@
|
||||
#define CORE_PWRCTL_IO_LOW BIT(2)
|
||||
#define CORE_PWRCTL_IO_HIGH BIT(3)
|
||||
#define CORE_PWRCTL_BUS_SUCCESS BIT(0)
|
||||
#define CORE_PWRCTL_BUS_FAIL BIT(1)
|
||||
#define CORE_PWRCTL_IO_SUCCESS BIT(2)
|
||||
#define CORE_PWRCTL_IO_FAIL BIT(3)
|
||||
#define REQ_BUS_OFF BIT(0)
|
||||
#define REQ_BUS_ON BIT(1)
|
||||
#define REQ_IO_LOW BIT(2)
|
||||
@ -126,6 +130,9 @@
|
||||
/* Timeout value to avoid infinite waiting for pwr_irq */
|
||||
#define MSM_PWR_IRQ_TIMEOUT_MS 5000
|
||||
|
||||
/* Max load for eMMC Vdd-io supply */
|
||||
#define MMC_VQMMC_MAX_LOAD_UA 325000
|
||||
|
||||
#define msm_host_readl(msm_host, host, offset) \
|
||||
msm_host->var_ops->msm_readl_relaxed(host, offset)
|
||||
|
||||
@ -277,6 +284,7 @@ struct sdhci_msm_host {
|
||||
bool uses_tassadar_dll;
|
||||
u32 dll_config;
|
||||
u32 ddr_config;
|
||||
bool vqmmc_enabled;
|
||||
};
|
||||
|
||||
static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
|
||||
@ -1346,6 +1354,108 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
|
||||
sdhci_msm_hs400(host, &mmc->ios);
|
||||
}
|
||||
|
||||
static int sdhci_msm_set_pincfg(struct sdhci_msm_host *msm_host, bool level)
|
||||
{
|
||||
struct platform_device *pdev = msm_host->pdev;
|
||||
int ret;
|
||||
|
||||
if (level)
|
||||
ret = pinctrl_pm_select_default_state(&pdev->dev);
|
||||
else
|
||||
ret = pinctrl_pm_select_sleep_state(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdhci_msm_set_vmmc(struct mmc_host *mmc)
|
||||
{
|
||||
if (IS_ERR(mmc->supply.vmmc))
|
||||
return 0;
|
||||
|
||||
return mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, mmc->ios.vdd);
|
||||
}
|
||||
|
||||
static int msm_toggle_vqmmc(struct sdhci_msm_host *msm_host,
|
||||
struct mmc_host *mmc, bool level)
|
||||
{
|
||||
int ret;
|
||||
struct mmc_ios ios;
|
||||
|
||||
if (msm_host->vqmmc_enabled == level)
|
||||
return 0;
|
||||
|
||||
if (level) {
|
||||
/* Set the IO voltage regulator to default voltage level */
|
||||
if (msm_host->caps_0 & CORE_3_0V_SUPPORT)
|
||||
ios.signal_voltage = MMC_SIGNAL_VOLTAGE_330;
|
||||
else if (msm_host->caps_0 & CORE_1_8V_SUPPORT)
|
||||
ios.signal_voltage = MMC_SIGNAL_VOLTAGE_180;
|
||||
|
||||
if (msm_host->caps_0 & CORE_VOLT_SUPPORT) {
|
||||
ret = mmc_regulator_set_vqmmc(mmc, &ios);
|
||||
if (ret < 0) {
|
||||
dev_err(mmc_dev(mmc), "%s: vqmmc set volgate failed: %d\n",
|
||||
mmc_hostname(mmc), ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = regulator_enable(mmc->supply.vqmmc);
|
||||
} else {
|
||||
ret = regulator_disable(mmc->supply.vqmmc);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(mmc_dev(mmc), "%s: vqmm %sable failed: %d\n",
|
||||
mmc_hostname(mmc), level ? "en":"dis", ret);
|
||||
else
|
||||
msm_host->vqmmc_enabled = level;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_config_vqmmc_mode(struct sdhci_msm_host *msm_host,
|
||||
struct mmc_host *mmc, bool hpm)
|
||||
{
|
||||
int load, ret;
|
||||
|
||||
load = hpm ? MMC_VQMMC_MAX_LOAD_UA : 0;
|
||||
ret = regulator_set_load(mmc->supply.vqmmc, load);
|
||||
if (ret)
|
||||
dev_err(mmc_dev(mmc), "%s: vqmmc set load failed: %d\n",
|
||||
mmc_hostname(mmc), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdhci_msm_set_vqmmc(struct sdhci_msm_host *msm_host,
|
||||
struct mmc_host *mmc, bool level)
|
||||
{
|
||||
int ret;
|
||||
bool always_on;
|
||||
|
||||
if (IS_ERR(mmc->supply.vqmmc) ||
|
||||
(mmc->ios.power_mode == MMC_POWER_UNDEFINED))
|
||||
return 0;
|
||||
/*
|
||||
* For eMMC don't turn off Vqmmc, Instead just configure it in LPM
|
||||
* and HPM modes by setting the corresponding load.
|
||||
*
|
||||
* Till eMMC is initialized (i.e. always_on == 0), just turn on/off
|
||||
* Vqmmc. Vqmmc gets turned off only if init fails and mmc_power_off
|
||||
* gets invoked. Once eMMC is initialized (i.e. always_on == 1),
|
||||
* Vqmmc should remain ON, So just set the load instead of turning it
|
||||
* off/on.
|
||||
*/
|
||||
always_on = !mmc_card_is_removable(mmc) &&
|
||||
mmc->card && mmc_card_mmc(mmc->card);
|
||||
|
||||
if (always_on)
|
||||
ret = msm_config_vqmmc_mode(msm_host, mmc, level);
|
||||
else
|
||||
ret = msm_toggle_vqmmc(msm_host, mmc, level);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
init_waitqueue_head(&msm_host->pwr_irq_wait);
|
||||
@ -1363,7 +1473,7 @@ static inline void sdhci_msm_complete_pwr_irq_wait(
|
||||
* To what state the register writes will change the IO lines should be passed
|
||||
* as the argument req_type. This API will check whether the IO line's state
|
||||
* is already the expected state and will wait for power irq only if
|
||||
* power irq is expected to be trigerred based on the current IO line state
|
||||
* power irq is expected to be triggered based on the current IO line state
|
||||
* and expected IO line state.
|
||||
*/
|
||||
static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
|
||||
@ -1449,8 +1559,9 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
u32 irq_status, irq_ack = 0;
|
||||
int retry = 10;
|
||||
int retry = 10, ret;
|
||||
u32 pwr_state = 0, io_level = 0;
|
||||
u32 config;
|
||||
const struct sdhci_msm_offset *msm_offset = msm_host->offset;
|
||||
@ -1488,21 +1599,45 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
|
||||
if (irq_status & CORE_PWRCTL_BUS_ON) {
|
||||
pwr_state = REQ_BUS_ON;
|
||||
io_level = REQ_IO_HIGH;
|
||||
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
|
||||
}
|
||||
if (irq_status & CORE_PWRCTL_BUS_OFF) {
|
||||
pwr_state = REQ_BUS_OFF;
|
||||
io_level = REQ_IO_LOW;
|
||||
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (pwr_state) {
|
||||
ret = sdhci_msm_set_vmmc(mmc);
|
||||
if (!ret)
|
||||
ret = sdhci_msm_set_vqmmc(msm_host, mmc,
|
||||
pwr_state & REQ_BUS_ON);
|
||||
if (!ret)
|
||||
ret = sdhci_msm_set_pincfg(msm_host,
|
||||
pwr_state & REQ_BUS_ON);
|
||||
if (!ret)
|
||||
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
|
||||
else
|
||||
irq_ack |= CORE_PWRCTL_BUS_FAIL;
|
||||
}
|
||||
|
||||
/* Handle IO LOW/HIGH */
|
||||
if (irq_status & CORE_PWRCTL_IO_LOW) {
|
||||
if (irq_status & CORE_PWRCTL_IO_LOW)
|
||||
io_level = REQ_IO_LOW;
|
||||
irq_ack |= CORE_PWRCTL_IO_SUCCESS;
|
||||
}
|
||||
if (irq_status & CORE_PWRCTL_IO_HIGH) {
|
||||
|
||||
if (irq_status & CORE_PWRCTL_IO_HIGH)
|
||||
io_level = REQ_IO_HIGH;
|
||||
|
||||
if (io_level)
|
||||
irq_ack |= CORE_PWRCTL_IO_SUCCESS;
|
||||
|
||||
if (io_level && !IS_ERR(mmc->supply.vqmmc) && !pwr_state) {
|
||||
ret = mmc_regulator_set_vqmmc(mmc, &mmc->ios);
|
||||
if (ret < 0) {
|
||||
dev_err(mmc_dev(mmc), "%s: IO_level setting failed(%d). signal_voltage: %d, vdd: %d irq_status: 0x%08x\n",
|
||||
mmc_hostname(mmc), ret,
|
||||
mmc->ios.signal_voltage, mmc->ios.vdd,
|
||||
irq_status);
|
||||
irq_ack |= CORE_PWRCTL_IO_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1551,7 +1686,7 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
|
||||
if (io_level)
|
||||
msm_host->curr_io_level = io_level;
|
||||
|
||||
pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
|
||||
dev_dbg(mmc_dev(mmc), "%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
|
||||
mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
|
||||
irq_ack);
|
||||
}
|
||||
@ -1584,7 +1719,7 @@ static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
|
||||
return SDHCI_MSM_MIN_CLOCK;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* __sdhci_msm_set_clock - sdhci_msm clock control.
|
||||
*
|
||||
* Description:
|
||||
@ -1881,11 +2016,76 @@ static void sdhci_msm_reset(struct sdhci_host *host, u8 mask)
|
||||
sdhci_reset(host, mask);
|
||||
}
|
||||
|
||||
static int sdhci_msm_register_vreg(struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mmc_regulator_get_supply(msm_host->mmc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sdhci_msm_set_regulator_caps(msm_host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_msm_start_signal_voltage_switch(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
u16 ctrl, status;
|
||||
|
||||
/*
|
||||
* Signal Voltage Switching is only applicable for Host Controllers
|
||||
* v3.00 and above.
|
||||
*/
|
||||
if (host->version < SDHCI_SPEC_300)
|
||||
return 0;
|
||||
|
||||
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||
|
||||
switch (ios->signal_voltage) {
|
||||
case MMC_SIGNAL_VOLTAGE_330:
|
||||
if (!(host->flags & SDHCI_SIGNALING_330))
|
||||
return -EINVAL;
|
||||
|
||||
/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
|
||||
ctrl &= ~SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
case MMC_SIGNAL_VOLTAGE_180:
|
||||
if (!(host->flags & SDHCI_SIGNALING_180))
|
||||
return -EINVAL;
|
||||
|
||||
/* Enable 1.8V Signal Enable in the Host Control2 register */
|
||||
ctrl |= SDHCI_CTRL_VDD_180;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
|
||||
|
||||
/* Wait for 5ms */
|
||||
usleep_range(5000, 5500);
|
||||
|
||||
/* regulator output should be stable within 5 ms */
|
||||
status = ctrl & SDHCI_CTRL_VDD_180;
|
||||
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||
if ((ctrl & SDHCI_CTRL_VDD_180) == status)
|
||||
return 0;
|
||||
|
||||
dev_warn(mmc_dev(mmc), "%s: Regulator output did not became stable\n",
|
||||
mmc_hostname(mmc));
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
#define DRIVER_NAME "sdhci_msm"
|
||||
#define SDHCI_MSM_DUMP(f, x...) \
|
||||
pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
|
||||
|
||||
void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
|
||||
static void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||
@ -1967,6 +2167,7 @@ static const struct sdhci_ops sdhci_msm_ops = {
|
||||
.write_b = sdhci_msm_writeb,
|
||||
.irq = sdhci_msm_cqe_irq,
|
||||
.dump_vendor_regs = sdhci_msm_dump_vendor_regs,
|
||||
.set_power = sdhci_set_power_noreg,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_msm_pdata = {
|
||||
@ -2071,6 +2272,11 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
}
|
||||
msm_host->bulk_clks[0].clk = clk;
|
||||
|
||||
/* Check for optional interconnect paths */
|
||||
ret = dev_pm_opp_of_find_icc_paths(&pdev->dev, NULL);
|
||||
if (ret)
|
||||
goto bus_clk_disable;
|
||||
|
||||
msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core");
|
||||
if (IS_ERR(msm_host->opp_table)) {
|
||||
ret = PTR_ERR(msm_host->opp_table);
|
||||
@ -2176,6 +2382,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
if (core_major == 1 && core_minor >= 0x49)
|
||||
msm_host->updated_ddr_cfg = true;
|
||||
|
||||
ret = sdhci_msm_register_vreg(msm_host);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
/*
|
||||
* Power on reset state may trigger power irq if previous status of
|
||||
* PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
|
||||
@ -2220,6 +2430,8 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
MSM_MMC_AUTOSUSPEND_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
|
||||
host->mmc_host_ops.start_signal_voltage_switch =
|
||||
sdhci_msm_start_signal_voltage_switch;
|
||||
host->mmc_host_ops.execute_tuning = sdhci_msm_execute_tuning;
|
||||
if (of_property_read_bool(node, "supports-cqe"))
|
||||
ret = sdhci_msm_cqe_add_host(host, pdev);
|
||||
@ -2227,7 +2439,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
ret = sdhci_add_host(host);
|
||||
if (ret)
|
||||
goto pm_runtime_disable;
|
||||
sdhci_msm_set_regulator_caps(msm_host);
|
||||
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
@ -1025,7 +1025,6 @@ static void arasan_dt_read_clk_phase(struct device *dev,
|
||||
static void arasan_dt_parse_clk_phases(struct device *dev,
|
||||
struct sdhci_arasan_clk_data *clk_data)
|
||||
{
|
||||
int *iclk_phase, *oclk_phase;
|
||||
u32 mio_bank = 0;
|
||||
int i;
|
||||
|
||||
@ -1037,28 +1036,32 @@ static void arasan_dt_parse_clk_phases(struct device *dev,
|
||||
clk_data->set_clk_delays = sdhci_arasan_set_clk_delays;
|
||||
|
||||
if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) {
|
||||
iclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) ZYNQMP_ICLK_PHASE;
|
||||
oclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) ZYNQMP_OCLK_PHASE;
|
||||
u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
|
||||
ZYNQMP_ICLK_PHASE;
|
||||
u32 zynqmp_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
|
||||
ZYNQMP_OCLK_PHASE;
|
||||
|
||||
of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank);
|
||||
if (mio_bank == 2) {
|
||||
oclk_phase[MMC_TIMING_UHS_SDR104] = 90;
|
||||
oclk_phase[MMC_TIMING_MMC_HS200] = 90;
|
||||
zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90;
|
||||
zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90;
|
||||
}
|
||||
|
||||
for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
|
||||
clk_data->clk_phase_in[i] = iclk_phase[i];
|
||||
clk_data->clk_phase_out[i] = oclk_phase[i];
|
||||
clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i];
|
||||
clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) {
|
||||
iclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) VERSAL_ICLK_PHASE;
|
||||
oclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) VERSAL_OCLK_PHASE;
|
||||
u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
|
||||
VERSAL_ICLK_PHASE;
|
||||
u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
|
||||
VERSAL_OCLK_PHASE;
|
||||
|
||||
for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
|
||||
clk_data->clk_phase_in[i] = iclk_phase[i];
|
||||
clk_data->clk_phase_out[i] = oclk_phase[i];
|
||||
clk_data->clk_phase_in[i] = versal_iclk_phase[i];
|
||||
clk_data->clk_phase_out[i] = versal_oclk_phase[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1299,6 +1302,8 @@ sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan,
|
||||
clk_data->sdcardclk_hw.init = &sdcardclk_init;
|
||||
clk_data->sdcardclk =
|
||||
devm_clk_register(dev, &clk_data->sdcardclk_hw);
|
||||
if (IS_ERR(clk_data->sdcardclk))
|
||||
return PTR_ERR(clk_data->sdcardclk);
|
||||
clk_data->sdcardclk_hw.init = NULL;
|
||||
|
||||
ret = of_clk_add_provider(np, of_clk_src_simple_get,
|
||||
@ -1349,6 +1354,8 @@ sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan,
|
||||
clk_data->sampleclk_hw.init = &sampleclk_init;
|
||||
clk_data->sampleclk =
|
||||
devm_clk_register(dev, &clk_data->sampleclk_hw);
|
||||
if (IS_ERR(clk_data->sampleclk))
|
||||
return PTR_ERR(clk_data->sampleclk);
|
||||
clk_data->sampleclk_hw.init = NULL;
|
||||
|
||||
ret = of_clk_add_provider(np, of_clk_src_simple_get,
|
||||
@ -1388,7 +1395,8 @@ static void sdhci_arasan_unregister_sdclk(struct device *dev)
|
||||
* - For Keem Bay, it is required to clear this bit. Its default value is 1'b1.
|
||||
* Keem Bay does not support 64-bit access.
|
||||
*
|
||||
* @host The sdhci_host
|
||||
* @host: The sdhci_host
|
||||
* @value: The value to write
|
||||
*/
|
||||
static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value)
|
||||
{
|
||||
|
@ -31,10 +31,18 @@
|
||||
#define SDHCI_GLI_9750_ALL_RST (BIT(24)|BIT(25)|BIT(28)|BIT(30))
|
||||
|
||||
#define SDHCI_GLI_9750_PLL 0x864
|
||||
#define SDHCI_GLI_9750_PLL_LDIV GENMASK(9, 0)
|
||||
#define SDHCI_GLI_9750_PLL_PDIV GENMASK(14, 12)
|
||||
#define SDHCI_GLI_9750_PLL_DIR BIT(15)
|
||||
#define SDHCI_GLI_9750_PLL_TX2_INV BIT(23)
|
||||
#define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20)
|
||||
#define GLI_9750_PLL_TX2_INV_VALUE 0x1
|
||||
#define GLI_9750_PLL_TX2_DLY_VALUE 0x0
|
||||
#define SDHCI_GLI_9750_PLLSSC_STEP GENMASK(28, 24)
|
||||
#define SDHCI_GLI_9750_PLLSSC_EN BIT(31)
|
||||
|
||||
#define SDHCI_GLI_9750_PLLSSC 0x86C
|
||||
#define SDHCI_GLI_9750_PLLSSC_PPM GENMASK(31, 16)
|
||||
|
||||
#define SDHCI_GLI_9750_SW_CTRL 0x874
|
||||
#define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6)
|
||||
@ -76,6 +84,21 @@
|
||||
#define PCIE_GLI_9763E_SCR 0x8E0
|
||||
#define GLI_9763E_SCR_AXI_REQ BIT(9)
|
||||
|
||||
#define PCI_GLI_9755_WT 0x800
|
||||
#define PCI_GLI_9755_WT_EN BIT(0)
|
||||
#define GLI_9755_WT_EN_ON 0x1
|
||||
#define GLI_9755_WT_EN_OFF 0x0
|
||||
|
||||
#define PCI_GLI_9755_PLL 0x64
|
||||
#define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0)
|
||||
#define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12)
|
||||
#define PCI_GLI_9755_PLL_DIR BIT(15)
|
||||
#define PCI_GLI_9755_PLLSSC_STEP GENMASK(28, 24)
|
||||
#define PCI_GLI_9755_PLLSSC_EN BIT(31)
|
||||
|
||||
#define PCI_GLI_9755_PLLSSC 0x68
|
||||
#define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0)
|
||||
|
||||
#define GLI_MAX_TUNING_LOOP 40
|
||||
|
||||
/* Genesys Logic chipset */
|
||||
@ -280,6 +303,84 @@ static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gl9750_disable_ssc_pll(struct sdhci_host *host)
|
||||
{
|
||||
u32 pll;
|
||||
|
||||
gl9750_wt_on(host);
|
||||
pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
|
||||
pll &= ~(SDHCI_GLI_9750_PLL_DIR | SDHCI_GLI_9750_PLLSSC_EN);
|
||||
sdhci_writel(host, pll, SDHCI_GLI_9750_PLL);
|
||||
gl9750_wt_off(host);
|
||||
}
|
||||
|
||||
static void gl9750_set_pll(struct sdhci_host *host, u8 dir, u16 ldiv, u8 pdiv)
|
||||
{
|
||||
u32 pll;
|
||||
|
||||
gl9750_wt_on(host);
|
||||
pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
|
||||
pll &= ~(SDHCI_GLI_9750_PLL_LDIV |
|
||||
SDHCI_GLI_9750_PLL_PDIV |
|
||||
SDHCI_GLI_9750_PLL_DIR);
|
||||
pll |= FIELD_PREP(SDHCI_GLI_9750_PLL_LDIV, ldiv) |
|
||||
FIELD_PREP(SDHCI_GLI_9750_PLL_PDIV, pdiv) |
|
||||
FIELD_PREP(SDHCI_GLI_9750_PLL_DIR, dir);
|
||||
sdhci_writel(host, pll, SDHCI_GLI_9750_PLL);
|
||||
gl9750_wt_off(host);
|
||||
|
||||
/* wait for pll stable */
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
static void gl9750_set_ssc(struct sdhci_host *host, u8 enable, u8 step, u16 ppm)
|
||||
{
|
||||
u32 pll;
|
||||
u32 ssc;
|
||||
|
||||
gl9750_wt_on(host);
|
||||
pll = sdhci_readl(host, SDHCI_GLI_9750_PLL);
|
||||
ssc = sdhci_readl(host, SDHCI_GLI_9750_PLLSSC);
|
||||
pll &= ~(SDHCI_GLI_9750_PLLSSC_STEP |
|
||||
SDHCI_GLI_9750_PLLSSC_EN);
|
||||
ssc &= ~SDHCI_GLI_9750_PLLSSC_PPM;
|
||||
pll |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_STEP, step) |
|
||||
FIELD_PREP(SDHCI_GLI_9750_PLLSSC_EN, enable);
|
||||
ssc |= FIELD_PREP(SDHCI_GLI_9750_PLLSSC_PPM, ppm);
|
||||
sdhci_writel(host, ssc, SDHCI_GLI_9750_PLLSSC);
|
||||
sdhci_writel(host, pll, SDHCI_GLI_9750_PLL);
|
||||
gl9750_wt_off(host);
|
||||
}
|
||||
|
||||
static void gl9750_set_ssc_pll_205mhz(struct sdhci_host *host)
|
||||
{
|
||||
/* set pll to 205MHz and enable ssc */
|
||||
gl9750_set_ssc(host, 0x1, 0x1F, 0xFFE7);
|
||||
gl9750_set_pll(host, 0x1, 0x246, 0x0);
|
||||
}
|
||||
|
||||
static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
struct mmc_ios *ios = &host->mmc->ios;
|
||||
u16 clk;
|
||||
|
||||
host->mmc->actual_clock = 0;
|
||||
|
||||
gl9750_disable_ssc_pll(host);
|
||||
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
if (clock == 0)
|
||||
return;
|
||||
|
||||
clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
|
||||
if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) {
|
||||
host->mmc->actual_clock = 205000000;
|
||||
gl9750_set_ssc_pll_205mhz(host);
|
||||
}
|
||||
|
||||
sdhci_enable_clk(host, clk);
|
||||
}
|
||||
|
||||
static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
int ret;
|
||||
@ -295,6 +396,121 @@ static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot)
|
||||
slot->host->irq = pci_irq_vector(slot->chip->pdev, 0);
|
||||
}
|
||||
|
||||
static inline void gl9755_wt_on(struct pci_dev *pdev)
|
||||
{
|
||||
u32 wt_value;
|
||||
u32 wt_enable;
|
||||
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value);
|
||||
wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value);
|
||||
|
||||
if (wt_enable == GLI_9755_WT_EN_ON)
|
||||
return;
|
||||
|
||||
wt_value &= ~PCI_GLI_9755_WT_EN;
|
||||
wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_ON);
|
||||
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value);
|
||||
}
|
||||
|
||||
static inline void gl9755_wt_off(struct pci_dev *pdev)
|
||||
{
|
||||
u32 wt_value;
|
||||
u32 wt_enable;
|
||||
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_WT, &wt_value);
|
||||
wt_enable = FIELD_GET(PCI_GLI_9755_WT_EN, wt_value);
|
||||
|
||||
if (wt_enable == GLI_9755_WT_EN_OFF)
|
||||
return;
|
||||
|
||||
wt_value &= ~PCI_GLI_9755_WT_EN;
|
||||
wt_value |= FIELD_PREP(PCI_GLI_9755_WT_EN, GLI_9755_WT_EN_OFF);
|
||||
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_WT, wt_value);
|
||||
}
|
||||
|
||||
static void gl9755_disable_ssc_pll(struct pci_dev *pdev)
|
||||
{
|
||||
u32 pll;
|
||||
|
||||
gl9755_wt_on(pdev);
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll);
|
||||
pll &= ~(PCI_GLI_9755_PLL_DIR | PCI_GLI_9755_PLLSSC_EN);
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll);
|
||||
gl9755_wt_off(pdev);
|
||||
}
|
||||
|
||||
static void gl9755_set_pll(struct pci_dev *pdev, u8 dir, u16 ldiv, u8 pdiv)
|
||||
{
|
||||
u32 pll;
|
||||
|
||||
gl9755_wt_on(pdev);
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll);
|
||||
pll &= ~(PCI_GLI_9755_PLL_LDIV |
|
||||
PCI_GLI_9755_PLL_PDIV |
|
||||
PCI_GLI_9755_PLL_DIR);
|
||||
pll |= FIELD_PREP(PCI_GLI_9755_PLL_LDIV, ldiv) |
|
||||
FIELD_PREP(PCI_GLI_9755_PLL_PDIV, pdiv) |
|
||||
FIELD_PREP(PCI_GLI_9755_PLL_DIR, dir);
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll);
|
||||
gl9755_wt_off(pdev);
|
||||
|
||||
/* wait for pll stable */
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
static void gl9755_set_ssc(struct pci_dev *pdev, u8 enable, u8 step, u16 ppm)
|
||||
{
|
||||
u32 pll;
|
||||
u32 ssc;
|
||||
|
||||
gl9755_wt_on(pdev);
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_PLL, &pll);
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &ssc);
|
||||
pll &= ~(PCI_GLI_9755_PLLSSC_STEP |
|
||||
PCI_GLI_9755_PLLSSC_EN);
|
||||
ssc &= ~PCI_GLI_9755_PLLSSC_PPM;
|
||||
pll |= FIELD_PREP(PCI_GLI_9755_PLLSSC_STEP, step) |
|
||||
FIELD_PREP(PCI_GLI_9755_PLLSSC_EN, enable);
|
||||
ssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_PPM, ppm);
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, ssc);
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_PLL, pll);
|
||||
gl9755_wt_off(pdev);
|
||||
}
|
||||
|
||||
static void gl9755_set_ssc_pll_205mhz(struct pci_dev *pdev)
|
||||
{
|
||||
/* set pll to 205MHz and enable ssc */
|
||||
gl9755_set_ssc(pdev, 0x1, 0x1F, 0xFFE7);
|
||||
gl9755_set_pll(pdev, 0x1, 0x246, 0x0);
|
||||
}
|
||||
|
||||
static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct mmc_ios *ios = &host->mmc->ios;
|
||||
struct pci_dev *pdev;
|
||||
u16 clk;
|
||||
|
||||
pdev = slot->chip->pdev;
|
||||
host->mmc->actual_clock = 0;
|
||||
|
||||
gl9755_disable_ssc_pll(pdev);
|
||||
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
if (clock == 0)
|
||||
return;
|
||||
|
||||
clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
|
||||
if (clock == 200000000 && ios->timing == MMC_TIMING_UHS_SDR104) {
|
||||
host->mmc->actual_clock = 205000000;
|
||||
gl9755_set_ssc_pll_205mhz(pdev);
|
||||
}
|
||||
|
||||
sdhci_enable_clk(host, clk);
|
||||
}
|
||||
|
||||
static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct sdhci_host *host = slot->host;
|
||||
@ -440,7 +656,7 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_gl9755_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_clock = sdhci_gl9755_set_clock,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_reset,
|
||||
@ -460,7 +676,7 @@ const struct sdhci_pci_fixes sdhci_gl9755 = {
|
||||
|
||||
static const struct sdhci_ops sdhci_gl9750_ops = {
|
||||
.read_l = sdhci_gl9750_readl,
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_clock = sdhci_gl9750_set_clock,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_gl9750_reset,
|
||||
|
@ -196,7 +196,7 @@ static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode)
|
||||
{
|
||||
int i;
|
||||
|
||||
sdhci_send_tuning(host, MMC_SEND_TUNING_BLOCK_HS200);
|
||||
sdhci_send_tuning(host, opcode);
|
||||
|
||||
for (i = 0; i < 150; i++) {
|
||||
u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||
@ -305,10 +305,12 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
* This handler only implements the eMMC tuning that is specific to
|
||||
* this controller. Fall back to the standard method for other TIMING.
|
||||
*/
|
||||
if (host->timing != MMC_TIMING_MMC_HS200)
|
||||
if ((host->timing != MMC_TIMING_MMC_HS200) &&
|
||||
(host->timing != MMC_TIMING_UHS_SDR104))
|
||||
return sdhci_execute_tuning(mmc, opcode);
|
||||
|
||||
if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
|
||||
if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
|
||||
(opcode != MMC_SEND_TUNING_BLOCK)))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Judge the tuning reason, whether caused by dll shift
|
||||
@ -342,6 +344,9 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
sdhci_set_bus_width(host, current_bus_width);
|
||||
}
|
||||
|
||||
sdhci_reset(host, SDHCI_RESET_CMD);
|
||||
sdhci_reset(host, SDHCI_RESET_DATA);
|
||||
|
||||
host->flags &= ~SDHCI_HS400_TUNING;
|
||||
return 0;
|
||||
}
|
||||
@ -369,7 +374,6 @@ static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
|
||||
scratch_32 |= O2_SD_LED_ENABLE;
|
||||
pci_write_config_dword(chip->pdev,
|
||||
O2_SD_TEST_REG, scratch_32);
|
||||
|
||||
}
|
||||
|
||||
static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
|
||||
@ -497,6 +501,10 @@ static void sdhci_o2_enable_clk(struct sdhci_host *host, u16 clk)
|
||||
static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
u16 clk;
|
||||
u8 scratch;
|
||||
u32 scratch_32;
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct sdhci_pci_chip *chip = slot->chip;
|
||||
|
||||
host->mmc->actual_clock = 0;
|
||||
|
||||
@ -505,6 +513,23 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
if (clock == 0)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -561,6 +586,12 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
|
||||
slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd;
|
||||
}
|
||||
|
||||
if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD1) {
|
||||
slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd;
|
||||
host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
|
||||
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
|
||||
}
|
||||
|
||||
host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning;
|
||||
|
||||
if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
|
||||
|
@ -107,8 +107,11 @@
|
||||
* @ioarea: The resource created when we claimed the IO area.
|
||||
* @pdata: The platform data for this controller.
|
||||
* @cur_clk: The index of the current bus clock.
|
||||
* @ext_cd_irq: External card detect interrupt.
|
||||
* @clk_io: The clock for the internal bus interface.
|
||||
* @clk_rates: Clock frequencies.
|
||||
* @clk_bus: The clocks that are available for the SD/MMC bus clock.
|
||||
* @no_divider: No or non-standard internal clock divider.
|
||||
*/
|
||||
struct sdhci_s3c {
|
||||
struct sdhci_host *host;
|
||||
@ -128,6 +131,7 @@ struct sdhci_s3c {
|
||||
/**
|
||||
* struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data
|
||||
* @sdhci_quirks: sdhci host specific quirks.
|
||||
* @no_divider: no or non-standard internal clock divider.
|
||||
*
|
||||
* Specifies platform specific configuration of sdhci controller.
|
||||
* Note: A structure for driver specific platform data is used for future
|
||||
|
@ -96,7 +96,16 @@
|
||||
#define NVQUIRK_ENABLE_SDR50 BIT(3)
|
||||
#define NVQUIRK_ENABLE_SDR104 BIT(4)
|
||||
#define NVQUIRK_ENABLE_DDR50 BIT(5)
|
||||
/*
|
||||
* HAS_PADCALIB NVQUIRK is for SoC's supporting auto calibration of pads
|
||||
* drive strength.
|
||||
*/
|
||||
#define NVQUIRK_HAS_PADCALIB BIT(6)
|
||||
/*
|
||||
* NEEDS_PAD_CONTROL NVQUIRK is for SoC's having separate 3V3 and 1V8 pads.
|
||||
* 3V3/1V8 pad selection happens through pinctrl state selection depending
|
||||
* on the signaling mode.
|
||||
*/
|
||||
#define NVQUIRK_NEEDS_PAD_CONTROL BIT(7)
|
||||
#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8)
|
||||
#define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING BIT(9)
|
||||
|
@ -4104,7 +4104,8 @@ int sdhci_setup_host(struct sdhci_host *host)
|
||||
unsigned int ocr_avail;
|
||||
unsigned int override_timeout_clk;
|
||||
u32 max_clk;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
bool enable_vqmmc = false;
|
||||
|
||||
WARN_ON(host == NULL);
|
||||
if (host == NULL)
|
||||
@ -4118,9 +4119,12 @@ int sdhci_setup_host(struct sdhci_host *host)
|
||||
* the host can take the appropriate action if regulators are not
|
||||
* available.
|
||||
*/
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!mmc->supply.vqmmc) {
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
if (ret)
|
||||
return ret;
|
||||
enable_vqmmc = true;
|
||||
}
|
||||
|
||||
DBG("Version: 0x%08x | Present: 0x%08x\n",
|
||||
sdhci_readw(host, SDHCI_HOST_VERSION),
|
||||
@ -4377,7 +4381,10 @@ int sdhci_setup_host(struct sdhci_host *host)
|
||||
mmc->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
if (!IS_ERR(mmc->supply.vqmmc)) {
|
||||
ret = regulator_enable(mmc->supply.vqmmc);
|
||||
if (enable_vqmmc) {
|
||||
ret = regulator_enable(mmc->supply.vqmmc);
|
||||
host->sdhci_core_to_disable_vqmmc = !ret;
|
||||
}
|
||||
|
||||
/* If vqmmc provides no 1.8V signalling, then there's no UHS */
|
||||
if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000,
|
||||
@ -4396,6 +4403,7 @@ int sdhci_setup_host(struct sdhci_host *host)
|
||||
mmc_hostname(mmc), ret);
|
||||
mmc->supply.vqmmc = ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
|
||||
@ -4626,7 +4634,7 @@ int sdhci_setup_host(struct sdhci_host *host)
|
||||
return 0;
|
||||
|
||||
unreg:
|
||||
if (!IS_ERR(mmc->supply.vqmmc))
|
||||
if (host->sdhci_core_to_disable_vqmmc)
|
||||
regulator_disable(mmc->supply.vqmmc);
|
||||
undma:
|
||||
if (host->align_buffer)
|
||||
@ -4644,7 +4652,7 @@ void sdhci_cleanup_host(struct sdhci_host *host)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
if (!IS_ERR(mmc->supply.vqmmc))
|
||||
if (host->sdhci_core_to_disable_vqmmc)
|
||||
regulator_disable(mmc->supply.vqmmc);
|
||||
|
||||
if (host->align_buffer)
|
||||
@ -4787,7 +4795,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
|
||||
|
||||
destroy_workqueue(host->complete_wq);
|
||||
|
||||
if (!IS_ERR(mmc->supply.vqmmc))
|
||||
if (host->sdhci_core_to_disable_vqmmc)
|
||||
regulator_disable(mmc->supply.vqmmc);
|
||||
|
||||
if (host->align_buffer)
|
||||
|
@ -567,6 +567,7 @@ struct sdhci_host {
|
||||
u32 caps1; /* CAPABILITY_1 */
|
||||
bool read_caps; /* Capability flags have been read */
|
||||
|
||||
bool sdhci_core_to_disable_vqmmc; /* sdhci core can disable vqmmc */
|
||||
unsigned int ocr_avail_sdio; /* OCR bit masks */
|
||||
unsigned int ocr_avail_sd;
|
||||
unsigned int ocr_avail_mmc;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
#include "cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
@ -46,6 +47,8 @@
|
||||
#define SEL100_MASK BIT(SEL100_SHIFT)
|
||||
#define FREQSEL_SHIFT 8
|
||||
#define FREQSEL_MASK GENMASK(10, 8)
|
||||
#define CLKBUFSEL_SHIFT 0
|
||||
#define CLKBUFSEL_MASK GENMASK(2, 0)
|
||||
#define DLL_TRIM_ICP_SHIFT 4
|
||||
#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
|
||||
#define DR_TY_SHIFT 20
|
||||
@ -60,6 +63,8 @@
|
||||
#define CALDONE_MASK BIT(CALDONE_SHIFT)
|
||||
#define RETRIM_SHIFT 17
|
||||
#define RETRIM_MASK BIT(RETRIM_SHIFT)
|
||||
#define SELDLYTXCLK_SHIFT 17
|
||||
#define SELDLYTXCLK_MASK BIT(SELDLYTXCLK_SHIFT)
|
||||
|
||||
#define DRIVER_STRENGTH_50_OHM 0x0
|
||||
#define DRIVER_STRENGTH_33_OHM 0x1
|
||||
@ -83,6 +88,7 @@ struct sdhci_am654_data {
|
||||
struct regmap *base;
|
||||
bool legacy_otapdly;
|
||||
int otap_del_sel[11];
|
||||
int clkbuf_sel;
|
||||
int trm_icp;
|
||||
int drv_strength;
|
||||
bool dll_on;
|
||||
@ -97,6 +103,7 @@ struct sdhci_am654_driver_data {
|
||||
#define FREQSEL_2_BIT (1 << 1)
|
||||
#define STRBSEL_4_BIT (1 << 2)
|
||||
#define DLL_PRESENT (1 << 3)
|
||||
#define DLL_CALIB (1 << 4)
|
||||
};
|
||||
|
||||
struct timing_data {
|
||||
@ -202,34 +209,41 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
|
||||
sdhci_set_clock(host, clock);
|
||||
|
||||
if (clock > CLOCK_TOO_SLOW_HZ) {
|
||||
/* Setup DLL Output TAP delay */
|
||||
if (sdhci_am654->legacy_otapdly)
|
||||
otap_del_sel = sdhci_am654->otap_del_sel[0];
|
||||
/* Setup DLL Output TAP delay */
|
||||
if (sdhci_am654->legacy_otapdly)
|
||||
otap_del_sel = sdhci_am654->otap_del_sel[0];
|
||||
else
|
||||
otap_del_sel = sdhci_am654->otap_del_sel[timing];
|
||||
|
||||
otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0;
|
||||
|
||||
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
||||
val = (otap_del_ena << OTAPDLYENA_SHIFT) |
|
||||
(otap_del_sel << OTAPDLYSEL_SHIFT);
|
||||
|
||||
/* Write to STRBSEL for HS400 speed mode */
|
||||
if (timing == MMC_TIMING_MMC_HS400) {
|
||||
if (sdhci_am654->flags & STRBSEL_4_BIT)
|
||||
mask |= STRBSEL_4BIT_MASK;
|
||||
else
|
||||
otap_del_sel = sdhci_am654->otap_del_sel[timing];
|
||||
mask |= STRBSEL_8BIT_MASK;
|
||||
|
||||
otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0;
|
||||
|
||||
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
||||
val = (otap_del_ena << OTAPDLYENA_SHIFT) |
|
||||
(otap_del_sel << OTAPDLYSEL_SHIFT);
|
||||
|
||||
/* Write to STRBSEL for HS400 speed mode */
|
||||
if (timing == MMC_TIMING_MMC_HS400) {
|
||||
if (sdhci_am654->flags & STRBSEL_4_BIT)
|
||||
mask |= STRBSEL_4BIT_MASK;
|
||||
else
|
||||
mask |= STRBSEL_8BIT_MASK;
|
||||
|
||||
val |= sdhci_am654->strb_sel << STRBSEL_SHIFT;
|
||||
}
|
||||
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
|
||||
|
||||
if (timing > MMC_TIMING_UHS_SDR25)
|
||||
sdhci_am654_setup_dll(host, clock);
|
||||
val |= sdhci_am654->strb_sel << STRBSEL_SHIFT;
|
||||
}
|
||||
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
|
||||
|
||||
if (timing > MMC_TIMING_UHS_SDR25 && clock > CLOCK_TOO_SLOW_HZ) {
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
|
||||
SELDLYTXCLK_MASK, 0);
|
||||
sdhci_am654_setup_dll(host, clock);
|
||||
} else {
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL5,
|
||||
SELDLYTXCLK_MASK, 1 << SELDLYTXCLK_SHIFT);
|
||||
}
|
||||
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
|
||||
sdhci_am654->clkbuf_sel);
|
||||
}
|
||||
|
||||
static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
|
||||
@ -252,6 +266,9 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
|
||||
(otap_del_sel << OTAPDLYSEL_SHIFT);
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
|
||||
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
|
||||
sdhci_am654->clkbuf_sel);
|
||||
|
||||
sdhci_set_clock(host, clock);
|
||||
}
|
||||
|
||||
@ -323,6 +340,12 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = {
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||
};
|
||||
|
||||
static const struct sdhci_am654_driver_data sdhci_am654_sr1_drvdata = {
|
||||
.pdata = &sdhci_am654_pdata,
|
||||
.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT |
|
||||
DLL_CALIB,
|
||||
};
|
||||
|
||||
static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
|
||||
.pdata = &sdhci_am654_pdata,
|
||||
.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,
|
||||
@ -348,7 +371,7 @@ static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
|
||||
|
||||
static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
|
||||
.pdata = &sdhci_j721e_8bit_pdata,
|
||||
.flags = DLL_PRESENT,
|
||||
.flags = DLL_PRESENT | DLL_CALIB,
|
||||
};
|
||||
|
||||
static struct sdhci_ops sdhci_j721e_4bit_ops = {
|
||||
@ -374,6 +397,14 @@ static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = {
|
||||
.flags = IOMUX_PRESENT,
|
||||
};
|
||||
|
||||
static const struct soc_device_attribute sdhci_am654_devices[] = {
|
||||
{ .family = "AM65X",
|
||||
.revision = "SR1.0",
|
||||
.data = &sdhci_am654_sr1_drvdata
|
||||
},
|
||||
{/* sentinel */}
|
||||
};
|
||||
|
||||
static void sdhci_am654_dumpregs(struct mmc_host *mmc)
|
||||
{
|
||||
sdhci_dumpregs(mmc_priv(mmc));
|
||||
@ -469,7 +500,7 @@ static int sdhci_am654_init(struct sdhci_host *host)
|
||||
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
|
||||
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0);
|
||||
|
||||
if (sdhci_am654->flags & DLL_PRESENT) {
|
||||
if (sdhci_am654->flags & DLL_CALIB) {
|
||||
regmap_read(sdhci_am654->base, PHY_STAT1, &val);
|
||||
if (~val & CALDONE_MASK) {
|
||||
/* Calibrate IO lines */
|
||||
@ -560,6 +591,8 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
device_property_read_u32(dev, "ti,strobe-sel", &sdhci_am654->strb_sel);
|
||||
device_property_read_u32(dev, "ti,clkbuf-sel",
|
||||
&sdhci_am654->clkbuf_sel);
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
|
||||
@ -585,6 +618,7 @@ static const struct of_device_id sdhci_am654_of_match[] = {
|
||||
static int sdhci_am654_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct sdhci_am654_driver_data *drvdata;
|
||||
const struct soc_device_attribute *soc;
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct sdhci_am654_data *sdhci_am654;
|
||||
const struct of_device_id *match;
|
||||
@ -596,6 +630,12 @@ static int sdhci_am654_probe(struct platform_device *pdev)
|
||||
|
||||
match = of_match_node(sdhci_am654_of_match, pdev->dev.of_node);
|
||||
drvdata = match->data;
|
||||
|
||||
/* Update drvdata based on SoC revision */
|
||||
soc = soc_device_match(sdhci_am654_devices);
|
||||
if (soc && soc->data)
|
||||
drvdata = soc->data;
|
||||
|
||||
host = sdhci_pltfm_init(pdev, drvdata->pdata, sizeof(*sdhci_am654));
|
||||
if (IS_ERR(host))
|
||||
return PTR_ERR(host);
|
||||
|
@ -191,9 +191,9 @@
|
||||
STS2_AC12BSYTO | STS2_RSPBSYTO | \
|
||||
STS2_AC12RSPTO | STS2_RSPTO)
|
||||
|
||||
#define CLKDEV_EMMC_DATA 52000000 /* 52MHz */
|
||||
#define CLKDEV_MMC_DATA 20000000 /* 20MHz */
|
||||
#define CLKDEV_INIT 400000 /* 400 KHz */
|
||||
#define CLKDEV_EMMC_DATA 52000000 /* 52 MHz */
|
||||
#define CLKDEV_MMC_DATA 20000000 /* 20 MHz */
|
||||
#define CLKDEV_INIT 400000 /* 400 kHz */
|
||||
|
||||
enum sh_mmcif_state {
|
||||
STATE_IDLE,
|
||||
|
@ -118,6 +118,9 @@ struct tmio_mmc_dma_ops {
|
||||
void (*release)(struct tmio_mmc_host *host);
|
||||
void (*abort)(struct tmio_mmc_host *host);
|
||||
void (*dataend)(struct tmio_mmc_host *host);
|
||||
|
||||
/* optional */
|
||||
void (*end)(struct tmio_mmc_host *host); /* held host->lock */
|
||||
};
|
||||
|
||||
struct tmio_mmc_host {
|
||||
|
@ -57,6 +57,12 @@ static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
|
||||
host->dma_ops->start(host, data);
|
||||
}
|
||||
|
||||
static inline void tmio_mmc_end_dma(struct tmio_mmc_host *host)
|
||||
{
|
||||
if (host->dma_ops && host->dma_ops->end)
|
||||
host->dma_ops->end(host);
|
||||
}
|
||||
|
||||
static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
|
||||
{
|
||||
if (host->dma_ops)
|
||||
@ -797,6 +803,8 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
tmio_mmc_end_dma(host);
|
||||
|
||||
mrq = host->mrq;
|
||||
if (IS_ERR_OR_NULL(mrq)) {
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
@ -1220,9 +1220,7 @@ static void via_sd_remove(struct pci_dev *pcidev)
|
||||
pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static void via_init_sdc_pm(struct via_crdr_mmc_host *host)
|
||||
static void __maybe_unused via_init_sdc_pm(struct via_crdr_mmc_host *host)
|
||||
{
|
||||
struct sdhcreg *pm_sdhcreg;
|
||||
void __iomem *addrbase;
|
||||
@ -1256,30 +1254,27 @@ static void via_init_sdc_pm(struct via_crdr_mmc_host *host)
|
||||
via_print_sdchc(host);
|
||||
}
|
||||
|
||||
static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state)
|
||||
static int __maybe_unused via_sd_suspend(struct device *dev)
|
||||
{
|
||||
struct via_crdr_mmc_host *host;
|
||||
|
||||
host = pci_get_drvdata(pcidev);
|
||||
host = dev_get_drvdata(dev);
|
||||
|
||||
via_save_pcictrlreg(host);
|
||||
via_save_sdcreg(host);
|
||||
|
||||
pci_save_state(pcidev);
|
||||
pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
|
||||
pci_disable_device(pcidev);
|
||||
pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
|
||||
device_wakeup_enable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int via_sd_resume(struct pci_dev *pcidev)
|
||||
static int __maybe_unused via_sd_resume(struct device *dev)
|
||||
{
|
||||
struct via_crdr_mmc_host *sdhost;
|
||||
int ret = 0;
|
||||
u8 gatt;
|
||||
|
||||
sdhost = pci_get_drvdata(pcidev);
|
||||
sdhost = dev_get_drvdata(dev);
|
||||
|
||||
gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON;
|
||||
if (sdhost->power == MMC_VDD_165_195)
|
||||
@ -1294,32 +1289,20 @@ static int via_sd_resume(struct pci_dev *pcidev)
|
||||
|
||||
msleep(100);
|
||||
|
||||
pci_set_power_state(pcidev, PCI_D0);
|
||||
pci_restore_state(pcidev);
|
||||
ret = pci_enable_device(pcidev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
via_restore_pcictrlreg(sdhost);
|
||||
via_init_sdc_pm(sdhost);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* CONFIG_PM */
|
||||
|
||||
#define via_sd_suspend NULL
|
||||
#define via_sd_resume NULL
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
static SIMPLE_DEV_PM_OPS(via_sd_pm_ops, via_sd_suspend, via_sd_resume);
|
||||
|
||||
static struct pci_driver via_sd_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = via_ids,
|
||||
.probe = via_sd_probe,
|
||||
.remove = via_sd_remove,
|
||||
.suspend = via_sd_suspend,
|
||||
.resume = via_sd_resume,
|
||||
.driver.pm = &via_sd_pm_ops,
|
||||
};
|
||||
|
||||
module_pci_driver(via_sd_driver);
|
||||
|
@ -1038,10 +1038,10 @@ static int rsi_probe(struct sdio_func *pfunction,
|
||||
goto fail_free_adapter;
|
||||
}
|
||||
|
||||
if (pfunction->device == RSI_SDIO_PID_9113) {
|
||||
if (pfunction->device == SDIO_DEVICE_ID_RSI_9113) {
|
||||
rsi_dbg(ERR_ZONE, "%s: 9113 module detected\n", __func__);
|
||||
adapter->device_model = RSI_DEV_9113;
|
||||
} else if (pfunction->device == RSI_SDIO_PID_9116) {
|
||||
} else if (pfunction->device == SDIO_DEVICE_ID_RSI_9116) {
|
||||
rsi_dbg(ERR_ZONE, "%s: 9116 module detected\n", __func__);
|
||||
adapter->device_model = RSI_DEV_9116;
|
||||
} else {
|
||||
@ -1526,8 +1526,8 @@ static const struct dev_pm_ops rsi_pm_ops = {
|
||||
#endif
|
||||
|
||||
static const struct sdio_device_id rsi_dev_table[] = {
|
||||
{ SDIO_DEVICE(RSI_SDIO_VENDOR_ID, RSI_SDIO_PID_9113) },
|
||||
{ SDIO_DEVICE(RSI_SDIO_VENDOR_ID, RSI_SDIO_PID_9116) },
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_RSI, SDIO_DEVICE_ID_RSI_9113) },
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_RSI, SDIO_DEVICE_ID_RSI_9116) },
|
||||
{ /* Blank */},
|
||||
};
|
||||
|
||||
|
@ -28,10 +28,6 @@
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include "rsi_main.h"
|
||||
|
||||
#define RSI_SDIO_VENDOR_ID 0x041B
|
||||
#define RSI_SDIO_PID_9113 0x9330
|
||||
#define RSI_SDIO_PID_9116 0x9116
|
||||
|
||||
enum sdio_interrupt_type {
|
||||
BUFFER_FULL = 0x0,
|
||||
BUFFER_AVAILABLE = 0x2,
|
||||
|
@ -287,6 +287,7 @@ struct mmc_host {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct notifier_block pm_notify;
|
||||
#endif
|
||||
struct wakeup_source *ws; /* Enable consume of uevents */
|
||||
u32 max_current_330;
|
||||
u32 max_current_300;
|
||||
u32 max_current_180;
|
||||
@ -351,6 +352,7 @@ struct mmc_host {
|
||||
|
||||
#define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
|
||||
#define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */
|
||||
#define MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND (1 << 3) /* Can do full power cycle in suspend */
|
||||
#define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */
|
||||
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
|
||||
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
|
||||
|
@ -118,6 +118,10 @@
|
||||
#define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100
|
||||
#define SDIO_DEVICE_ID_SIANO_STELLAR 0x5347
|
||||
|
||||
#define SDIO_VENDOR_ID_RSI 0x041b
|
||||
#define SDIO_DEVICE_ID_RSI_9113 0x9330
|
||||
#define SDIO_DEVICE_ID_RSI_9116 0x9116
|
||||
|
||||
#define SDIO_VENDOR_ID_TI_WL1251 0x104c
|
||||
#define SDIO_DEVICE_ID_TI_WL1251 0x9066
|
||||
|
||||
|
@ -116,3 +116,6 @@ struct omap_mmc_platform_data {
|
||||
|
||||
} slots[OMAP_MMC_MAX_SLOTS];
|
||||
};
|
||||
|
||||
extern void omap_mmc_notify_cover_event(struct device *dev, int slot,
|
||||
int is_closed);
|
||||
|
Loading…
Reference in New Issue
Block a user