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

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
  ...
parents 9aebd325 7f4bc2e8
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>;
};
# 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: ...@@ -169,6 +169,11 @@ properties:
description: description:
Full power cycle of the card is supported. 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: mmc-ddr-1_2v:
$ref: /schemas/types.yaml#/definitions/flag $ref: /schemas/types.yaml#/definitions/flag
description: description:
......
* 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>;
}
# 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>;
};
...
* 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>;
}
# 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>;
};
...
* 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";
}
# 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: ...@@ -12,6 +12,7 @@ Required properties:
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173 "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
"mediatek,mt8183-mmc": for mmc host ip compatible with mt8183 "mediatek,mt8183-mmc": for mmc host ip compatible with mt8183
"mediatek,mt8516-mmc": for mmc host ip compatible with mt8516 "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,mt2701-mmc": for mmc host ip compatible with mt2701
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712 "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
"mediatek,mt7622-mmc": for MT7622 SoC "mediatek,mt7622-mmc": for MT7622 SoC
......
* 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>;
};
# 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): ...@@ -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. Valid values are 33, 40, 50, 66 and 100 ohms.
Optional Properties: Optional Properties:
- ti,strobe-sel: strobe select delay for HS400 speed mode. Default value: 0x0. - ti,strobe-sel: strobe select delay for HS400 speed mode. Default value: 0x0.
- ti,clkbuf-sel: Clock Delay Buffer Select
Example: Example:
......
...@@ -54,6 +54,21 @@ Required properties: ...@@ -54,6 +54,21 @@ Required properties:
- qcom,dll-config: Chipset and Platform specific value. Use this field to - qcom,dll-config: Chipset and Platform specific value. Use this field to
specify the DLL_CONFIG register value as per Hardware Programming Guide. 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: Example:
sdhc_1: sdhci@f9824900 { sdhc_1: sdhci@f9824900 {
...@@ -71,6 +86,9 @@ Example: ...@@ -71,6 +86,9 @@ Example:
clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>; clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>;
clock-names = "core", "iface"; 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,dll-config = <0x000f642c>;
qcom,ddr-config = <0x80040868>; qcom,ddr-config = <0x80040868>;
......
...@@ -15383,7 +15383,7 @@ F: drivers/mmc/host/sdhci* ...@@ -15383,7 +15383,7 @@ F: drivers/mmc/host/sdhci*
F: include/linux/mmc/sdhci* F: include/linux/mmc/sdhci*
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER 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 L: linux-mmc@vger.kernel.org
S: Supported S: Supported
F: drivers/mmc/host/sdhci-of-at91.c F: drivers/mmc/host/sdhci-of-at91.c
......
...@@ -16,7 +16,3 @@ static inline int omap_msdi_reset(struct omap_hwmod *oh) ...@@ -16,7 +16,3 @@ static inline int omap_msdi_reset(struct omap_hwmod *oh)
return 0; return 0;
} }
#endif #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) ...@@ -793,11 +793,10 @@ static int jmb38x_ms_pmos(struct pci_dev *pdev, int flag)
return 0; return 0;
} }
#ifdef CONFIG_PM static int __maybe_unused jmb38x_ms_suspend(struct device *dev)
static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state)
{ {
struct jmb38x_ms *jm = pci_get_drvdata(dev); struct jmb38x_ms *jm = dev_get_drvdata(dev);
int cnt; int cnt;
for (cnt = 0; cnt < jm->host_cnt; ++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) ...@@ -806,26 +805,17 @@ static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state)
memstick_suspend_host(jm->hosts[cnt]); memstick_suspend_host(jm->hosts[cnt]);
} }
pci_save_state(dev); device_wakeup_disable(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));
return 0; 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; int rc;
pci_set_power_state(dev, PCI_D0); jmb38x_ms_pmos(to_pci_dev(dev), 1);
pci_restore_state(dev);
rc = pci_enable_device(dev);
if (rc)
return rc;
pci_set_master(dev);
jmb38x_ms_pmos(dev, 1);
for (rc = 0; rc < jm->host_cnt; ++rc) { for (rc = 0; rc < jm->host_cnt; ++rc) {
if (!jm->hosts[rc]) if (!jm->hosts[rc])
...@@ -837,13 +827,6 @@ static int jmb38x_ms_resume(struct pci_dev *dev) ...@@ -837,13 +827,6 @@ static int jmb38x_ms_resume(struct pci_dev *dev)
return 0; 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) static int jmb38x_ms_count_slots(struct pci_dev *pdev)
{ {
int cnt, rc = 0; int cnt, rc = 0;
...@@ -1030,13 +1013,14 @@ static struct pci_device_id jmb38x_ms_id_tbl [] = { ...@@ -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 = { static struct pci_driver jmb38x_ms_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = jmb38x_ms_id_tbl, .id_table = jmb38x_ms_id_tbl,
.probe = jmb38x_ms_probe, .probe = jmb38x_ms_probe,
.remove = jmb38x_ms_remove, .remove = jmb38x_ms_remove,
.suspend = jmb38x_ms_suspend, .driver.pm = &jmb38x_ms_pm_ops,
.resume = jmb38x_ms_resume
}; };
module_pci_driver(jmb38x_ms_driver); module_pci_driver(jmb38x_ms_driver);
......
...@@ -1455,12 +1455,12 @@ void mmc_detach_bus(struct mmc_host *host) ...@@ -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) 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 * Prevent system sleep for 5s to allow user space to consume the
* 5 s to give provision for user space to consume the event. * 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) && if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL))
device_can_wakeup(mmc_dev(host))) __pm_wakeup_event(host->ws, 5000);
pm_wakeup_event(mmc_dev(host), 5000);
host->detect_change = 1; host->detect_change = 1;
mmc_schedule_delayed_work(&host->detect, delay); mmc_schedule_delayed_work(&host->detect, delay);
...@@ -2303,7 +2303,6 @@ void mmc_start_host(struct mmc_host *host) ...@@ -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->f_init = max(min(freqs[0], host->f_max), host->f_min);
host->rescan_disable = 0; host->rescan_disable = 0;
host->ios.power_mode = MMC_POWER_UNDEFINED;
if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) { if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
mmc_claim_host(host); mmc_claim_host(host);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/pm_wakeup.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -36,6 +37,7 @@ static DEFINE_IDA(mmc_host_ida); ...@@ -36,6 +37,7 @@ static DEFINE_IDA(mmc_host_ida);
static void mmc_host_classdev_release(struct device *dev) static void mmc_host_classdev_release(struct device *dev)
{ {
struct mmc_host *host = cls_dev_to_mmc_host(dev); struct mmc_host *host = cls_dev_to_mmc_host(dev);
wakeup_source_unregister(host->ws);
ida_simple_remove(&mmc_host_ida, host->index); ida_simple_remove(&mmc_host_ida, host->index);
kfree(host); kfree(host);
} }
...@@ -275,6 +277,8 @@ int mmc_of_parse(struct mmc_host *host) ...@@ -275,6 +277,8 @@ int mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_SDIO_IRQ; host->caps |= MMC_CAP_SDIO_IRQ;
if (device_property_read_bool(dev, "full-pwr-cycle")) if (device_property_read_bool(dev, "full-pwr-cycle"))
host->caps2 |= MMC_CAP2_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")) if (device_property_read_bool(dev, "keep-power-in-suspend"))
host->pm_caps |= MMC_PM_KEEP_POWER; host->pm_caps |= MMC_PM_KEEP_POWER;
if (device_property_read_bool(dev, "wakeup-source") || if (device_property_read_bool(dev, "wakeup-source") ||
...@@ -400,6 +404,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -400,6 +404,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->index = err; host->index = err;
dev_set_name(&host->class_dev, "mmc%d", host->index); 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->parent = dev;
host->class_dev.parent = dev; host->class_dev.parent = dev;
...@@ -431,6 +436,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -431,6 +436,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->fixed_drv_type = -EINVAL; host->fixed_drv_type = -EINVAL;
host->ios.power_delay_ms = 10; host->ios.power_delay_ms = 10;
host->ios.power_mode = MMC_POWER_UNDEFINED;
return host; return host;
} }
......
...@@ -2038,7 +2038,8 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) ...@@ -2038,7 +2038,8 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
goto out; goto out;
if (mmc_can_poweroff_notify(host->card) && 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); err = mmc_poweroff_notify(host->card, notify_type);
else if (mmc_can_sleep(host->card)) else if (mmc_can_sleep(host->card))
err = mmc_sleep(host); err = mmc_sleep(host);
......
...@@ -203,7 +203,7 @@ static unsigned int mmc_get_max_segments(struct mmc_host *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 * mmc_init_request() - initialize the MMC-specific per-request data
* @q: the request queue * @mq: the request queue
* @req: the request * @req: the request
* @gfp: memory allocation policy * @gfp: memory allocation policy
*/ */
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "card.h" #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_EXT_CSD 113
#define INAND_CMD38_ARG_ERASE 0x00 #define INAND_CMD38_ARG_ERASE 0x00
#define INAND_CMD38_ARG_TRIM 0x01 #define INAND_CMD38_ARG_TRIM 0x01
...@@ -102,7 +102,7 @@ static const struct mmc_fixup mmc_blk_fixups[] = { ...@@ -102,7 +102,7 @@ static const struct mmc_fixup mmc_blk_fixups[] = {
END_FIXUP 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 * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
* is used so disable the HPI feature for such buggy cards. * is used so disable the HPI feature for such buggy cards.
...@@ -120,7 +120,7 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = { ...@@ -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, SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
......
...@@ -159,6 +159,8 @@ static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator, ...@@ -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_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. * 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 * 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) ...@@ -176,15 +176,18 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
if (mmc_host_uhs(card->host)) { if (mmc_host_uhs(card->host)) {
if (data & SDIO_UHS_DDR50) if (data & SDIO_UHS_DDR50)
card->sw_caps.sd3_bus_mode 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) if (data & SDIO_UHS_SDR50)
card->sw_caps.sd3_bus_mode 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) if (data & SDIO_UHS_SDR104)
card->sw_caps.sd3_bus_mode 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, ret = mmc_io_rw_direct(card, 0, 0,
...@@ -303,30 +306,49 @@ static int sdio_disable_wide(struct mmc_card *card) ...@@ -303,30 +306,49 @@ static int sdio_disable_wide(struct mmc_card *card)
return 0; 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) static int sdio_enable_4bit_bus(struct mmc_card *card)
{ {
int err; int err;
err = sdio_enable_wide(card);
if (err <= 0)
return err;
if (card->type == MMC_TYPE_SDIO) if (card->type == MMC_TYPE_SDIO)
err = sdio_enable_wide(card); goto out;
else if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { if (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
if (err) if (err) {
sdio_disable_wide(card);
return err; 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) ...@@ -518,10 +540,8 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
max_rate = min_not_zero(card->quirk_max_rate, max_rate = min_not_zero(card->quirk_max_rate,
card->sw_caps.uhs_max_dtr); card->sw_caps.uhs_max_dtr);
if (bus_speed) { mmc_set_timing(card->host, timing);
mmc_set_timing(card->host, timing); mmc_set_clock(card->host, max_rate);
mmc_set_clock(card->host, max_rate);
}
return 0; return 0;
} }
...@@ -972,7 +992,7 @@ static int mmc_sdio_suspend(struct mmc_host *host) ...@@ -972,7 +992,7 @@ static int mmc_sdio_suspend(struct mmc_host *host)
mmc_claim_host(host); mmc_claim_host(host);
if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(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)) { if (!mmc_card_keep_power(host)) {
mmc_power_off(host); mmc_power_off(host);
......
...@@ -133,7 +133,7 @@ int sdio_disable_func(struct sdio_func *func) ...@@ -133,7 +133,7 @@ int sdio_disable_func(struct sdio_func *func)
err: err:
pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func)); pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func));
return -EIO; return ret;
} }
EXPORT_SYMBOL_GPL(sdio_disable_func); EXPORT_SYMBOL_GPL(sdio_disable_func);
...@@ -709,6 +709,7 @@ EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps); ...@@ -709,6 +709,7 @@ EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps);
/** /**
* sdio_set_host_pm_flags - set wanted host power management capabilities * sdio_set_host_pm_flags - set wanted host power management capabilities
* @func: SDIO function attached to host * @func: SDIO function attached to host
* @flags: Power Management flags to set
* *
* Set a capability bitmask corresponding to wanted host controller * Set a capability bitmask corresponding to wanted host controller
* power management features for the upcoming suspend state. * power management features for the upcoming suspend state.
......
...@@ -1009,6 +1009,7 @@ config MMC_MTK ...@@ -1009,6 +1009,7 @@ config MMC_MTK
tristate "MediaTek SD/MMC Card Interface support" tristate "MediaTek SD/MMC Card Interface support"
depends on HAS_DMA depends on HAS_DMA
select REGULATOR select REGULATOR
select MMC_CQHCI
help help
This selects the MediaTek(R) Secure digital and Multimedia card Interface. 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. 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 { ...@@ -225,12 +225,13 @@ struct atmel_mci_dma {
* @lock: Spinlock protecting the queue and associated data. * @lock: Spinlock protecting the queue and associated data.
* @regs: Pointer to MMIO registers. * @regs: Pointer to MMIO registers.
* @sg: Scatterlist entry currently being processed by PIO or PDC code. * @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. * @pio_offset: Offset into the current scatterlist entry.
* @buffer: Buffer used if we don't have the r/w proof capability. We * @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 * don't have the time to switch pdc buffers so we have to use only
* one buffer for the full transaction. * one buffer for the full transaction.
* @buf_size: size of the buffer. * @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. * @cur_slot: The slot which is currently using the controller.
* @mrq: The request currently being processed on @cur_slot, * @mrq: The request currently being processed on @cur_slot,
* or NULL if the controller is idle. * or NULL if the controller is idle.
...@@ -240,6 +241,7 @@ struct atmel_mci_dma { ...@@ -240,6 +241,7 @@ struct atmel_mci_dma {
* @data_size: just data->blocks * data->blksz. * @data_size: just data->blocks * data->blksz.
* @dma: DMA client state. * @dma: DMA client state.
* @data_chan: DMA channel being used for the current data transfer. * @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 * @cmd_status: Snapshot of SR taken upon completion of the current
* command. Only valid when EVENT_CMD_COMPLETE is pending. * command. Only valid when EVENT_CMD_COMPLETE is pending.
* @data_status: Snapshot of SR taken upon completion of the current * @data_status: Snapshot of SR taken upon completion of the current
......
...@@ -144,7 +144,7 @@ static void cqhci_dumpregs(struct cqhci_host *cq_host) ...@@ -144,7 +144,7 @@ static void cqhci_dumpregs(struct cqhci_host *cq_host)
CQHCI_DUMP(": ===========================================\n"); CQHCI_DUMP(": ===========================================\n");
} }
/** /*
* The allocated descriptor table for task, link & transfer descritors * The allocated descriptor table for task, link & transfer descritors
* looks like: * looks like:
* |----------| * |----------|
...@@ -422,7 +422,7 @@ static void cqhci_prep_task_desc(struct mmc_request *mrq, ...@@ -422,7 +422,7 @@ static void cqhci_prep_task_desc(struct mmc_request *mrq,
CQHCI_BLK_COUNT(mrq->data->blocks) | CQHCI_BLK_COUNT(mrq->data->blocks) |
CQHCI_BLK_ADDR((u64)mrq->data->blk_addr); 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); mmc_hostname(mrq->host), mrq->tag, (unsigned long long)*data);
} }
......
...@@ -176,6 +176,7 @@ static int dw_mci_exynos_runtime_resume(struct device *dev) ...@@ -176,6 +176,7 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
/** /**
* dw_mci_exynos_suspend_noirq - Exynos-specific suspend code * 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 * This ensures that device will be in runtime active state in
* dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume() * 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) ...@@ -188,6 +189,7 @@ static int dw_mci_exynos_suspend_noirq(struct device *dev)
/** /**
* dw_mci_exynos_resume_noirq - Exynos-specific resume code * 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 * 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 * 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) ...@@ -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 dw_mci_exynos_priv_data *priv = host->priv;
struct mmc_host *mmc = slot->mmc; struct mmc_host *mmc = slot->mmc;
u8 start_smpl, smpl, candiates = 0; u8 start_smpl, smpl, candiates = 0;
s8 found = -1; s8 found;
int ret = 0; int ret = 0;
start_smpl = dw_mci_exynos_get_clksmpl(host); start_smpl = dw_mci_exynos_get_clksmpl(host);
......
...@@ -267,6 +267,7 @@ static struct variant_data variant_stm32_sdmmc = { ...@@ -267,6 +267,7 @@ static struct variant_data variant_stm32_sdmmc = {
.datalength_bits = 25, .datalength_bits = 25,
.datactrl_blocksz = 14, .datactrl_blocksz = 14,
.datactrl_any_blocksz = true, .datactrl_any_blocksz = true,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.stm32_idmabsize_mask = GENMASK(12, 5), .stm32_idmabsize_mask = GENMASK(12, 5),
.busy_timeout = true, .busy_timeout = true,
.busy_detect = true, .busy_detect = true,
...@@ -292,6 +293,7 @@ static struct variant_data variant_stm32_sdmmcv2 = { ...@@ -292,6 +293,7 @@ static struct variant_data variant_stm32_sdmmcv2 = {
.datalength_bits = 25, .datalength_bits = 25,
.datactrl_blocksz = 14, .datactrl_blocksz = 14,
.datactrl_any_blocksz = true, .datactrl_any_blocksz = true,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.stm32_idmabsize_mask = GENMASK(16, 5), .stm32_idmabsize_mask = GENMASK(16, 5),
.dma_lli = true, .dma_lli = true,
.busy_timeout = true, .busy_timeout = true,
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include <linux/mmc/sdio.h> #include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include "cqhci.h"
#define MAX_BD_NUM 1024 #define MAX_BD_NUM 1024
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
...@@ -152,6 +154,7 @@ ...@@ -152,6 +154,7 @@
#define MSDC_INT_DMA_BDCSERR (0x1 << 17) /* W1C */ #define MSDC_INT_DMA_BDCSERR (0x1 << 17) /* W1C */
#define MSDC_INT_DMA_GPDCSERR (0x1 << 18) /* W1C */ #define MSDC_INT_DMA_GPDCSERR (0x1 << 18) /* W1C */
#define MSDC_INT_DMA_PROTECT (0x1 << 19) /* W1C */ #define MSDC_INT_DMA_PROTECT (0x1 << 19) /* W1C */
#define MSDC_INT_CMDQ (0x1 << 28) /* W1C */
/* MSDC_INTEN mask */ /* MSDC_INTEN mask */
#define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */ #define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */
...@@ -182,6 +185,7 @@ ...@@ -182,6 +185,7 @@
/* SDC_CFG mask */ /* SDC_CFG mask */
#define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */ #define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */
#define SDC_CFG_INSWKUP (0x1 << 1) /* 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_BUSWIDTH (0x3 << 16) /* RW */
#define SDC_CFG_SDIO (0x1 << 19) /* RW */ #define SDC_CFG_SDIO (0x1 << 19) /* RW */
#define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */ #define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */
...@@ -230,6 +234,7 @@ ...@@ -230,6 +234,7 @@
#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */ #define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */
#define MSDC_PATCH_BIT1_CMDTA (0x7 << 3) /* RW */ #define MSDC_PATCH_BIT1_CMDTA (0x7 << 3) /* RW */
#define MSDC_PB1_BUSY_CHECK_SEL (0x1 << 7) /* RW */
#define MSDC_PATCH_BIT1_STOP_DLY (0xf << 8) /* RW */ #define MSDC_PATCH_BIT1_STOP_DLY (0xf << 8) /* RW */
#define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */ #define MSDC_PATCH_BIT2_CFGRESP (0x1 << 15) /* RW */
...@@ -431,9 +436,11 @@ struct msdc_host { ...@@ -431,9 +436,11 @@ struct msdc_host {
/* cmd response sample selection for HS400 */ /* cmd response sample selection for HS400 */
bool hs400_mode; /* current eMMC will run at hs400 mode */ bool hs400_mode; /* current eMMC will run at hs400 mode */
bool internal_cd; /* Use internal card-detect logic */ 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_save_para save_para; /* used when gate HCLK */
struct msdc_tune_para def_tune_para; /* default tune setting */ struct msdc_tune_para def_tune_para; /* default tune setting */
struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ 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 = { static const struct mtk_mmc_compatible mt8135_compat = {
...@@ -538,6 +545,18 @@ static const struct mtk_mmc_compatible mt7620_compat = { ...@@ -538,6 +545,18 @@ static const struct mtk_mmc_compatible mt7620_compat = {
.use_internal_cd = true, .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[] = { static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
...@@ -547,6 +566,7 @@ static const struct of_device_id msdc_of_ids[] = { ...@@ -547,6 +566,7 @@ static const struct of_device_id msdc_of_ids[] = {
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat}, { .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
{ .compatible = "mediatek,mt6779-mmc", .data = &mt6779_compat},
{} {}
}; };
MODULE_DEVICE_TABLE(of, msdc_of_ids); MODULE_DEVICE_TABLE(of, msdc_of_ids);
...@@ -710,21 +730,21 @@ static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq) ...@@ -710,21 +730,21 @@ static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq)
} }
} }
/* clock control primitives */ static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks)
static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
{ {
u32 timeout, clk_ns; u64 timeout, clk_ns;
u32 mode = 0; u32 mode = 0;
host->timeout_ns = ns;
host->timeout_clks = clks;
if (host->mmc->actual_clock == 0) { if (host->mmc->actual_clock == 0) {
timeout = 0; timeout = 0;
} else { } else {
clk_ns = 1000000000UL / host->mmc->actual_clock; clk_ns = 1000000000ULL;
timeout = (ns + clk_ns - 1) / clk_ns + clks; 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 */ /* 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) if (host->dev_comp->clk_div_bits == 8)
sdr_get_field(host->base + MSDC_CFG, sdr_get_field(host->base + MSDC_CFG,
MSDC_CFG_CKMOD, &mode); MSDC_CFG_CKMOD, &mode);
...@@ -734,9 +754,30 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) ...@@ -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 */ /*DDR mode will double the clk cycles for data timeout */
timeout = mode >= 2 ? timeout * 2 : timeout; timeout = mode >= 2 ? timeout * 2 : timeout;
timeout = timeout > 1 ? timeout - 1 : 0; 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) 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, ...@@ -1018,13 +1059,12 @@ static int msdc_auto_cmd_done(struct msdc_host *host, int events,
return cmd->error; return cmd->error;
} }
/** /*
* msdc_recheck_sdio_irq - recheck whether the SDIO irq is lost * msdc_recheck_sdio_irq - recheck whether the SDIO irq is lost
* *
* Host controller may lost interrupt in some special case. * Host controller may lost interrupt in some special case.
* Add SDIO irq recheck mechanism to make sure all interrupts * Add SDIO irq recheck mechanism to make sure all interrupts
* can be processed immediately * can be processed immediately
*
*/ */
static void msdc_recheck_sdio_irq(struct msdc_host *host) 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) ...@@ -1456,6 +1496,34 @@ static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
pm_runtime_put_noidle(host->dev); 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) static irqreturn_t msdc_irq(int irq, void *dev_id)
{ {
struct msdc_host *host = (struct msdc_host *) 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) ...@@ -1492,6 +1560,14 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ))) if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
break; 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) { if (!mrq) {
dev_err(host->dev, dev_err(host->dev,
"%s: MRQ=NULL; events=%08X; event_mask=%08X\n", "%s: MRQ=NULL; events=%08X; event_mask=%08X\n",
...@@ -2176,6 +2252,36 @@ static int msdc_get_cd(struct mmc_host *mmc) ...@@ -2176,6 +2252,36 @@ static int msdc_get_cd(struct mmc_host *mmc)
return !val; 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 = { static const struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req, .post_req = msdc_post_req,
.pre_req = msdc_pre_req, .pre_req = msdc_pre_req,
...@@ -2192,6 +2298,11 @@ static const struct mmc_host_ops mt_msdc_ops = { ...@@ -2192,6 +2298,11 @@ static const struct mmc_host_ops mt_msdc_ops = {
.hw_reset = msdc_hw_reset, .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, static void msdc_of_property_parse(struct platform_device *pdev,
struct msdc_host *host) struct msdc_host *host)
{ {
...@@ -2212,6 +2323,12 @@ static void msdc_of_property_parse(struct platform_device *pdev, ...@@ -2212,6 +2323,12 @@ static void msdc_of_property_parse(struct platform_device *pdev,
host->hs400_cmd_resp_sel_rising = true; host->hs400_cmd_resp_sel_rising = true;
else else
host->hs400_cmd_resp_sel_rising = false; 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) static int msdc_drv_probe(struct platform_device *pdev)
...@@ -2327,6 +2444,8 @@ 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->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
mmc->caps |= MMC_CAP_CMD23; mmc->caps |= MMC_CAP_CMD23;
if (host->cqhci)
mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
/* MMC core transfer sizes tunable parameters */ /* MMC core transfer sizes tunable parameters */
mmc->max_segs = MAX_BD_NUM; mmc->max_segs = MAX_BD_NUM;
if (host->dev_comp->support_64g) if (host->dev_comp->support_64g)
...@@ -2342,6 +2461,26 @@ static int msdc_drv_probe(struct platform_device *pdev) ...@@ -2342,6 +2461,26 @@ static int msdc_drv_probe(struct platform_device *pdev)
host->dma_mask = DMA_BIT_MASK(32); host->dma_mask = DMA_BIT_MASK(32);
mmc_dev(mmc)->dma_mask = &host->dma_mask; 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->timeout_clks = 3 * 1048576;
host->dma.gpd = dma_alloc_coherent(&pdev->dev, host->dma.gpd = dma_alloc_coherent(&pdev->dev,
2 * sizeof(struct mt_gpdma_desc), 2 * sizeof(struct mt_gpdma_desc),
......
...@@ -229,15 +229,15 @@ static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg) ...@@ -229,15 +229,15 @@ static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
DTRAN_CTRL_DM_START); 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; enum dma_data_direction dir;
spin_lock_irq(&host->lock); if (!host->dma_on)
return false;
if (!host->data) if (!host->data)
goto out; return false;
if (host->data->flags & MMC_DATA_READ) if (host->data->flags & MMC_DATA_READ)
dir = DMA_FROM_DEVICE; dir = DMA_FROM_DEVICE;
...@@ -250,11 +250,30 @@ static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg) ...@@ -250,11 +250,30 @@ static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
if (dir == DMA_FROM_DEVICE) if (dir == DMA_FROM_DEVICE)
clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags); 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); tmio_mmc_do_data_irq(host);
out: out:
spin_unlock_irq(&host->lock); 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 static void
renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host, renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
struct tmio_mmc_data *pdata) struct tmio_mmc_data *pdata)
...@@ -292,6 +311,7 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = { ...@@ -292,6 +311,7 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
.release = renesas_sdhi_internal_dmac_release_dma, .release = renesas_sdhi_internal_dmac_release_dma,
.abort = renesas_sdhi_internal_dmac_abort_dma, .abort = renesas_sdhi_internal_dmac_abort_dma,
.dataend = renesas_sdhi_internal_dmac_dataend_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) ...@@ -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) static void sd_wait_data_idle(struct realtek_pci_sdmmc *host)
{ {
int err, i; int i;
u8 val = 0; u8 val = 0;
for (i = 0; i < 100; i++) { 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) if (val & SD_DATA_IDLE)
return; return;
......
...@@ -654,12 +654,11 @@ static u8 sd_search_final_phase(struct rtsx_usb_sdmmc *host, u32 phase_map) ...@@ -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) static void sd_wait_data_idle(struct rtsx_usb_sdmmc *host)
{ {
int err, i; int i;
u8 val = 0; u8 val = 0;
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
err = rtsx_usb_ep0_read_register(host->ucr, rtsx_usb_ep0_read_register(host->ucr, SD_DATA_STATE, &val);
SD_DATA_STATE, &val);
if (val & SD_DATA_IDLE) if (val & SD_DATA_IDLE)
return; return;
......
...@@ -542,6 +542,7 @@ static int amd_select_drive_strength(struct mmc_card *card, ...@@ -542,6 +542,7 @@ static int amd_select_drive_strength(struct mmc_card *card,
unsigned int max_dtr, int host_drv, unsigned int max_dtr, int host_drv,
int card_drv, int *drv_type) int card_drv, int *drv_type)
{ {
*drv_type = MMC_SET_DRIVER_TYPE_A;
return MMC_SET_DRIVER_TYPE_A; return MMC_SET_DRIVER_TYPE_A;
} }
......
...@@ -202,57 +202,6 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv) ...@@ -202,57 +202,6 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp); return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
} }
static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
u32 mode;
switch (timing) {
case MMC_TIMING_MMC_HS:
mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
break;
case MMC_TIMING_MMC_DDR52:
mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
break;
case MMC_TIMING_MMC_HS200:
mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
break;
case MMC_TIMING_MMC_HS400:
if (priv->enhanced_strobe)
mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
else
mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
break;
default:
mode = SDHCI_CDNS_HRS06_MODE_SD;
break;
}
sdhci_cdns_set_emmc_mode(priv, mode);
/* For SD, fall back to the default handler */
if (mode == SDHCI_CDNS_HRS06_MODE_SD)
sdhci_set_uhs_signaling(host, timing);
}
static const struct sdhci_ops sdhci_cdns_ops = {
.set_clock = sdhci_set_clock,
.get_timeout_clock = sdhci_cdns_get_timeout_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
};
static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
.ops = &sdhci_cdns_ops,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
};
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) static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
{ {
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
...@@ -286,23 +235,24 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val) ...@@ -286,23 +235,24 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
return 0; return 0;
} }
static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode) /*
* 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)
{ {
struct sdhci_host *host = mmc_priv(mmc);
int cur_streak = 0; int cur_streak = 0;
int max_streak = 0; int max_streak = 0;
int end_of_streak = 0; int end_of_streak = 0;
int i; int i;
/* /*
* This handler only implements the eMMC tuning that is specific to * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
* this controller. Fall back to the standard method for SD timing. * The delay is set by probe, based on the DT properties.
*/ */
if (host->timing != MMC_TIMING_MMC_HS200) if (host->timing != MMC_TIMING_MMC_HS200 &&
return sdhci_execute_tuning(mmc, opcode); host->timing != MMC_TIMING_UHS_SDR104)
return 0;
if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
return -EINVAL;
for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) { for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
if (sdhci_cdns_set_tune_val(host, i) || if (sdhci_cdns_set_tune_val(host, i) ||
...@@ -325,6 +275,58 @@ static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -325,6 +275,58 @@ static int sdhci_cdns_execute_tuning(struct mmc_host *mmc, u32 opcode)
return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2); 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)
{
struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host);
u32 mode;
switch (timing) {
case MMC_TIMING_MMC_HS:
mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR;
break;
case MMC_TIMING_MMC_DDR52:
mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR;
break;
case MMC_TIMING_MMC_HS200:
mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200;
break;
case MMC_TIMING_MMC_HS400:
if (priv->enhanced_strobe)
mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400ES;
else
mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400;
break;
default:
mode = SDHCI_CDNS_HRS06_MODE_SD;
break;
}
sdhci_cdns_set_emmc_mode(priv, mode);
/* For SD, fall back to the default handler */
if (mode == SDHCI_CDNS_HRS06_MODE_SD)
sdhci_set_uhs_signaling(host, timing);
}
static const struct sdhci_ops sdhci_cdns_ops = {
.set_clock = sdhci_set_clock,
.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,
};
static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
.ops = &sdhci_cdns_ops,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
};
static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
.ops = &sdhci_cdns_ops,
};
static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc, static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios) struct mmc_ios *ios)
{ {
...@@ -385,7 +387,6 @@ static int sdhci_cdns_probe(struct platform_device *pdev) ...@@ -385,7 +387,6 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
priv->hrs_addr = host->ioaddr; priv->hrs_addr = host->ioaddr;
priv->enhanced_strobe = false; priv->enhanced_strobe = false;
host->ioaddr += SDHCI_CDNS_SRS_BASE; host->ioaddr += SDHCI_CDNS_SRS_BASE;
host->mmc_host_ops.execute_tuning = sdhci_cdns_execute_tuning;
host->mmc_host_ops.hs400_enhanced_strobe = host->mmc_host_ops.hs400_enhanced_strobe =
sdhci_cdns_hs400_enhanced_strobe; sdhci_cdns_hs400_enhanced_strobe;
sdhci_enable_v4_mode(host); sdhci_enable_v4_mode(host);
......
...@@ -38,6 +38,16 @@ ...@@ -38,6 +38,16 @@
#define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1) #define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1)
#define ESDHC_VENDOR_SPEC_VSELECT (1 << 1) #define ESDHC_VENDOR_SPEC_VSELECT (1 << 1)
#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8) #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_LVL 0x44
#define ESDHC_WTMK_DEFAULT_VAL 0x10401040 #define ESDHC_WTMK_DEFAULT_VAL 0x10401040
#define ESDHC_WTMK_LVL_RD_WML_MASK 0x000000FF #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 ...@@ -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); 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) static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
{ {
u32 present_state; u32 present_state;
...@@ -1237,6 +1275,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { ...@@ -1237,6 +1275,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.set_uhs_signaling = esdhc_set_uhs_signaling, .set_uhs_signaling = esdhc_set_uhs_signaling,
.reset = esdhc_reset, .reset = esdhc_reset,
.irq = esdhc_cqhci_irq, .irq = esdhc_cqhci_irq,
.dump_vendor_regs = esdhc_dump_debug_regs,
}; };
static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
......
...@@ -294,12 +294,14 @@ static const struct of_device_id sdhci_iproc_of_match[] = { ...@@ -294,12 +294,14 @@ static const struct of_device_id sdhci_iproc_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, 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[] = { static const struct acpi_device_id sdhci_iproc_acpi_ids[] = {
{ .id = "BRCM5871", .driver_data = (kernel_ulong_t)&iproc_cygnus_data }, { .id = "BRCM5871", .driver_data = (kernel_ulong_t)&iproc_cygnus_data },
{ .id = "BRCM5872", .driver_data = (kernel_ulong_t)&iproc_data }, { .id = "BRCM5872", .driver_data = (kernel_ulong_t)&iproc_data },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(acpi, sdhci_iproc_acpi_ids); MODULE_DEVICE_TABLE(acpi, sdhci_iproc_acpi_ids);
#endif
static int sdhci_iproc_probe(struct platform_device *pdev) static int sdhci_iproc_probe(struct platform_device *pdev)
{ {
......
This diff is collapsed.
...@@ -1025,7 +1025,6 @@ static void arasan_dt_read_clk_phase(struct device *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, static void arasan_dt_parse_clk_phases(struct device *dev,
struct sdhci_arasan_clk_data *clk_data) struct sdhci_arasan_clk_data *clk_data)
{ {
int *iclk_phase, *oclk_phase;
u32 mio_bank = 0; u32 mio_bank = 0;
int i; int i;
...@@ -1037,28 +1036,32 @@ static void arasan_dt_parse_clk_phases(struct device *dev, ...@@ -1037,28 +1036,32 @@ static void arasan_dt_parse_clk_phases(struct device *dev,
clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; clk_data->set_clk_delays = sdhci_arasan_set_clk_delays;
if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) { if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) {
iclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) ZYNQMP_ICLK_PHASE; u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
oclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) ZYNQMP_OCLK_PHASE; 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); of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank);
if (mio_bank == 2) { if (mio_bank == 2) {
oclk_phase[MMC_TIMING_UHS_SDR104] = 90; zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90;
oclk_phase[MMC_TIMING_MMC_HS200] = 90; zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90;
} }
for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
clk_data->clk_phase_in[i] = iclk_phase[i]; clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i];
clk_data->clk_phase_out[i] = oclk_phase[i]; clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i];
} }
} }
if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) { if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) {
iclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) VERSAL_ICLK_PHASE; u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] =
oclk_phase = (int [MMC_TIMING_MMC_HS400 + 1]) VERSAL_OCLK_PHASE; VERSAL_ICLK_PHASE;
u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] =
VERSAL_OCLK_PHASE;
for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) {
clk_data->clk_phase_in[i] = iclk_phase[i]; clk_data->clk_phase_in[i] = versal_iclk_phase[i];
clk_data->clk_phase_out[i] = oclk_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, ...@@ -1299,6 +1302,8 @@ sdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan,
clk_data->sdcardclk_hw.init = &sdcardclk_init; clk_data->sdcardclk_hw.init = &sdcardclk_init;
clk_data->sdcardclk = clk_data->sdcardclk =
devm_clk_register(dev, &clk_data->sdcardclk_hw); 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; clk_data->sdcardclk_hw.init = NULL;
ret = of_clk_add_provider(np, of_clk_src_simple_get, 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, ...@@ -1349,6 +1354,8 @@ sdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan,
clk_data->sampleclk_hw.init = &sampleclk_init; clk_data->sampleclk_hw.init = &sampleclk_init;
clk_data->sampleclk = clk_data->sampleclk =
devm_clk_register(dev, &clk_data->sampleclk_hw); 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; clk_data->sampleclk_hw.init = NULL;
ret = of_clk_add_provider(np, of_clk_src_simple_get, ret = of_clk_add_provider(np, of_clk_src_simple_get,
...@@ -1388,7 +1395,8 @@ static void sdhci_arasan_unregister_sdclk(struct device *dev) ...@@ -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. * - For Keem Bay, it is required to clear this bit. Its default value is 1'b1.
* Keem Bay does not support 64-bit access. * 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) static void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value)
{ {
......
...@@ -31,10 +31,18 @@ ...@@ -31,10 +31,18 @@
#define SDHCI_GLI_9750_ALL_RST (BIT(24)|BIT(25)|BIT(28)|BIT(30)) #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 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_INV BIT(23)
#define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20) #define SDHCI_GLI_9750_PLL_TX2_DLY GENMASK(22, 20)
#define GLI_9750_PLL_TX2_INV_VALUE 0x1 #define GLI_9750_PLL_TX2_INV_VALUE 0x1
#define GLI_9750_PLL_TX2_DLY_VALUE 0x0 #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 0x874
#define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6) #define SDHCI_GLI_9750_SW_CTRL_4 GENMASK(7, 6)
...@@ -76,6 +84,21 @@ ...@@ -76,6 +84,21 @@
#define PCIE_GLI_9763E_SCR 0x8E0 #define PCIE_GLI_9763E_SCR 0x8E0
#define GLI_9763E_SCR_AXI_REQ BIT(9) #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 #define GLI_MAX_TUNING_LOOP 40
/* Genesys Logic chipset */ /* Genesys Logic chipset */
...@@ -280,6 +303,84 @@ static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode) ...@@ -280,6 +303,84 @@ static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode)
return 0; 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) static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot)
{ {
int ret; int ret;
...@@ -295,6 +396,121 @@ static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot) ...@@ -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); 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) static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
{ {
struct sdhci_host *host = slot->host; struct sdhci_host *host = slot->host;
...@@ -440,7 +656,7 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot) ...@@ -440,7 +656,7 @@ static int gli_probe_slot_gl9763e(struct sdhci_pci_slot *slot)
} }
static const struct sdhci_ops sdhci_gl9755_ops = { 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, .enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_reset,
...@@ -460,7 +676,7 @@ const struct sdhci_pci_fixes sdhci_gl9755 = { ...@@ -460,7 +676,7 @@ const struct sdhci_pci_fixes sdhci_gl9755 = {
static const struct sdhci_ops sdhci_gl9750_ops = { static const struct sdhci_ops sdhci_gl9750_ops = {
.read_l = sdhci_gl9750_readl, .read_l = sdhci_gl9750_readl,
.set_clock = sdhci_set_clock, .set_clock = sdhci_gl9750_set_clock,
.enable_dma = sdhci_pci_enable_dma, .enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_gl9750_reset, .reset = sdhci_gl9750_reset,
......
...@@ -196,7 +196,7 @@ static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode) ...@@ -196,7 +196,7 @@ static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode)
{ {
int i; int i;
sdhci_send_tuning(host, MMC_SEND_TUNING_BLOCK_HS200); sdhci_send_tuning(host, opcode);
for (i = 0; i < 150; i++) { for (i = 0; i < 150; i++) {
u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
...@@ -305,10 +305,12 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -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 handler only implements the eMMC tuning that is specific to
* this controller. Fall back to the standard method for other TIMING. * 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); 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; return -EINVAL;
/* /*
* Judge the tuning reason, whether caused by dll shift * 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) ...@@ -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_set_bus_width(host, current_bus_width);
} }
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
host->flags &= ~SDHCI_HS400_TUNING; host->flags &= ~SDHCI_HS400_TUNING;
return 0; return 0;
} }
...@@ -369,7 +374,6 @@ static void o2_pci_led_enable(struct sdhci_pci_chip *chip) ...@@ -369,7 +374,6 @@ static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
scratch_32 |= O2_SD_LED_ENABLE; scratch_32 |= O2_SD_LED_ENABLE;
pci_write_config_dword(chip->pdev, pci_write_config_dword(chip->pdev,
O2_SD_TEST_REG, scratch_32); O2_SD_TEST_REG, scratch_32);
} }
static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) 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) ...@@ -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) static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
{ {
u16 clk; 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; host->mmc->actual_clock = 0;
...@@ -505,6 +513,23 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -505,6 +513,23 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock == 0) if (clock == 0)
return; return;
if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) {
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); clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
sdhci_o2_enable_clk(host, clk); sdhci_o2_enable_clk(host, clk);
} }
...@@ -561,6 +586,12 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) ...@@ -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; 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; host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning;
if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2) if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
......
...@@ -107,8 +107,11 @@ ...@@ -107,8 +107,11 @@
* @ioarea: The resource created when we claimed the IO area. * @ioarea: The resource created when we claimed the IO area.
* @pdata: The platform data for this controller. * @pdata: The platform data for this controller.
* @cur_clk: The index of the current bus clock. * @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_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. * @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_s3c {
struct sdhci_host *host; struct sdhci_host *host;
...@@ -128,6 +131,7 @@ struct sdhci_s3c { ...@@ -128,6 +131,7 @@ struct sdhci_s3c {
/** /**
* struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data * struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data
* @sdhci_quirks: sdhci host specific quirks. * @sdhci_quirks: sdhci host specific quirks.
* @no_divider: no or non-standard internal clock divider.
* *
* Specifies platform specific configuration of sdhci controller. * Specifies platform specific configuration of sdhci controller.
* Note: A structure for driver specific platform data is used for future * Note: A structure for driver specific platform data is used for future
......
...@@ -96,7 +96,16 @@ ...@@ -96,7 +96,16 @@
#define NVQUIRK_ENABLE_SDR50 BIT(3) #define NVQUIRK_ENABLE_SDR50 BIT(3)
#define NVQUIRK_ENABLE_SDR104 BIT(4) #define NVQUIRK_ENABLE_SDR104 BIT(4)
#define NVQUIRK_ENABLE_DDR50 BIT(5) #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) #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_NEEDS_PAD_CONTROL BIT(7)
#define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8) #define NVQUIRK_DIS_CARD_CLK_CONFIG_TAP BIT(8)
#define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING BIT(9) #define NVQUIRK_CQHCI_DCMD_R1B_CMD_TIMING BIT(9)
......
...@@ -4104,7 +4104,8 @@ int sdhci_setup_host(struct sdhci_host *host) ...@@ -4104,7 +4104,8 @@ int sdhci_setup_host(struct sdhci_host *host)
unsigned int ocr_avail; unsigned int ocr_avail;
unsigned int override_timeout_clk; unsigned int override_timeout_clk;
u32 max_clk; u32 max_clk;
int ret; int ret = 0;
bool enable_vqmmc = false;
WARN_ON(host == NULL); WARN_ON(host == NULL);
if (host == NULL) if (host == NULL)
...@@ -4118,9 +4119,12 @@ int sdhci_setup_host(struct sdhci_host *host) ...@@ -4118,9 +4119,12 @@ int sdhci_setup_host(struct sdhci_host *host)
* the host can take the appropriate action if regulators are not * the host can take the appropriate action if regulators are not
* available. * available.
*/ */
ret = mmc_regulator_get_supply(mmc); if (!mmc->supply.vqmmc) {
if (ret) ret = mmc_regulator_get_supply(mmc);
return ret; if (ret)
return ret;
enable_vqmmc = true;
}
DBG("Version: 0x%08x | Present: 0x%08x\n", DBG("Version: 0x%08x | Present: 0x%08x\n",
sdhci_readw(host, SDHCI_HOST_VERSION), sdhci_readw(host, SDHCI_HOST_VERSION),
...@@ -4377,7 +4381,10 @@ int sdhci_setup_host(struct sdhci_host *host) ...@@ -4377,7 +4381,10 @@ int sdhci_setup_host(struct sdhci_host *host)
mmc->caps |= MMC_CAP_NEEDS_POLL; mmc->caps |= MMC_CAP_NEEDS_POLL;
if (!IS_ERR(mmc->supply.vqmmc)) { 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 vqmmc provides no 1.8V signalling, then there's no UHS */
if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000, if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000,
...@@ -4396,6 +4403,7 @@ int sdhci_setup_host(struct sdhci_host *host) ...@@ -4396,6 +4403,7 @@ int sdhci_setup_host(struct sdhci_host *host)
mmc_hostname(mmc), ret); mmc_hostname(mmc), ret);
mmc->supply.vqmmc = ERR_PTR(-EINVAL); mmc->supply.vqmmc = ERR_PTR(-EINVAL);
} }
} }
if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) { if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
...@@ -4626,7 +4634,7 @@ int sdhci_setup_host(struct sdhci_host *host) ...@@ -4626,7 +4634,7 @@ int sdhci_setup_host(struct sdhci_host *host)
return 0; return 0;
unreg: unreg:
if (!IS_ERR(mmc->supply.vqmmc)) if (host->sdhci_core_to_disable_vqmmc)
regulator_disable(mmc->supply.vqmmc); regulator_disable(mmc->supply.vqmmc);
undma: undma:
if (host->align_buffer) if (host->align_buffer)
...@@ -4644,7 +4652,7 @@ void sdhci_cleanup_host(struct sdhci_host *host) ...@@ -4644,7 +4652,7 @@ void sdhci_cleanup_host(struct sdhci_host *host)
{ {
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
if (!IS_ERR(mmc->supply.vqmmc)) if (host->sdhci_core_to_disable_vqmmc)
regulator_disable(mmc->supply.vqmmc); regulator_disable(mmc->supply.vqmmc);
if (host->align_buffer) if (host->align_buffer)
...@@ -4787,7 +4795,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) ...@@ -4787,7 +4795,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
destroy_workqueue(host->complete_wq); destroy_workqueue(host->complete_wq);
if (!IS_ERR(mmc->supply.vqmmc)) if (host->sdhci_core_to_disable_vqmmc)
regulator_disable(mmc->supply.vqmmc); regulator_disable(mmc->supply.vqmmc);
if (host->align_buffer) if (host->align_buffer)
......
...@@ -567,6 +567,7 @@ struct sdhci_host { ...@@ -567,6 +567,7 @@ struct sdhci_host {
u32 caps1; /* CAPABILITY_1 */ u32 caps1; /* CAPABILITY_1 */
bool read_caps; /* Capability flags have been read */ 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_sdio; /* OCR bit masks */
unsigned int ocr_avail_sd; unsigned int ocr_avail_sd;
unsigned int ocr_avail_mmc; unsigned int ocr_avail_mmc;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/sys_soc.h>
#include "cqhci.h" #include "cqhci.h"
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
...@@ -46,6 +47,8 @@ ...@@ -46,6 +47,8 @@
#define SEL100_MASK BIT(SEL100_SHIFT) #define SEL100_MASK BIT(SEL100_SHIFT)
#define FREQSEL_SHIFT 8 #define FREQSEL_SHIFT 8
#define FREQSEL_MASK GENMASK(10, 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_SHIFT 4
#define DLL_TRIM_ICP_MASK GENMASK(7, 4) #define DLL_TRIM_ICP_MASK GENMASK(7, 4)
#define DR_TY_SHIFT 20 #define DR_TY_SHIFT 20
...@@ -60,6 +63,8 @@ ...@@ -60,6 +63,8 @@
#define CALDONE_MASK BIT(CALDONE_SHIFT) #define CALDONE_MASK BIT(CALDONE_SHIFT)
#define RETRIM_SHIFT 17 #define RETRIM_SHIFT 17
#define RETRIM_MASK BIT(RETRIM_SHIFT) #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_50_OHM 0x0
#define DRIVER_STRENGTH_33_OHM 0x1 #define DRIVER_STRENGTH_33_OHM 0x1
...@@ -83,6 +88,7 @@ struct sdhci_am654_data { ...@@ -83,6 +88,7 @@ struct sdhci_am654_data {
struct regmap *base; struct regmap *base;
bool legacy_otapdly; bool legacy_otapdly;
int otap_del_sel[11]; int otap_del_sel[11];
int clkbuf_sel;
int trm_icp; int trm_icp;
int drv_strength; int drv_strength;
bool dll_on; bool dll_on;
...@@ -97,6 +103,7 @@ struct sdhci_am654_driver_data { ...@@ -97,6 +103,7 @@ struct sdhci_am654_driver_data {
#define FREQSEL_2_BIT (1 << 1) #define FREQSEL_2_BIT (1 << 1)
#define STRBSEL_4_BIT (1 << 2) #define STRBSEL_4_BIT (1 << 2)
#define DLL_PRESENT (1 << 3) #define DLL_PRESENT (1 << 3)
#define DLL_CALIB (1 << 4)
}; };
struct timing_data { struct timing_data {
...@@ -202,34 +209,41 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -202,34 +209,41 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_set_clock(host, clock); sdhci_set_clock(host, clock);
if (clock > CLOCK_TOO_SLOW_HZ) { /* Setup DLL Output TAP delay */
/* Setup DLL Output TAP delay */ if (sdhci_am654->legacy_otapdly)
if (sdhci_am654->legacy_otapdly) otap_del_sel = sdhci_am654->otap_del_sel[0];
otap_del_sel = sdhci_am654->otap_del_sel[0]; else
else otap_del_sel = sdhci_am654->otap_del_sel[timing];
otap_del_sel = sdhci_am654->otap_del_sel[timing];
otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0; otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0;
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (otap_del_ena << OTAPDLYENA_SHIFT) | val = (otap_del_ena << OTAPDLYENA_SHIFT) |
(otap_del_sel << OTAPDLYSEL_SHIFT); (otap_del_sel << OTAPDLYSEL_SHIFT);
/* Write to STRBSEL for HS400 speed mode */ /* Write to STRBSEL for HS400 speed mode */
if (timing == MMC_TIMING_MMC_HS400) { if (timing == MMC_TIMING_MMC_HS400) {
if (sdhci_am654->flags & STRBSEL_4_BIT) if (sdhci_am654->flags & STRBSEL_4_BIT)
mask |= STRBSEL_4BIT_MASK; mask |= STRBSEL_4BIT_MASK;
else else
mask |= STRBSEL_8BIT_MASK; mask |= STRBSEL_8BIT_MASK;
val |= sdhci_am654->strb_sel << STRBSEL_SHIFT; val |= sdhci_am654->strb_sel << STRBSEL_SHIFT;
} }
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
if (timing > MMC_TIMING_UHS_SDR25) if (timing > MMC_TIMING_UHS_SDR25 && clock > CLOCK_TOO_SLOW_HZ) {
sdhci_am654_setup_dll(host, clock); 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, 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, ...@@ -252,6 +266,9 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
(otap_del_sel << OTAPDLYSEL_SHIFT); (otap_del_sel << OTAPDLYSEL_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val); 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); sdhci_set_clock(host, clock);
} }
...@@ -323,6 +340,12 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = { ...@@ -323,6 +340,12 @@ static const struct sdhci_pltfm_data sdhci_am654_pdata = {
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .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 = { static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
.pdata = &sdhci_am654_pdata, .pdata = &sdhci_am654_pdata,
.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT, .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 = { ...@@ -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 = { static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
.pdata = &sdhci_j721e_8bit_pdata, .pdata = &sdhci_j721e_8bit_pdata,
.flags = DLL_PRESENT, .flags = DLL_PRESENT | DLL_CALIB,
}; };
static struct sdhci_ops sdhci_j721e_4bit_ops = { static struct sdhci_ops sdhci_j721e_4bit_ops = {
...@@ -374,6 +397,14 @@ static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = { ...@@ -374,6 +397,14 @@ static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = {
.flags = IOMUX_PRESENT, .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) static void sdhci_am654_dumpregs(struct mmc_host *mmc)
{ {
sdhci_dumpregs(mmc_priv(mmc)); sdhci_dumpregs(mmc_priv(mmc));
...@@ -469,7 +500,7 @@ static int sdhci_am654_init(struct sdhci_host *host) ...@@ -469,7 +500,7 @@ static int sdhci_am654_init(struct sdhci_host *host)
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK; mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, 0x0); 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); regmap_read(sdhci_am654->base, PHY_STAT1, &val);
if (~val & CALDONE_MASK) { if (~val & CALDONE_MASK) {
/* Calibrate IO lines */ /* Calibrate IO lines */
...@@ -560,6 +591,8 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev, ...@@ -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,strobe-sel", &sdhci_am654->strb_sel);
device_property_read_u32(dev, "ti,clkbuf-sel",
&sdhci_am654->clkbuf_sel);
sdhci_get_of_property(pdev); sdhci_get_of_property(pdev);
...@@ -585,6 +618,7 @@ static const struct of_device_id sdhci_am654_of_match[] = { ...@@ -585,6 +618,7 @@ static const struct of_device_id sdhci_am654_of_match[] = {
static int sdhci_am654_probe(struct platform_device *pdev) static int sdhci_am654_probe(struct platform_device *pdev)
{ {
const struct sdhci_am654_driver_data *drvdata; const struct sdhci_am654_driver_data *drvdata;
const struct soc_device_attribute *soc;
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
struct sdhci_am654_data *sdhci_am654; struct sdhci_am654_data *sdhci_am654;
const struct of_device_id *match; const struct of_device_id *match;
...@@ -596,6 +630,12 @@ static int sdhci_am654_probe(struct platform_device *pdev) ...@@ -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); match = of_match_node(sdhci_am654_of_match, pdev->dev.of_node);
drvdata = match->data; 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)); host = sdhci_pltfm_init(pdev, drvdata->pdata, sizeof(*sdhci_am654));
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
......
...@@ -191,9 +191,9 @@ ...@@ -191,9 +191,9 @@
STS2_AC12BSYTO | STS2_RSPBSYTO | \ STS2_AC12BSYTO | STS2_RSPBSYTO | \
STS2_AC12RSPTO | STS2_RSPTO) STS2_AC12RSPTO | STS2_RSPTO)
#define CLKDEV_EMMC_DATA 52000000 /* 52MHz */ #define CLKDEV_EMMC_DATA 52000000 /* 52 MHz */
#define CLKDEV_MMC_DATA 20000000 /* 20MHz */ #define CLKDEV_MMC_DATA 20000000 /* 20 MHz */
#define CLKDEV_INIT 400000 /* 400 KHz */ #define CLKDEV_INIT 400000 /* 400 kHz */
enum sh_mmcif_state { enum sh_mmcif_state {
STATE_IDLE, STATE_IDLE,
......
...@@ -118,6 +118,9 @@ struct tmio_mmc_dma_ops { ...@@ -118,6 +118,9 @@ struct tmio_mmc_dma_ops {
void (*release)(struct tmio_mmc_host *host); void (*release)(struct tmio_mmc_host *host);
void (*abort)(struct tmio_mmc_host *host); void (*abort)(struct tmio_mmc_host *host);
void (*dataend)(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 { struct tmio_mmc_host {
......
...@@ -57,6 +57,12 @@ static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, ...@@ -57,6 +57,12 @@ static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
host->dma_ops->start(host, data); 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) static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
{ {
if (host->dma_ops) if (host->dma_ops)
...@@ -797,6 +803,8 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) ...@@ -797,6 +803,8 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
tmio_mmc_end_dma(host);
mrq = host->mrq; mrq = host->mrq;
if (IS_ERR_OR_NULL(mrq)) { if (IS_ERR_OR_NULL(mrq)) {
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
......
...@@ -1220,9 +1220,7 @@ static void via_sd_remove(struct pci_dev *pcidev) ...@@ -1220,9 +1220,7 @@ static void via_sd_remove(struct pci_dev *pcidev)
pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device); pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device);
} }
#ifdef CONFIG_PM static void __maybe_unused via_init_sdc_pm(struct via_crdr_mmc_host *host)
static void via_init_sdc_pm(struct via_crdr_mmc_host *host)
{ {
struct sdhcreg *pm_sdhcreg; struct sdhcreg *pm_sdhcreg;
void __iomem *addrbase; void __iomem *addrbase;
...@@ -1256,30 +1254,27 @@ static void via_init_sdc_pm(struct via_crdr_mmc_host *host) ...@@ -1256,30 +1254,27 @@ static void via_init_sdc_pm(struct via_crdr_mmc_host *host)
via_print_sdchc(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; struct via_crdr_mmc_host *host;
host = pci_get_drvdata(pcidev); host = dev_get_drvdata(dev);
via_save_pcictrlreg(host); via_save_pcictrlreg(host);
via_save_sdcreg(host); via_save_sdcreg(host);
pci_save_state(pcidev); device_wakeup_enable(dev);
pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
pci_disable_device(pcidev);
pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
return 0; 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; struct via_crdr_mmc_host *sdhost;
int ret = 0; int ret = 0;
u8 gatt; u8 gatt;
sdhost = pci_get_drvdata(pcidev); sdhost = dev_get_drvdata(dev);
gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON; gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON;
if (sdhost->power == MMC_VDD_165_195) if (sdhost->power == MMC_VDD_165_195)
...@@ -1294,32 +1289,20 @@ static int via_sd_resume(struct pci_dev *pcidev) ...@@ -1294,32 +1289,20 @@ static int via_sd_resume(struct pci_dev *pcidev)
msleep(100); 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_restore_pcictrlreg(sdhost);
via_init_sdc_pm(sdhost); via_init_sdc_pm(sdhost);
return ret; return ret;
} }
#else /* CONFIG_PM */ static SIMPLE_DEV_PM_OPS(via_sd_pm_ops, via_sd_suspend, via_sd_resume);
#define via_sd_suspend NULL
#define via_sd_resume NULL
#endif /* CONFIG_PM */
static struct pci_driver via_sd_driver = { static struct pci_driver via_sd_driver = {
.name = DRV_NAME, .name = DRV_NAME,
.id_table = via_ids, .id_table = via_ids,
.probe = via_sd_probe, .probe = via_sd_probe,
.remove = via_sd_remove, .remove = via_sd_remove,
.suspend = via_sd_suspend, .driver.pm = &via_sd_pm_ops,
.resume = via_sd_resume,
}; };
module_pci_driver(via_sd_driver); module_pci_driver(via_sd_driver);
......
...@@ -1038,10 +1038,10 @@ static int rsi_probe(struct sdio_func *pfunction, ...@@ -1038,10 +1038,10 @@ static int rsi_probe(struct sdio_func *pfunction,
goto fail_free_adapter; 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__); rsi_dbg(ERR_ZONE, "%s: 9113 module detected\n", __func__);
adapter->device_model = RSI_DEV_9113; 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__); rsi_dbg(ERR_ZONE, "%s: 9116 module detected\n", __func__);
adapter->device_model = RSI_DEV_9116; adapter->device_model = RSI_DEV_9116;
} else { } else {
...@@ -1526,8 +1526,8 @@ static const struct dev_pm_ops rsi_pm_ops = { ...@@ -1526,8 +1526,8 @@ static const struct dev_pm_ops rsi_pm_ops = {
#endif #endif
static const struct sdio_device_id rsi_dev_table[] = { static const struct sdio_device_id rsi_dev_table[] = {
{ SDIO_DEVICE(RSI_SDIO_VENDOR_ID, RSI_SDIO_PID_9113) }, { SDIO_DEVICE(SDIO_VENDOR_ID_RSI, SDIO_DEVICE_ID_RSI_9113) },
{ SDIO_DEVICE(RSI_SDIO_VENDOR_ID, RSI_SDIO_PID_9116) }, { SDIO_DEVICE(SDIO_VENDOR_ID_RSI, SDIO_DEVICE_ID_RSI_9116) },
{ /* Blank */}, { /* Blank */},
}; };
......
...@@ -28,10 +28,6 @@ ...@@ -28,10 +28,6 @@
#include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_ids.h>
#include "rsi_main.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 { enum sdio_interrupt_type {
BUFFER_FULL = 0x0, BUFFER_FULL = 0x0,
BUFFER_AVAILABLE = 0x2, BUFFER_AVAILABLE = 0x2,
......
...@@ -287,6 +287,7 @@ struct mmc_host { ...@@ -287,6 +287,7 @@ struct mmc_host {
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
struct notifier_block pm_notify; struct notifier_block pm_notify;
#endif #endif
struct wakeup_source *ws; /* Enable consume of uevents */
u32 max_current_330; u32 max_current_330;
u32 max_current_300; u32 max_current_300;
u32 max_current_180; u32 max_current_180;
...@@ -351,6 +352,7 @@ struct mmc_host { ...@@ -351,6 +352,7 @@ struct mmc_host {
#define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */ #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 (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_8V_SDR (1 << 5) /* can support */
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
......
...@@ -118,6 +118,10 @@ ...@@ -118,6 +118,10 @@
#define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100 #define SDIO_DEVICE_ID_SIANO_NOVA_A0 0x1100
#define SDIO_DEVICE_ID_SIANO_STELLAR 0x5347 #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_VENDOR_ID_TI_WL1251 0x104c
#define SDIO_DEVICE_ID_TI_WL1251 0x9066 #define SDIO_DEVICE_ID_TI_WL1251 0x9066
......
...@@ -116,3 +116,6 @@ struct omap_mmc_platform_data { ...@@ -116,3 +116,6 @@ struct omap_mmc_platform_data {
} slots[OMAP_MMC_MAX_SLOTS]; } slots[OMAP_MMC_MAX_SLOTS];
}; };
extern void omap_mmc_notify_cover_event(struct device *dev, int slot,
int is_closed);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment