mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-06 13:16:22 +00:00
MMC core:
- A few minor improvements and cleanups MMC host: - Remove some redundant calls to local_irq_{save,restore}() - Replace kmap_atomic() with kmap_local_page() - Take return values from mmc_add_host() into account - dw_mmc-pltfm: Add support to configure clk-phase for socfpga - hsq: Minimize latency by using a fifo to dispatch requests - litex_mmc: Fixup corner case for polling mode - mtk-sd: Add inline crypto engine clock control - mtk-sd: Add support for the mediatek MT7986 variant - renesas_sdhi: Improve reset from HS400 mode - renesas_sdhi: Take DMA end interrupts into account - sdhci: Avoid unnecessary update of clock - sdhci: Fix an SD tuning issue - sdhci-brcmst: Add Kamal Dasu as maintainer for the Broadcom driver - sdhci-esdhc-imx: Improve tuning logic - sdhci-esdhc-imx: Improve support for the imxrt1050 variant - sdhci_f_sdh30: Add support for non-removable media - sdhci_f_sdh30: Add support for the Socionext F_SDH30_E51 variant - sdhci_f_sdh30: Add reset control support - sdhci-msm: Add support for the Qcom SM8550/SM8350/SM6375 variants - sdhci-msm: Add support for the Qcom MSM8976 variant - sdhci-of-arasan: Add support for dynamic configuration - sdhci-of-esdhc: Limit the clock frequency to confirm to spec - sdhci-pci: Enable asynchronous probe - sdhci-sprd: Improve card detection - sdhci-tegra: Improve reset support - sdhci-tegra: Add support to program MC stream ID - sunplus-mmc: Add new mmc driver for the Sunplus SP7021 controller - vub300: Fix warning splat for SDIO irq MEMSTICK core: - memstick: A few minor improvements and cleanups CLK/IOMMU: - clk: socfpga: Drop redundant support for clk-phase for the SD/MMC clk - iommu: Add tegra specific helper to get stream_id -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmOYUeUXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCnUmA//cdC4gF86ROp+d2lKZVHn9FVK jgF0NJ9DZiDOZm7qta7rqmAGo/Xq9sacHq65qGjXMeei/MNrwu7xW/U3Ihk0pK9z Gnphck3JgbkLJ6ijxsuBqNavsYjXJVqys3f2qThXYh+xXyLAfIvOtPj9984EfdvR AtZuTwpvebNxB6Qu6SFIYZ4Yt4ZaTN/AuCRyjS9HHNLugjbgditZQcw6wjqlTRb7 fhSNwK3srWGzdthtiiXBoFSjjpd7AESGPjqaGDJNgIDYxFXOUX2vx2eb15s1beVN i7pN8D83StNjF+PF551trUyNCaW4Ukbl7hHTqC9sFvjgtRFVB97oSoxm7F03fsX3 bM6USXtG1xOGkPG9Dqneuhee157UCgNIWs46H/CuZYmGgBN6I7l0Jt3+Lru5IwwQ NstKcLS6xaWyYOEAoAR5yFDJXBagxEXNArtHkzoLabvcsk0XPdGAMd87RUuyGgXt Vpd4VjH1VSDcaG7DF3+XR3uTy5mUAOrehBrVr1eKH7gYRpr4TLlYgE/a3AkSs/m+ 3ftM3o6hraHKqwY32vDG9vSsuLrGdh286rEypmc1gmejiNTz+SFSIex1YoefWtx2 O0u+7plcauuUX+7EQ79RzZkB/FS40uL3wxAii7Ta+on4P7Cwuh6jo1Hakvy5JjtW 5733RKV5nkKUkKMOwsU= =nstz -----END PGP SIGNATURE----- Merge tag 'mmc-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC and MEMSTICK updates from Ulf Hansson: "MMC core: - A few minor improvements and cleanups MMC host: - Remove some redundant calls to local_irq_{save,restore}() - Replace kmap_atomic() with kmap_local_page() - Take return values from mmc_add_host() into account - dw_mmc-pltfm: Add support to configure clk-phase for socfpga - hsq: Minimize latency by using a fifo to dispatch requests - litex_mmc: Fixup corner case for polling mode - mtk-sd: Add inline crypto engine clock control - mtk-sd: Add support for the mediatek MT7986 variant - renesas_sdhi: Improve reset from HS400 mode - renesas_sdhi: Take DMA end interrupts into account - sdhci: Avoid unnecessary update of clock - sdhci: Fix an SD tuning issue - sdhci-brcmst: Add Kamal Dasu as maintainer for the Broadcom driver - sdhci-esdhc-imx: Improve tuning logic - sdhci-esdhc-imx: Improve support for the imxrt1050 variant - sdhci_f_sdh30: Add support for non-removable media - sdhci_f_sdh30: Add support for the Socionext F_SDH30_E51 variant - sdhci_f_sdh30: Add reset control support - sdhci-msm: Add support for the Qcom SM8550/SM8350/SM6375 variants - sdhci-msm: Add support for the Qcom MSM8976 variant - sdhci-of-arasan: Add support for dynamic configuration - sdhci-of-esdhc: Limit the clock frequency to confirm to spec - sdhci-pci: Enable asynchronous probe - sdhci-sprd: Improve card detection - sdhci-tegra: Improve reset support - sdhci-tegra: Add support to program MC stream ID - sunplus-mmc: Add new mmc driver for the Sunplus SP7021 controller - vub300: Fix warning splat for SDIO irq MEMSTICK core: - memstick: A few minor improvements and cleanups CLK/IOMMU: - clk: socfpga: Drop redundant support for clk-phase for the SD/MMC clk - iommu: Add tegra specific helper to get stream_id" * tag 'mmc-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (108 commits) mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K mmc: sdhci-of-esdhc: Modify mismatched function name memstick/mspro_block: Convert to use sysfs_emit()/sysfs_emit_at() APIs mmc: sdhci-tegra: Issue CMD and DAT resets together mmc: sdhci-tegra: Add support to program MC stream ID mmc: sdhci-tegra: Separate Tegra194 and Tegra234 SoC data mmc: sdhci-tegra: Sort includes alphabetically iommu/tegra: Add tegra_dev_iommu_get_stream_id() helper iommu: Add note about struct iommu_fwspec usage mmc: sdhci-brcmstb: Resolve "unused" warnings with CONFIG_OF=n dt-bindings: mmc: sdhci-msm: allow dma-coherent dt-bindings: mmc: sdhci-msm: drop properties mentioned in common MMC dt-bindings: mmc: sdhci-msm: cleanup style dt-bindings: mmc: sdhci-am654: cleanup style dt-bindings: mmc: sdhci: document sdhci-caps and sdhci-caps-mask mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING MAINTAINERS: Update maintainer for SDHCI Broadcom BRCMSTB driver mmc: sdhci-of-esdhc: limit the SDHC clock frequency mmc: sdhci: Remove unneeded semicolon mmc: core: Normalize the error handling branch in sd_read_ext_regs() ...
This commit is contained in:
commit
71946a25f3
@ -95,7 +95,9 @@ properties:
|
||||
PIO (polled I/O) interrupt and occurs when the FIFO needs to be
|
||||
emptied as part of a bulk read from the card. Some variants have these
|
||||
two interrupts wired into the same line (logic OR) and in that case
|
||||
only one interrupt may be provided.
|
||||
only one interrupt may be provided. The interrupt-names property is
|
||||
not used due to inconsistency of existing DTs regarding its content.
|
||||
deprecated: false
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
|
@ -50,11 +50,11 @@ properties:
|
||||
- const: fsl,imx8mm-usdhc
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx8dxl-usdhc
|
||||
- fsl,imx8qm-usdhc
|
||||
- const: fsl,imx8qxp-usdhc
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx8dxl-usdhc
|
||||
- fsl,imx8mm-usdhc
|
||||
- fsl,imx8mn-usdhc
|
||||
- fsl,imx8mp-usdhc
|
||||
@ -71,6 +71,7 @@ properties:
|
||||
deprecated: true
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx8dxl-usdhc
|
||||
- fsl,imx8qm-usdhc
|
||||
- const: fsl,imx8qxp-usdhc
|
||||
- const: fsl,imx7d-usdhc
|
||||
|
@ -0,0 +1,57 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/fujitsu,sdhci-fujitsu.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Fujitsu/Socionext SDHCI controller (F_SDH30)
|
||||
|
||||
maintainers:
|
||||
- Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fujitsu,mb86s70-sdhci-3.0
|
||||
- socionext,f-sdh30-e51-mmc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: iface
|
||||
- const: core
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
fujitsu,cmd-dat-delay-select:
|
||||
type: boolean
|
||||
description: |
|
||||
Indicating that this host requires the CMD_DAT_DELAY control to be enabled
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
examples:
|
||||
- |
|
||||
sdhci1: mmc@36600000 {
|
||||
compatible = "fujitsu,mb86s70-sdhci-3.0";
|
||||
reg = <0x36600000 0x1000>;
|
||||
bus-width = <4>;
|
||||
vqmmc-supply = <&vccq_sdhci1>;
|
||||
clocks = <&clock 2 2 0>, <&clock 2 3 0>;
|
||||
clock-names = "iface", "core";
|
||||
};
|
@ -293,7 +293,6 @@ properties:
|
||||
description:
|
||||
SDIO only. Preserves card power during a suspend/resume cycle.
|
||||
|
||||
# Deprecated: enable-sdio-wakeup
|
||||
wakeup-source:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
|
@ -10,9 +10,6 @@ maintainers:
|
||||
- Chaotian Jing <chaotian.jing@mediatek.com>
|
||||
- Wenbin Mei <wenbin.mei@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
@ -23,6 +20,7 @@ properties:
|
||||
- mediatek,mt6795-mmc
|
||||
- mediatek,mt7620-mmc
|
||||
- mediatek,mt7622-mmc
|
||||
- mediatek,mt7986-mmc
|
||||
- mediatek,mt8135-mmc
|
||||
- mediatek,mt8173-mmc
|
||||
- mediatek,mt8183-mmc
|
||||
@ -48,27 +46,11 @@ properties:
|
||||
description:
|
||||
Should contain phandle for the clock feeding the MMC controller.
|
||||
minItems: 2
|
||||
items:
|
||||
- description: source clock (required).
|
||||
- description: HCLK which used for host (required).
|
||||
- description: independent source clock gate (required for MT2712).
|
||||
- description: bus clock used for internal register access (required for MT2712 MSDC0/3).
|
||||
- description: msdc subsys clock gate (required for MT8192).
|
||||
- description: peripheral bus clock gate (required for MT8192).
|
||||
- description: AXI bus clock gate (required for MT8192).
|
||||
- description: AHB bus clock gate (required for MT8192).
|
||||
maxItems: 7
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: source_cg
|
||||
- const: bus_clk
|
||||
- const: sys_cg
|
||||
- const: pclk_cg
|
||||
- const: axi_cg
|
||||
- const: ahb_cg
|
||||
maxItems: 7
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
@ -190,15 +172,144 @@ required:
|
||||
- vmmc-supply
|
||||
- vqmmc-supply
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mediatek,mt8183-mmc
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt2701-mmc
|
||||
- mediatek,mt6779-mmc
|
||||
- mediatek,mt6795-mmc
|
||||
- mediatek,mt7620-mmc
|
||||
- mediatek,mt7622-mmc
|
||||
- mediatek,mt7623-mmc
|
||||
- mediatek,mt8135-mmc
|
||||
- mediatek,mt8173-mmc
|
||||
- mediatek,mt8183-mmc
|
||||
- mediatek,mt8186-mmc
|
||||
- mediatek,mt8188-mmc
|
||||
- mediatek,mt8195-mmc
|
||||
- mediatek,mt8516-mmc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
items:
|
||||
- description: source clock
|
||||
- description: HCLK which used for host
|
||||
- description: independent source clock gate
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: source_cg
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mediatek,mt2712-mmc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
items:
|
||||
- description: source clock
|
||||
- description: HCLK which used for host
|
||||
- description: independent source clock gate
|
||||
- description: bus clock used for internal register access (required for MSDC0/3).
|
||||
clock-names:
|
||||
minItems: 3
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: source_cg
|
||||
- const: bus_clk
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mediatek,mt8183-mmc
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt7986-mmc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
items:
|
||||
- description: source clock
|
||||
- description: HCLK which used for host
|
||||
- description: independent source clock gate
|
||||
- description: bus clock used for internal register access (required for MSDC0/3).
|
||||
- description: msdc subsys clock gate
|
||||
clock-names:
|
||||
minItems: 3
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: source_cg
|
||||
- const: bus_clk
|
||||
- const: sys_cg
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8186-mmc
|
||||
- mediatek,mt8188-mmc
|
||||
- mediatek,mt8195-mmc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: source clock
|
||||
- description: HCLK which used for host
|
||||
- description: independent source clock gate
|
||||
- description: crypto clock used for data encrypt/decrypt (optional)
|
||||
clock-names:
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: source_cg
|
||||
- const: crypto
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: mediatek,mt8192-mmc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: source clock
|
||||
- description: HCLK which used for host
|
||||
- description: independent source clock gate
|
||||
- description: msdc subsys clock gate
|
||||
- description: peripheral bus clock gate
|
||||
- description: AXI bus clock gate
|
||||
- description: AHB bus clock gate
|
||||
clock-names:
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: source_cg
|
||||
- const: sys_cg
|
||||
- const: pclk_cg
|
||||
- const: axi_cg
|
||||
- const: ahb_cg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
@ -64,6 +64,7 @@ properties:
|
||||
- enum:
|
||||
- renesas,sdhi-r8a779a0 # R-Car V3U
|
||||
- renesas,sdhi-r8a779f0 # R-Car S4-8
|
||||
- renesas,sdhi-r8a779g0 # R-Car V4H
|
||||
- const: renesas,rcar-gen4-sdhi # R-Car Gen4
|
||||
|
||||
reg:
|
||||
|
@ -71,6 +71,9 @@ properties:
|
||||
to control the clock phases, "ciu-sample" is required for tuning
|
||||
high speed modes.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
rockchip,default-sample-phase:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/mmc/sdhci-am654.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/mmc/sdhci-am654.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TI AM654 MMC Controller
|
||||
|
||||
@ -11,17 +11,18 @@ maintainers:
|
||||
- Ulf Hansson <ulf.hansson@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
- $ref: sdhci-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: ti,am654-sdhci-5.1
|
||||
- const: ti,j721e-sdhci-8bit
|
||||
- const: ti,j721e-sdhci-4bit
|
||||
- const: ti,am64-sdhci-8bit
|
||||
- const: ti,am64-sdhci-4bit
|
||||
- const: ti,am62-sdhci
|
||||
- enum:
|
||||
- ti,am62-sdhci
|
||||
- ti,am64-sdhci-4bit
|
||||
- ti,am64-sdhci-8bit
|
||||
- ti,am654-sdhci-5.1
|
||||
- ti,j721e-sdhci-4bit
|
||||
- ti,j721e-sdhci-8bit
|
||||
- items:
|
||||
- const: ti,j7200-sdhci-8bit
|
||||
- const: ti,j721e-sdhci-8bit
|
||||
@ -49,8 +50,6 @@ properties:
|
||||
- const: clk_ahb
|
||||
- const: clk_xin
|
||||
|
||||
sdhci-caps-mask: true
|
||||
|
||||
dma-coherent:
|
||||
type: boolean
|
||||
|
||||
@ -61,67 +60,67 @@ properties:
|
||||
|
||||
ti,otap-del-sel-legacy:
|
||||
description: Output tap delay for SD/MMC legacy timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-mmc-hs:
|
||||
description: Output tap delay for MMC high speed timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-sd-hs:
|
||||
description: Output tap delay for SD high speed timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-sdr12:
|
||||
description: Output tap delay for SD UHS SDR12 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-sdr25:
|
||||
description: Output tap delay for SD UHS SDR25 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-sdr50:
|
||||
description: Output tap delay for SD UHS SDR50 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-sdr104:
|
||||
description: Output tap delay for SD UHS SDR104 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-ddr50:
|
||||
description: Output tap delay for SD UHS DDR50 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-ddr52:
|
||||
description: Output tap delay for eMMC DDR52 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-hs200:
|
||||
description: Output tap delay for eMMC HS200 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,otap-del-sel-hs400:
|
||||
description: Output tap delay for eMMC HS400 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
@ -131,49 +130,55 @@ properties:
|
||||
|
||||
ti,itap-del-sel-legacy:
|
||||
description: Input tap delay for SD/MMC legacy timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0x1f
|
||||
|
||||
ti,itap-del-sel-mmc-hs:
|
||||
description: Input tap delay for MMC high speed timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0x1f
|
||||
|
||||
ti,itap-del-sel-sd-hs:
|
||||
description: Input tap delay for SD high speed timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0x1f
|
||||
|
||||
ti,itap-del-sel-sdr12:
|
||||
description: Input tap delay for SD UHS SDR12 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0x1f
|
||||
|
||||
ti,itap-del-sel-sdr25:
|
||||
description: Input tap delay for SD UHS SDR25 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0x1f
|
||||
|
||||
ti,itap-del-sel-ddr50:
|
||||
description: Input tap delay for MMC DDR50 timing
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0x1f
|
||||
|
||||
ti,itap-del-sel-ddr52:
|
||||
description: Input tap delay for MMC DDR52 timing
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0x1f
|
||||
|
||||
ti,trm-icp:
|
||||
description: DLL trim select
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 0xf
|
||||
|
||||
ti,driver-strength-ohm:
|
||||
description: DLL drive strength in ohms
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 33
|
||||
- 40
|
||||
@ -183,11 +188,11 @@ properties:
|
||||
|
||||
ti,strobe-sel:
|
||||
description: strobe select delay for HS400 speed mode.
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
ti,clkbuf-sel:
|
||||
description: Clock Delay Buffer Select
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
ti,fails-without-test-cd:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
32
Documentation/devicetree/bindings/mmc/sdhci-common.yaml
Normal file
32
Documentation/devicetree/bindings/mmc/sdhci-common.yaml
Normal file
@ -0,0 +1,32 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/sdhci-common.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SDHCI Controller Common Properties
|
||||
|
||||
maintainers:
|
||||
- Adrian Hunter <adrian.hunter@intel.com>
|
||||
|
||||
description:
|
||||
Common properties present on Secure Digital Host Controller Interface (SDHCI)
|
||||
devices.
|
||||
|
||||
properties:
|
||||
sdhci-caps:
|
||||
$ref: /schemas/types.yaml#/definitions/uint64
|
||||
description:
|
||||
Additionally present SDHCI capabilities - values for SDHCI_CAPABILITIES
|
||||
and SDHCI_CAPABILITIES_1 registers.
|
||||
|
||||
sdhci-caps-mask:
|
||||
$ref: /schemas/types.yaml#/definitions/uint64
|
||||
description:
|
||||
Masked SDHCI capabilities to remove from SDHCI_CAPABILITIES and
|
||||
SDHCI_CAPABILITIES_1 registers.
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
|
||||
additionalProperties: true
|
@ -1,32 +0,0 @@
|
||||
* Fujitsu SDHCI controller
|
||||
|
||||
This file documents differences between the core properties in mmc.txt
|
||||
and the properties used by the sdhci_f_sdh30 driver.
|
||||
|
||||
Required properties:
|
||||
- compatible: "fujitsu,mb86s70-sdhci-3.0"
|
||||
- clocks: Must contain an entry for each entry in clock-names. It is a
|
||||
list of phandles and clock-specifier pairs.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names: Should contain the following two entries:
|
||||
"iface" - clock used for sdhci interface
|
||||
"core" - core clock for sdhci controller
|
||||
|
||||
Optional properties:
|
||||
- vqmmc-supply: phandle to the regulator device tree node, mentioned
|
||||
as the VCCQ/VDD_IO supply in the eMMC/SD specs.
|
||||
- fujitsu,cmd-dat-delay-select: boolean property indicating that this host
|
||||
requires the CMD_DAT_DELAY control to be enabled.
|
||||
|
||||
Example:
|
||||
|
||||
sdhci1: mmc@36600000 {
|
||||
compatible = "fujitsu,mb86s70-sdhci-3.0";
|
||||
reg = <0 0x36600000 0x1000>;
|
||||
interrupts = <0 172 0x4>,
|
||||
<0 173 0x4>;
|
||||
bus-width = <4>;
|
||||
vqmmc-supply = <&vccq_sdhci1>;
|
||||
clocks = <&clock 2 2 0>, <&clock 2 3 0>;
|
||||
clock-names = "iface", "core";
|
||||
};
|
@ -1,9 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/mmc/sdhci-msm.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/mmc/sdhci-msm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm SDHCI controller (sdhci-msm)
|
||||
|
||||
@ -26,6 +25,7 @@ properties:
|
||||
- qcom,msm8226-sdhci
|
||||
- qcom,msm8953-sdhci
|
||||
- qcom,msm8974-sdhci
|
||||
- qcom,msm8976-sdhci
|
||||
- qcom,msm8916-sdhci
|
||||
- qcom,msm8992-sdhci
|
||||
- qcom,msm8994-sdhci
|
||||
@ -45,9 +45,12 @@ properties:
|
||||
- qcom,sm6115-sdhci
|
||||
- qcom,sm6125-sdhci
|
||||
- qcom,sm6350-sdhci
|
||||
- qcom,sm6375-sdhci
|
||||
- qcom,sm8150-sdhci
|
||||
- qcom,sm8250-sdhci
|
||||
- qcom,sm8350-sdhci
|
||||
- qcom,sm8450-sdhci
|
||||
- qcom,sm8550-sdhci
|
||||
- const: qcom,sdhci-msm-v5 # for sdcc version 5.0
|
||||
|
||||
reg:
|
||||
@ -80,6 +83,8 @@ properties:
|
||||
- const: cal
|
||||
- const: sleep
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
@ -133,16 +138,6 @@ properties:
|
||||
description: A phandle to sdhci power domain node
|
||||
maxItems: 1
|
||||
|
||||
mmc-ddr-1_8v: true
|
||||
|
||||
mmc-hs200-1_8v: true
|
||||
|
||||
mmc-hs400-1_8v: true
|
||||
|
||||
bus-width: true
|
||||
|
||||
max-frequency: true
|
||||
|
||||
operating-points-v2: true
|
||||
|
||||
patternProperties:
|
||||
@ -165,7 +160,7 @@ required:
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
- $ref: sdhci-common.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
|
@ -45,6 +45,17 @@ properties:
|
||||
- const: block
|
||||
- const: timer
|
||||
|
||||
resets:
|
||||
maxItems: 5
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: bus
|
||||
- const: axi
|
||||
- const: block
|
||||
- const: timer
|
||||
|
||||
rockchip,txclk-tapnum:
|
||||
description: Specify the number of delay for tx sampling.
|
||||
$ref: /schemas/types.yaml#/definitions/uint8
|
||||
|
61
Documentation/devicetree/bindings/mmc/sunplus,mmc.yaml
Normal file
61
Documentation/devicetree/bindings/mmc/sunplus,mmc.yaml
Normal file
@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) Sunplus Ltd. Co. 2021
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/sunplus,mmc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sunplus MMC Controller
|
||||
|
||||
maintainers:
|
||||
- Tony Huang <tonyhuang.sunplus@gmail.com>
|
||||
- Li-hao Kuo <lhjeff911@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "mmc-controller.yaml"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- sunplus,sp7021-mmc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- resets
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
mmc0: mmc@9c003b00 {
|
||||
compatible = "sunplus,sp7021-mmc";
|
||||
reg = <0x9c003b00 0x180>;
|
||||
interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clkc 0x4e>;
|
||||
resets = <&rstc 0x3e>;
|
||||
bus-width = <8>;
|
||||
max-frequency = <52000000>;
|
||||
non-removable;
|
||||
disable-wp;
|
||||
cap-mmc-highspeed;
|
||||
mmc-ddr-3_3v;
|
||||
no-sdio;
|
||||
no-sd;
|
||||
};
|
@ -6,9 +6,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Synopsys Designware Mobile Storage Host Controller Binding
|
||||
|
||||
allOf:
|
||||
- $ref: "synopsys-dw-mshc-common.yaml#"
|
||||
|
||||
maintainers:
|
||||
- Ulf Hansson <ulf.hansson@linaro.org>
|
||||
|
||||
@ -38,6 +35,35 @@ properties:
|
||||
- const: biu
|
||||
- const: ciu
|
||||
|
||||
altr,sysmgr-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- items:
|
||||
- description: phandle to the sysmgr node
|
||||
- description: register offset that controls the SDMMC clock phase
|
||||
- description: register shift for the smplsel(drive in) setting
|
||||
description:
|
||||
This property is optional. Contains the phandle to System Manager block
|
||||
that contains the SDMMC clock-phase control register. The first value is
|
||||
the pointer to the sysmgr, the 2nd value is the register offset for the
|
||||
SDMMC clock phase register, and the 3rd value is the bit shift for the
|
||||
smplsel(drive in) setting.
|
||||
|
||||
allOf:
|
||||
- $ref: synopsys-dw-mshc-common.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: altr,socfpga-dw-mshc
|
||||
then:
|
||||
properties:
|
||||
altr,sysmgr-syscon: true
|
||||
else:
|
||||
properties:
|
||||
altr,sysmgr-syscon: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -17,15 +17,14 @@ interrupt.
|
||||
List of legacy properties and respective binding document
|
||||
---------------------------------------------------------
|
||||
|
||||
1. "enable-sdio-wakeup" Documentation/devicetree/bindings/mmc/mmc.txt
|
||||
2. "gpio-key,wakeup" Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt
|
||||
3. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt
|
||||
4. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
|
||||
1. "gpio-key,wakeup" Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt
|
||||
2. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt
|
||||
3. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
|
||||
Documentation/devicetree/bindings/mfd/tc3589x.txt
|
||||
Documentation/devicetree/bindings/input/touchscreen/ads7846.txt
|
||||
5. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
|
||||
6. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt
|
||||
7. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
|
||||
4. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
|
||||
5. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt
|
||||
6. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
@ -18612,6 +18612,7 @@ K: \bsecure_computing
|
||||
K: \bTIF_SECCOMP\b
|
||||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) Broadcom BRCMSTB DRIVER
|
||||
M: Kamal Dasu <kdasu.kdev@gmail.com>
|
||||
M: Al Cooper <alcooperx@gmail.com>
|
||||
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
@ -18622,6 +18623,7 @@ SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
|
||||
M: Adrian Hunter <adrian.hunter@intel.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/mmc/sdhci-common.yaml
|
||||
F: drivers/mmc/host/sdhci*
|
||||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
|
||||
@ -19884,6 +19886,13 @@ W: https://sunplus.atlassian.net/wiki/spaces/doc/overview
|
||||
F: Documentation/devicetree/bindings/net/sunplus,sp7021-emac.yaml
|
||||
F: drivers/net/ethernet/sunplus/
|
||||
|
||||
SUNPLUS MMC DRIVER
|
||||
M: Tony Huang <tonyhuang.sunplus@gmail.com>
|
||||
M: Li-hao Kuo <lhjeff911@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/mmc/sunplus,mmc.yaml
|
||||
F: drivers/mmc/host/sunplus-mmc.c
|
||||
|
||||
SUNPLUS OCOTP DRIVER
|
||||
M: Vincent Shih <vincent.sunplus@gmail.com>
|
||||
S: Maintained
|
||||
|
@ -35,59 +35,7 @@ static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw *hwclk,
|
||||
return parent_rate / div;
|
||||
}
|
||||
|
||||
static int socfpga_clk_prepare(struct clk_hw *hwclk)
|
||||
{
|
||||
struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
|
||||
int i;
|
||||
u32 hs_timing;
|
||||
u32 clk_phase[2];
|
||||
|
||||
if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
|
||||
for (i = 0; i < ARRAY_SIZE(clk_phase); i++) {
|
||||
switch (socfpgaclk->clk_phase[i]) {
|
||||
case 0:
|
||||
clk_phase[i] = 0;
|
||||
break;
|
||||
case 45:
|
||||
clk_phase[i] = 1;
|
||||
break;
|
||||
case 90:
|
||||
clk_phase[i] = 2;
|
||||
break;
|
||||
case 135:
|
||||
clk_phase[i] = 3;
|
||||
break;
|
||||
case 180:
|
||||
clk_phase[i] = 4;
|
||||
break;
|
||||
case 225:
|
||||
clk_phase[i] = 5;
|
||||
break;
|
||||
case 270:
|
||||
clk_phase[i] = 6;
|
||||
break;
|
||||
case 315:
|
||||
clk_phase[i] = 7;
|
||||
break;
|
||||
default:
|
||||
clk_phase[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hs_timing = SYSMGR_SDMMC_CTRL_SET_AS10(clk_phase[0], clk_phase[1]);
|
||||
if (!IS_ERR(socfpgaclk->sys_mgr_base_addr))
|
||||
regmap_write(socfpgaclk->sys_mgr_base_addr,
|
||||
SYSMGR_SDMMCGRP_CTRL_OFFSET, hs_timing);
|
||||
else
|
||||
pr_err("%s: cannot set clk_phase because sys_mgr_base_addr is not available!\n",
|
||||
__func__);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops gateclk_ops = {
|
||||
.prepare = socfpga_clk_prepare,
|
||||
.recalc_rate = socfpga_gate_clk_recalc_rate,
|
||||
};
|
||||
|
||||
@ -96,7 +44,6 @@ static void __init __socfpga_gate_init(struct device_node *node,
|
||||
{
|
||||
u32 clk_gate[2];
|
||||
u32 div_reg[3];
|
||||
u32 clk_phase[2];
|
||||
u32 fixed_div;
|
||||
struct clk_hw *hw_clk;
|
||||
struct socfpga_gate_clk *socfpga_clk;
|
||||
@ -136,21 +83,6 @@ static void __init __socfpga_gate_init(struct device_node *node,
|
||||
socfpga_clk->div_reg = NULL;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
|
||||
if (!rc) {
|
||||
socfpga_clk->clk_phase[0] = clk_phase[0];
|
||||
socfpga_clk->clk_phase[1] = clk_phase[1];
|
||||
|
||||
socfpga_clk->sys_mgr_base_addr =
|
||||
syscon_regmap_lookup_by_compatible("altr,sys-mgr");
|
||||
if (IS_ERR(socfpga_clk->sys_mgr_base_addr)) {
|
||||
pr_err("%s: failed to find altr,sys-mgr regmap!\n",
|
||||
__func__);
|
||||
kfree(socfpga_clk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
of_property_read_string(node, "clock-output-names", &clk_name);
|
||||
|
||||
init.name = clk_name;
|
||||
|
@ -108,61 +108,7 @@ static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk,
|
||||
return parent_rate / div;
|
||||
}
|
||||
|
||||
static int socfpga_clk_prepare(struct clk_hw *hwclk)
|
||||
{
|
||||
struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
|
||||
struct regmap *sys_mgr_base_addr;
|
||||
int i;
|
||||
u32 hs_timing;
|
||||
u32 clk_phase[2];
|
||||
|
||||
if (socfpgaclk->clk_phase[0] || socfpgaclk->clk_phase[1]) {
|
||||
sys_mgr_base_addr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
|
||||
if (IS_ERR(sys_mgr_base_addr)) {
|
||||
pr_err("%s: failed to find altr,sys-mgr regmap!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
switch (socfpgaclk->clk_phase[i]) {
|
||||
case 0:
|
||||
clk_phase[i] = 0;
|
||||
break;
|
||||
case 45:
|
||||
clk_phase[i] = 1;
|
||||
break;
|
||||
case 90:
|
||||
clk_phase[i] = 2;
|
||||
break;
|
||||
case 135:
|
||||
clk_phase[i] = 3;
|
||||
break;
|
||||
case 180:
|
||||
clk_phase[i] = 4;
|
||||
break;
|
||||
case 225:
|
||||
clk_phase[i] = 5;
|
||||
break;
|
||||
case 270:
|
||||
clk_phase[i] = 6;
|
||||
break;
|
||||
case 315:
|
||||
clk_phase[i] = 7;
|
||||
break;
|
||||
default:
|
||||
clk_phase[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1]);
|
||||
regmap_write(sys_mgr_base_addr, SYSMGR_SDMMCGRP_CTRL_OFFSET,
|
||||
hs_timing);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops gateclk_ops = {
|
||||
.prepare = socfpga_clk_prepare,
|
||||
.recalc_rate = socfpga_clk_recalc_rate,
|
||||
.get_parent = socfpga_clk_get_parent,
|
||||
.set_parent = socfpga_clk_set_parent,
|
||||
@ -172,7 +118,6 @@ void __init socfpga_gate_init(struct device_node *node)
|
||||
{
|
||||
u32 clk_gate[2];
|
||||
u32 div_reg[3];
|
||||
u32 clk_phase[2];
|
||||
u32 fixed_div;
|
||||
struct clk_hw *hw_clk;
|
||||
struct socfpga_gate_clk *socfpga_clk;
|
||||
@ -218,12 +163,6 @@ void __init socfpga_gate_init(struct device_node *node)
|
||||
socfpga_clk->div_reg = NULL;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_array(node, "clk-phase", clk_phase, 2);
|
||||
if (!rc) {
|
||||
socfpga_clk->clk_phase[0] = clk_phase[0];
|
||||
socfpga_clk->clk_phase[1] = clk_phase[1];
|
||||
}
|
||||
|
||||
of_property_read_string(node, "clock-output-names", &clk_name);
|
||||
|
||||
init.name = clk_name;
|
||||
|
@ -50,7 +50,6 @@ struct socfpga_gate_clk {
|
||||
u32 width; /* only valid if div_reg != 0 */
|
||||
u32 shift; /* only valid if div_reg != 0 */
|
||||
u32 bypass_shift; /* only valid if bypass_reg != 0 */
|
||||
u32 clk_phase[2];
|
||||
};
|
||||
|
||||
struct socfpga_periph_clk {
|
||||
|
@ -2116,6 +2116,11 @@ static int msb_init_disk(struct memstick_dev *card)
|
||||
dbg("Set total disk size to %lu sectors", capacity);
|
||||
|
||||
msb->io_queue = alloc_ordered_workqueue("ms_block", WQ_MEM_RECLAIM);
|
||||
if (!msb->io_queue) {
|
||||
rc = -ENOMEM;
|
||||
goto out_cleanup_disk;
|
||||
}
|
||||
|
||||
INIT_WORK(&msb->io_work, msb_io_work);
|
||||
sg_init_table(msb->prealloc_sg, MS_BLOCK_MAX_SEGS+1);
|
||||
|
||||
@ -2125,10 +2130,12 @@ static int msb_init_disk(struct memstick_dev *card)
|
||||
msb_start(card);
|
||||
rc = device_add_disk(&card->dev, msb->disk, NULL);
|
||||
if (rc)
|
||||
goto out_cleanup_disk;
|
||||
goto out_destroy_workqueue;
|
||||
dbg("Disk added");
|
||||
return 0;
|
||||
|
||||
out_destroy_workqueue:
|
||||
destroy_workqueue(msb->io_queue);
|
||||
out_cleanup_disk:
|
||||
put_disk(msb->disk);
|
||||
out_free_tag_set:
|
||||
|
@ -260,8 +260,8 @@ static ssize_t mspro_block_attr_show_default(struct device *dev,
|
||||
buffer[rc++] = '\n';
|
||||
}
|
||||
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "%02x ",
|
||||
((unsigned char *)s_attr->data)[cnt]);
|
||||
rc += sysfs_emit_at(buffer, rc, "%02x ",
|
||||
((unsigned char *)s_attr->data)[cnt]);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -290,61 +290,43 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev,
|
||||
date_tz_f *= 15;
|
||||
}
|
||||
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "class: %x\n",
|
||||
x_sys->class);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block size: %x\n",
|
||||
be16_to_cpu(x_sys->block_size));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "block count: %x\n",
|
||||
be16_to_cpu(x_sys->block_count));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "user block count: %x\n",
|
||||
be16_to_cpu(x_sys->user_block_count));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "page size: %x\n",
|
||||
be16_to_cpu(x_sys->page_size));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: "
|
||||
"GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n",
|
||||
date_tz, date_tz_f,
|
||||
be16_to_cpup((__be16 *)&x_sys->assembly_date[1]),
|
||||
x_sys->assembly_date[3], x_sys->assembly_date[4],
|
||||
x_sys->assembly_date[5], x_sys->assembly_date[6],
|
||||
x_sys->assembly_date[7]);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "serial number: %x\n",
|
||||
be32_to_cpu(x_sys->serial_number));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
|
||||
"assembly maker code: %x\n",
|
||||
x_sys->assembly_maker_code);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly model code: "
|
||||
"%02x%02x%02x\n", x_sys->assembly_model_code[0],
|
||||
x_sys->assembly_model_code[1],
|
||||
x_sys->assembly_model_code[2]);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory maker code: %x\n",
|
||||
be16_to_cpu(x_sys->memory_maker_code));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "memory model code: %x\n",
|
||||
be16_to_cpu(x_sys->memory_model_code));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vcc: %x\n",
|
||||
x_sys->vcc);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "vpp: %x\n",
|
||||
x_sys->vpp);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller number: %x\n",
|
||||
be16_to_cpu(x_sys->controller_number));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
|
||||
"controller function: %x\n",
|
||||
be16_to_cpu(x_sys->controller_function));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",
|
||||
be16_to_cpu(x_sys->start_sector));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "unit size: %x\n",
|
||||
be16_to_cpu(x_sys->unit_size));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sub class: %x\n",
|
||||
x_sys->ms_sub_class);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "interface type: %x\n",
|
||||
x_sys->interface_type);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "controller code: %x\n",
|
||||
be16_to_cpu(x_sys->controller_code));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "format type: %x\n",
|
||||
x_sys->format_type);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "device type: %x\n",
|
||||
x_sys->device_type);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "mspro id: %s\n",
|
||||
x_sys->mspro_id);
|
||||
rc += sysfs_emit_at(buffer, rc, "class: %x\n", x_sys->class);
|
||||
rc += sysfs_emit_at(buffer, rc, "block size: %x\n", be16_to_cpu(x_sys->block_size));
|
||||
rc += sysfs_emit_at(buffer, rc, "block count: %x\n", be16_to_cpu(x_sys->block_count));
|
||||
rc += sysfs_emit_at(buffer, rc, "user block count: %x\n",
|
||||
be16_to_cpu(x_sys->user_block_count));
|
||||
rc += sysfs_emit_at(buffer, rc, "page size: %x\n", be16_to_cpu(x_sys->page_size));
|
||||
rc += sysfs_emit_at(buffer, rc, "assembly date: GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n",
|
||||
date_tz, date_tz_f,
|
||||
be16_to_cpup((__be16 *)&x_sys->assembly_date[1]),
|
||||
x_sys->assembly_date[3], x_sys->assembly_date[4],
|
||||
x_sys->assembly_date[5], x_sys->assembly_date[6],
|
||||
x_sys->assembly_date[7]);
|
||||
rc += sysfs_emit_at(buffer, rc, "serial number: %x\n", be32_to_cpu(x_sys->serial_number));
|
||||
rc += sysfs_emit_at(buffer, rc, "assembly maker code: %x\n", x_sys->assembly_maker_code);
|
||||
rc += sysfs_emit_at(buffer, rc, "assembly model code: %02x%02x%02x\n",
|
||||
x_sys->assembly_model_code[0],
|
||||
x_sys->assembly_model_code[1],
|
||||
x_sys->assembly_model_code[2]);
|
||||
rc += sysfs_emit_at(buffer, rc, "memory maker code: %x\n",
|
||||
be16_to_cpu(x_sys->memory_maker_code));
|
||||
rc += sysfs_emit_at(buffer, rc, "memory model code: %x\n",
|
||||
be16_to_cpu(x_sys->memory_model_code));
|
||||
rc += sysfs_emit_at(buffer, rc, "vcc: %x\n", x_sys->vcc);
|
||||
rc += sysfs_emit_at(buffer, rc, "vpp: %x\n", x_sys->vpp);
|
||||
rc += sysfs_emit_at(buffer, rc, "controller number: %x\n",
|
||||
be16_to_cpu(x_sys->controller_number));
|
||||
rc += sysfs_emit_at(buffer, rc, "controller function: %x\n",
|
||||
be16_to_cpu(x_sys->controller_function));
|
||||
rc += sysfs_emit_at(buffer, rc, "start sector: %x\n", be16_to_cpu(x_sys->start_sector));
|
||||
rc += sysfs_emit_at(buffer, rc, "unit size: %x\n", be16_to_cpu(x_sys->unit_size));
|
||||
rc += sysfs_emit_at(buffer, rc, "sub class: %x\n", x_sys->ms_sub_class);
|
||||
rc += sysfs_emit_at(buffer, rc, "interface type: %x\n", x_sys->interface_type);
|
||||
rc += sysfs_emit_at(buffer, rc, "controller code: %x\n",
|
||||
be16_to_cpu(x_sys->controller_code));
|
||||
rc += sysfs_emit_at(buffer, rc, "format type: %x\n", x_sys->format_type);
|
||||
rc += sysfs_emit_at(buffer, rc, "device type: %x\n", x_sys->device_type);
|
||||
rc += sysfs_emit_at(buffer, rc, "mspro id: %s\n", x_sys->mspro_id);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -356,7 +338,7 @@ static ssize_t mspro_block_attr_show_modelname(struct device *dev,
|
||||
struct mspro_sys_attr,
|
||||
dev_attr);
|
||||
|
||||
return scnprintf(buffer, PAGE_SIZE, "%s", (char *)s_attr->data);
|
||||
return sysfs_emit(buffer, "%s", (char *)s_attr->data);
|
||||
}
|
||||
|
||||
static ssize_t mspro_block_attr_show_mbr(struct device *dev,
|
||||
@ -369,27 +351,17 @@ static ssize_t mspro_block_attr_show_mbr(struct device *dev,
|
||||
struct mspro_mbr *x_mbr = x_attr->data;
|
||||
ssize_t rc = 0;
|
||||
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "boot partition: %x\n",
|
||||
x_mbr->boot_partition);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start head: %x\n",
|
||||
x_mbr->start_head);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sector: %x\n",
|
||||
x_mbr->start_sector);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cylinder: %x\n",
|
||||
x_mbr->start_cylinder);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "partition type: %x\n",
|
||||
x_mbr->partition_type);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end head: %x\n",
|
||||
x_mbr->end_head);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end sector: %x\n",
|
||||
x_mbr->end_sector);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "end cylinder: %x\n",
|
||||
x_mbr->end_cylinder);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start sectors: %x\n",
|
||||
x_mbr->start_sectors);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc,
|
||||
"sectors per partition: %x\n",
|
||||
x_mbr->sectors_per_partition);
|
||||
rc += sysfs_emit_at(buffer, rc, "boot partition: %x\n", x_mbr->boot_partition);
|
||||
rc += sysfs_emit_at(buffer, rc, "start head: %x\n", x_mbr->start_head);
|
||||
rc += sysfs_emit_at(buffer, rc, "start sector: %x\n", x_mbr->start_sector);
|
||||
rc += sysfs_emit_at(buffer, rc, "start cylinder: %x\n", x_mbr->start_cylinder);
|
||||
rc += sysfs_emit_at(buffer, rc, "partition type: %x\n", x_mbr->partition_type);
|
||||
rc += sysfs_emit_at(buffer, rc, "end head: %x\n", x_mbr->end_head);
|
||||
rc += sysfs_emit_at(buffer, rc, "end sector: %x\n", x_mbr->end_sector);
|
||||
rc += sysfs_emit_at(buffer, rc, "end cylinder: %x\n", x_mbr->end_cylinder);
|
||||
rc += sysfs_emit_at(buffer, rc, "start sectors: %x\n", x_mbr->start_sectors);
|
||||
rc += sysfs_emit_at(buffer, rc, "sectors per partition: %x\n",
|
||||
x_mbr->sectors_per_partition);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -409,22 +381,19 @@ static ssize_t mspro_block_attr_show_specfile(struct device *dev,
|
||||
memcpy(ext, x_spfile->ext, 3);
|
||||
ext[3] = 0;
|
||||
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "name: %s\n", name);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "ext: %s\n", ext);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "attribute: %x\n",
|
||||
x_spfile->attr);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "time: %d:%d:%d\n",
|
||||
x_spfile->time >> 11,
|
||||
(x_spfile->time >> 5) & 0x3f,
|
||||
(x_spfile->time & 0x1f) * 2);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "date: %d-%d-%d\n",
|
||||
(x_spfile->date >> 9) + 1980,
|
||||
(x_spfile->date >> 5) & 0xf,
|
||||
x_spfile->date & 0x1f);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "start cluster: %x\n",
|
||||
x_spfile->cluster);
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "size: %x\n",
|
||||
x_spfile->size);
|
||||
rc += sysfs_emit_at(buffer, rc, "name: %s\n", name);
|
||||
rc += sysfs_emit_at(buffer, rc, "ext: %s\n", ext);
|
||||
rc += sysfs_emit_at(buffer, rc, "attribute: %x\n", x_spfile->attr);
|
||||
rc += sysfs_emit_at(buffer, rc, "time: %d:%d:%d\n",
|
||||
x_spfile->time >> 11,
|
||||
(x_spfile->time >> 5) & 0x3f,
|
||||
(x_spfile->time & 0x1f) * 2);
|
||||
rc += sysfs_emit_at(buffer, rc, "date: %d-%d-%d\n",
|
||||
(x_spfile->date >> 9) + 1980,
|
||||
(x_spfile->date >> 5) & 0xf,
|
||||
x_spfile->date & 0x1f);
|
||||
rc += sysfs_emit_at(buffer, rc, "start cluster: %x\n", x_spfile->cluster);
|
||||
rc += sysfs_emit_at(buffer, rc, "size: %x\n", x_spfile->size);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -438,16 +407,14 @@ static ssize_t mspro_block_attr_show_devinfo(struct device *dev,
|
||||
struct mspro_devinfo *x_devinfo = x_attr->data;
|
||||
ssize_t rc = 0;
|
||||
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "cylinders: %x\n",
|
||||
be16_to_cpu(x_devinfo->cylinders));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "heads: %x\n",
|
||||
be16_to_cpu(x_devinfo->heads));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per track: %x\n",
|
||||
be16_to_cpu(x_devinfo->bytes_per_track));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "bytes per sector: %x\n",
|
||||
be16_to_cpu(x_devinfo->bytes_per_sector));
|
||||
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "sectors per track: %x\n",
|
||||
be16_to_cpu(x_devinfo->sectors_per_track));
|
||||
rc += sysfs_emit_at(buffer, rc, "cylinders: %x\n", be16_to_cpu(x_devinfo->cylinders));
|
||||
rc += sysfs_emit_at(buffer, rc, "heads: %x\n", be16_to_cpu(x_devinfo->heads));
|
||||
rc += sysfs_emit_at(buffer, rc, "bytes per track: %x\n",
|
||||
be16_to_cpu(x_devinfo->bytes_per_track));
|
||||
rc += sysfs_emit_at(buffer, rc, "bytes per sector: %x\n",
|
||||
be16_to_cpu(x_devinfo->bytes_per_sector));
|
||||
rc += sysfs_emit_at(buffer, rc, "sectors per track: %x\n",
|
||||
be16_to_cpu(x_devinfo->sectors_per_track));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -514,19 +514,6 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
|
||||
if (idata->ic.data_timeout_ns)
|
||||
data.timeout_ns = idata->ic.data_timeout_ns;
|
||||
|
||||
if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
|
||||
/*
|
||||
* Pretend this is a data transfer and rely on the
|
||||
* host driver to compute timeout. When all host
|
||||
* drivers support cmd.cmd_timeout for R1B, this
|
||||
* can be changed to:
|
||||
*
|
||||
* mrq.data = NULL;
|
||||
* cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
|
||||
*/
|
||||
data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
|
||||
}
|
||||
|
||||
mrq.data = &data;
|
||||
}
|
||||
|
||||
|
@ -359,9 +359,7 @@ int mmc_add_card(struct mmc_card *card)
|
||||
uhs_bus_speed_mode, type, card->rca);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_add_card_debugfs(card);
|
||||
#endif
|
||||
card->dev.of_node = mmc_of_find_child_device(card->host, 0);
|
||||
|
||||
device_enable_async_suspend(&card->dev);
|
||||
@ -383,9 +381,7 @@ void mmc_remove_card(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_remove_card_debugfs(card);
|
||||
#endif
|
||||
|
||||
if (mmc_card_present(card)) {
|
||||
if (mmc_host_is_spi(card->host)) {
|
||||
|
@ -56,7 +56,7 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
|
||||
/*
|
||||
* Enabling software CRCs on the data blocks can be a significant (30%)
|
||||
* performance cost, and for other reasons may not always be desired.
|
||||
* So we allow it it to be disabled.
|
||||
* So we allow it to be disabled.
|
||||
*/
|
||||
bool use_spi_crc = 1;
|
||||
module_param(use_spi_crc, bool, 0);
|
||||
@ -142,8 +142,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
|
||||
int err = cmd->error;
|
||||
|
||||
/* Flag re-tuning needed on CRC errors */
|
||||
if (cmd->opcode != MMC_SEND_TUNING_BLOCK &&
|
||||
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
|
||||
if (!mmc_op_tuning(cmd->opcode) &&
|
||||
!host->retune_crc_disable &&
|
||||
(err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) ||
|
||||
(mrq->data && mrq->data->error == -EILSEQ) ||
|
||||
@ -527,7 +526,7 @@ EXPORT_SYMBOL(mmc_cqe_post_req);
|
||||
* mmc_cqe_recovery - Recover from CQE errors.
|
||||
* @host: MMC host to recover
|
||||
*
|
||||
* Recovery consists of stopping CQE, stopping eMMC, discarding the queue in
|
||||
* Recovery consists of stopping CQE, stopping eMMC, discarding the queue
|
||||
* in eMMC, and discarding the queue in CQE. CQE must call
|
||||
* mmc_cqe_request_done() on all requests. An error is returned if the eMMC
|
||||
* fails to discard its queue.
|
||||
|
@ -86,11 +86,26 @@ int mmc_attach_sdio(struct mmc_host *host);
|
||||
extern bool use_spi_crc;
|
||||
|
||||
/* Debugfs information for hosts and cards */
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void mmc_add_host_debugfs(struct mmc_host *host);
|
||||
void mmc_remove_host_debugfs(struct mmc_host *host);
|
||||
|
||||
void mmc_add_card_debugfs(struct mmc_card *card);
|
||||
void mmc_remove_card_debugfs(struct mmc_card *card);
|
||||
#else
|
||||
static inline void mmc_add_host_debugfs(struct mmc_host *host)
|
||||
{
|
||||
}
|
||||
static inline void mmc_remove_host_debugfs(struct mmc_host *host)
|
||||
{
|
||||
}
|
||||
static inline void mmc_add_card_debugfs(struct mmc_card *card)
|
||||
{
|
||||
}
|
||||
static inline void mmc_remove_card_debugfs(struct mmc_card *card)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int mmc_execute_tuning(struct mmc_card *card);
|
||||
int mmc_hs200_to_hs400(struct mmc_card *card);
|
||||
|
@ -269,7 +269,7 @@ EXPORT_SYMBOL(mmc_of_parse_clk_phase);
|
||||
* @host: host whose properties should be parsed.
|
||||
*
|
||||
* To keep the rest of the MMC subsystem unaware of whether DT has been
|
||||
* used to to instantiate and configure this host instance or not, we
|
||||
* used to instantiate and configure this host instance or not, we
|
||||
* parse the properties and set respective generic mmc-host flags and
|
||||
* parameters.
|
||||
*/
|
||||
@ -629,9 +629,7 @@ int mmc_add_host(struct mmc_host *host)
|
||||
|
||||
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_add_host_debugfs(host);
|
||||
#endif
|
||||
|
||||
mmc_start_host(host);
|
||||
return 0;
|
||||
@ -651,9 +649,7 @@ void mmc_remove_host(struct mmc_host *host)
|
||||
{
|
||||
mmc_stop_host(host);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_remove_host_debugfs(host);
|
||||
#endif
|
||||
|
||||
device_del(&host->class_dev);
|
||||
|
||||
|
@ -932,7 +932,6 @@ static int mmc_test_transfer(struct mmc_test_card *test,
|
||||
unsigned blocks, unsigned blksz, int write)
|
||||
{
|
||||
int ret, i;
|
||||
unsigned long flags;
|
||||
|
||||
if (write) {
|
||||
for (i = 0; i < blocks * blksz; i++)
|
||||
@ -940,9 +939,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
|
||||
} else {
|
||||
memset(test->scratch, 0, BUFFER_SIZE);
|
||||
}
|
||||
local_irq_save(flags);
|
||||
sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
|
||||
local_irq_restore(flags);
|
||||
|
||||
ret = mmc_test_set_blksize(test, blksz);
|
||||
if (ret)
|
||||
@ -987,9 +984,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
|
||||
return RESULT_FAIL;
|
||||
}
|
||||
} else {
|
||||
local_irq_save(flags);
|
||||
sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
|
||||
local_irq_restore(flags);
|
||||
for (i = 0; i < blocks * blksz; i++) {
|
||||
if (test->scratch[i] != (u8)i)
|
||||
return RESULT_FAIL;
|
||||
|
@ -29,7 +29,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
|
||||
|
||||
mutex_lock(&pwrseq_list_mutex);
|
||||
list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
|
||||
if (p->dev->of_node == np) {
|
||||
if (device_match_of_node(p->dev, np)) {
|
||||
if (!try_module_get(p->owner))
|
||||
dev_err(host->parent,
|
||||
"increasing module refcount failed\n");
|
||||
|
@ -1259,7 +1259,7 @@ static int sd_read_ext_regs(struct mmc_card *card)
|
||||
*/
|
||||
err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf);
|
||||
if (err) {
|
||||
pr_warn("%s: error %d reading general info of SD ext reg\n",
|
||||
pr_err("%s: error %d reading general info of SD ext reg\n",
|
||||
mmc_hostname(card->host), err);
|
||||
goto out;
|
||||
}
|
||||
@ -1273,7 +1273,12 @@ static int sd_read_ext_regs(struct mmc_card *card)
|
||||
/* Number of extensions to be find. */
|
||||
num_ext = gen_info_buf[4];
|
||||
|
||||
/* We support revision 0, but limit it to 512 bytes for simplicity. */
|
||||
/*
|
||||
* We only support revision 0 and limit it to 512 bytes for simplicity.
|
||||
* No matter what, let's return zero to allow us to continue using the
|
||||
* card, even if we can't support the features from the SD function
|
||||
* extensions registers.
|
||||
*/
|
||||
if (rev != 0 || len > 512) {
|
||||
pr_warn("%s: non-supported SD ext reg layout\n",
|
||||
mmc_hostname(card->host));
|
||||
@ -1288,7 +1293,7 @@ static int sd_read_ext_regs(struct mmc_card *card)
|
||||
for (i = 0; i < num_ext; i++) {
|
||||
err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr);
|
||||
if (err) {
|
||||
pr_warn("%s: error %d parsing SD ext reg\n",
|
||||
pr_err("%s: error %d parsing SD ext reg\n",
|
||||
mmc_hostname(card->host), err);
|
||||
goto out;
|
||||
}
|
||||
|
@ -14,6 +14,15 @@ config MMC_DEBUG
|
||||
added host drivers please don't invent their private macro for
|
||||
debugging.
|
||||
|
||||
config MMC_SUNPLUS
|
||||
tristate "Sunplus SP7021 MMC Controller"
|
||||
depends on ARCH_SUNPLUS || COMPILE_TEST
|
||||
help
|
||||
If you say yes here, you will get support for eMMC host interface
|
||||
on Sunplus SoCs.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config MMC_ARMMMCI
|
||||
tristate "ARM AMBA Multimedia Card Interface support"
|
||||
depends on ARM_AMBA
|
||||
@ -1040,10 +1049,10 @@ config MMC_SDHCI_MICROCHIP_PIC32
|
||||
|
||||
config MMC_SDHCI_BRCMSTB
|
||||
tristate "Broadcom SDIO/SD/MMC support"
|
||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC
|
||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
select MMC_CQHCI
|
||||
default y
|
||||
default ARCH_BRCMSTB || BMIPS_GENERIC
|
||||
help
|
||||
This selects support for the SDIO/SD/MMC Host Controller on
|
||||
Broadcom STB SoCs.
|
||||
|
@ -97,6 +97,7 @@ obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
|
||||
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
|
||||
obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o
|
||||
obj-$(CONFIG_MMC_SDHCI_SPRD) += sdhci-sprd.o
|
||||
obj-$(CONFIG_MMC_SUNPLUS) += sunplus-mmc.o
|
||||
obj-$(CONFIG_MMC_CQHCI) += cqhci.o
|
||||
cqhci-y += cqhci-core.o
|
||||
cqhci-$(CONFIG_MMC_CRYPTO) += cqhci-crypto.o
|
||||
|
@ -1114,7 +1114,10 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)
|
||||
alcor_hw_init(host);
|
||||
|
||||
dev_set_drvdata(&pdev->dev, host);
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto free_host;
|
||||
|
||||
return 0;
|
||||
|
||||
free_host:
|
||||
|
@ -2222,6 +2222,7 @@ static int atmci_init_slot(struct atmel_mci *host,
|
||||
{
|
||||
struct mmc_host *mmc;
|
||||
struct atmel_mci_slot *slot;
|
||||
int ret;
|
||||
|
||||
mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
|
||||
if (!mmc)
|
||||
@ -2305,11 +2306,13 @@ static int atmci_init_slot(struct atmel_mci *host,
|
||||
|
||||
host->slot[id] = slot;
|
||||
mmc_regulator_get_supply(mmc);
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret) {
|
||||
mmc_free_host(mmc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(slot->detect_pin)) {
|
||||
int ret;
|
||||
|
||||
timer_setup(&slot->detect_timer, atmci_detect_change, 0);
|
||||
|
||||
ret = request_irq(gpio_to_irq(slot->detect_pin),
|
||||
|
@ -388,7 +388,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
|
||||
|
||||
/* This is the pointer to the data buffer */
|
||||
sg = &data->sg[host->pio.index];
|
||||
sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset;
|
||||
sg_ptr = kmap_local_page(sg_page(sg)) + sg->offset + host->pio.offset;
|
||||
|
||||
/* This is the space left inside the buffer */
|
||||
sg_len = data->sg[host->pio.index].length - host->pio.offset;
|
||||
@ -409,7 +409,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
|
||||
__raw_writel((unsigned long)val, HOST_TXPORT(host));
|
||||
wmb(); /* drain writebuffer */
|
||||
}
|
||||
kunmap_atomic(sg_ptr);
|
||||
kunmap_local(sg_ptr);
|
||||
|
||||
host->pio.len -= count;
|
||||
host->pio.offset += count;
|
||||
@ -446,7 +446,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
|
||||
|
||||
if (host->pio.index < host->dma.len) {
|
||||
sg = &data->sg[host->pio.index];
|
||||
sg_ptr = kmap_atomic(sg_page(sg)) + sg->offset + host->pio.offset;
|
||||
sg_ptr = kmap_local_page(sg_page(sg)) + sg->offset + host->pio.offset;
|
||||
|
||||
/* This is the space left inside the buffer */
|
||||
sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
|
||||
@ -488,7 +488,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
|
||||
sg_ptr[count] = (unsigned char)(val & 0xFF);
|
||||
}
|
||||
if (sg_ptr)
|
||||
kunmap_atomic(sg_ptr);
|
||||
kunmap_local(sg_ptr);
|
||||
|
||||
host->pio.len -= count;
|
||||
host->pio.offset += count;
|
||||
|
@ -327,7 +327,6 @@ static void bcm2835_dma_complete(void *param)
|
||||
|
||||
static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read)
|
||||
{
|
||||
unsigned long flags;
|
||||
size_t blksize;
|
||||
unsigned long wait_max;
|
||||
|
||||
@ -335,8 +334,6 @@ static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read)
|
||||
|
||||
wait_max = jiffies + msecs_to_jiffies(500);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
while (blksize) {
|
||||
int copy_words;
|
||||
u32 hsts = 0;
|
||||
@ -421,8 +418,6 @@ static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read)
|
||||
}
|
||||
|
||||
sg_miter_stop(&host->sg_miter);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void bcm2835_transfer_pio(struct bcm2835_host *host)
|
||||
@ -1068,7 +1063,6 @@ static void bcm2835_dma_complete_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (host->drain_words) {
|
||||
unsigned long flags;
|
||||
void *page;
|
||||
u32 *buf;
|
||||
|
||||
@ -1076,8 +1070,7 @@ static void bcm2835_dma_complete_work(struct work_struct *work)
|
||||
host->drain_page += host->drain_offset >> PAGE_SHIFT;
|
||||
host->drain_offset &= ~PAGE_MASK;
|
||||
}
|
||||
local_irq_save(flags);
|
||||
page = kmap_atomic(host->drain_page);
|
||||
page = kmap_local_page(host->drain_page);
|
||||
buf = page + host->drain_offset;
|
||||
|
||||
while (host->drain_words) {
|
||||
@ -1088,8 +1081,7 @@ static void bcm2835_dma_complete_work(struct work_struct *work)
|
||||
host->drain_words--;
|
||||
}
|
||||
|
||||
kunmap_atomic(page);
|
||||
local_irq_restore(flags);
|
||||
kunmap_local(page);
|
||||
}
|
||||
|
||||
bcm2835_finish_data(host);
|
||||
|
@ -17,10 +17,16 @@
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/altera-sysmgr.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "dw_mmc.h"
|
||||
#include "dw_mmc-pltfm.h"
|
||||
|
||||
#define SOCFPGA_DW_MMC_CLK_PHASE_STEP 45
|
||||
#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel, reg_shift) \
|
||||
((((smplsel) & 0x7) << reg_shift) | (((drvsel) & 0x7) << 0))
|
||||
|
||||
int dw_mci_pltfm_register(struct platform_device *pdev,
|
||||
const struct dw_mci_drv_data *drv_data)
|
||||
{
|
||||
@ -62,9 +68,42 @@ const struct dev_pm_ops dw_mci_pltfm_pmops = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
|
||||
|
||||
static int dw_mci_socfpga_priv_init(struct dw_mci *host)
|
||||
{
|
||||
struct device_node *np = host->dev->of_node;
|
||||
struct regmap *sys_mgr_base_addr;
|
||||
u32 clk_phase[2] = {0}, reg_offset, reg_shift;
|
||||
int i, rc, hs_timing;
|
||||
|
||||
rc = of_property_read_variable_u32_array(np, "clk-phase-sd-hs", &clk_phase[0], 2, 0);
|
||||
if (rc < 0)
|
||||
return 0;
|
||||
|
||||
sys_mgr_base_addr = altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
|
||||
if (IS_ERR(sys_mgr_base_addr)) {
|
||||
dev_warn(host->dev, "clk-phase-sd-hs was specified, but failed to find altr,sys-mgr regmap!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, ®_offset);
|
||||
of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, ®_shift);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clk_phase); i++)
|
||||
clk_phase[i] /= SOCFPGA_DW_MMC_CLK_PHASE_STEP;
|
||||
|
||||
hs_timing = SYSMGR_SDMMC_CTRL_SET(clk_phase[0], clk_phase[1], reg_shift);
|
||||
regmap_write(sys_mgr_base_addr, reg_offset, hs_timing);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_mci_drv_data socfpga_drv_data = {
|
||||
.init = dw_mci_socfpga_priv_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id dw_mci_pltfm_match[] = {
|
||||
{ .compatible = "snps,dw-mshc", },
|
||||
{ .compatible = "altr,socfpga-dw-mshc", },
|
||||
{ .compatible = "altr,socfpga-dw-mshc", .data = &socfpga_drv_data, },
|
||||
{ .compatible = "img,pistachio-dw-mshc", },
|
||||
{},
|
||||
};
|
||||
|
@ -334,8 +334,7 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
|
||||
cmdr == MMC_READ_MULTIPLE_BLOCK ||
|
||||
cmdr == MMC_WRITE_BLOCK ||
|
||||
cmdr == MMC_WRITE_MULTIPLE_BLOCK ||
|
||||
cmdr == MMC_SEND_TUNING_BLOCK ||
|
||||
cmdr == MMC_SEND_TUNING_BLOCK_HS200 ||
|
||||
mmc_op_tuning(cmdr) ||
|
||||
cmdr == MMC_GEN_CMD) {
|
||||
stop->opcode = MMC_STOP_TRANSMISSION;
|
||||
stop->arg = 0;
|
||||
@ -1363,7 +1362,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
|
||||
* is just about to roll over.
|
||||
*
|
||||
* We do this whole thing under spinlock and only if the
|
||||
* command hasn't already completed (indicating the the irq
|
||||
* command hasn't already completed (indicating the irq
|
||||
* already ran so we don't want the timeout).
|
||||
*/
|
||||
spin_lock_irqsave(&host->irq_lock, irqflags);
|
||||
|
@ -502,6 +502,7 @@ static int litex_mmc_irq_init(struct platform_device *pdev,
|
||||
|
||||
use_polling:
|
||||
host->mmc->caps |= MMC_CAP_NEEDS_POLL;
|
||||
host->irq = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1335,7 +1335,9 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
mmc->ops = &meson_mmc_ops;
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto err_free_irq;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -13,9 +13,6 @@
|
||||
|
||||
#include "mmc_hsq.h"
|
||||
|
||||
#define HSQ_NUM_SLOTS 64
|
||||
#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
|
||||
|
||||
static void mmc_hsq_retry_handler(struct work_struct *work)
|
||||
{
|
||||
struct mmc_hsq *hsq = container_of(work, struct mmc_hsq, retry_work);
|
||||
@ -73,7 +70,6 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
|
||||
|
||||
static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
|
||||
{
|
||||
struct hsq_slot *slot;
|
||||
int tag;
|
||||
|
||||
/*
|
||||
@ -82,29 +78,12 @@ static void mmc_hsq_update_next_tag(struct mmc_hsq *hsq, int remains)
|
||||
*/
|
||||
if (!remains) {
|
||||
hsq->next_tag = HSQ_INVALID_TAG;
|
||||
hsq->tail_tag = HSQ_INVALID_TAG;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increasing the next tag and check if the corresponding request is
|
||||
* available, if yes, then we found a candidate request.
|
||||
*/
|
||||
if (++hsq->next_tag != HSQ_INVALID_TAG) {
|
||||
slot = &hsq->slot[hsq->next_tag];
|
||||
if (slot->mrq)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Othersie we should iterate all slots to find a available tag. */
|
||||
for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) {
|
||||
slot = &hsq->slot[tag];
|
||||
if (slot->mrq)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tag == HSQ_NUM_SLOTS)
|
||||
tag = HSQ_INVALID_TAG;
|
||||
|
||||
tag = hsq->tag_slot[hsq->next_tag];
|
||||
hsq->tag_slot[hsq->next_tag] = HSQ_INVALID_TAG;
|
||||
hsq->next_tag = tag;
|
||||
}
|
||||
|
||||
@ -233,8 +212,14 @@ static int mmc_hsq_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
* Set the next tag as current request tag if no available
|
||||
* next tag.
|
||||
*/
|
||||
if (hsq->next_tag == HSQ_INVALID_TAG)
|
||||
if (hsq->next_tag == HSQ_INVALID_TAG) {
|
||||
hsq->next_tag = tag;
|
||||
hsq->tail_tag = tag;
|
||||
hsq->tag_slot[hsq->tail_tag] = HSQ_INVALID_TAG;
|
||||
} else {
|
||||
hsq->tag_slot[hsq->tail_tag] = tag;
|
||||
hsq->tail_tag = tag;
|
||||
}
|
||||
|
||||
hsq->qcnt++;
|
||||
|
||||
@ -339,8 +324,10 @@ static const struct mmc_cqe_ops mmc_hsq_ops = {
|
||||
|
||||
int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
|
||||
{
|
||||
int i;
|
||||
hsq->num_slots = HSQ_NUM_SLOTS;
|
||||
hsq->next_tag = HSQ_INVALID_TAG;
|
||||
hsq->tail_tag = HSQ_INVALID_TAG;
|
||||
|
||||
hsq->slot = devm_kcalloc(mmc_dev(mmc), hsq->num_slots,
|
||||
sizeof(struct hsq_slot), GFP_KERNEL);
|
||||
@ -351,6 +338,9 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
|
||||
hsq->mmc->cqe_private = hsq;
|
||||
mmc->cqe_ops = &mmc_hsq_ops;
|
||||
|
||||
for (i = 0; i < HSQ_NUM_SLOTS; i++)
|
||||
hsq->tag_slot[i] = HSQ_INVALID_TAG;
|
||||
|
||||
INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler);
|
||||
spin_lock_init(&hsq->lock);
|
||||
init_waitqueue_head(&hsq->wait_queue);
|
||||
|
@ -2,6 +2,9 @@
|
||||
#ifndef LINUX_MMC_HSQ_H
|
||||
#define LINUX_MMC_HSQ_H
|
||||
|
||||
#define HSQ_NUM_SLOTS 64
|
||||
#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
|
||||
|
||||
struct hsq_slot {
|
||||
struct mmc_request *mrq;
|
||||
};
|
||||
@ -17,6 +20,8 @@ struct mmc_hsq {
|
||||
int next_tag;
|
||||
int num_slots;
|
||||
int qcnt;
|
||||
int tail_tag;
|
||||
int tag_slot[HSQ_NUM_SLOTS];
|
||||
|
||||
bool enabled;
|
||||
bool waiting_for_idle;
|
||||
|
@ -2256,7 +2256,9 @@ static int mmci_probe(struct amba_device *dev,
|
||||
pm_runtime_set_autosuspend_delay(&dev->dev, 50);
|
||||
pm_runtime_use_autosuspend(&dev->dev);
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
pm_runtime_put(&dev->dev);
|
||||
return 0;
|
||||
|
@ -665,7 +665,9 @@ static int moxart_probe(struct platform_device *pdev)
|
||||
goto out;
|
||||
|
||||
dev_set_drvdata(dev, mmc);
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
dev_dbg(dev, "IRQ=%d, FIFO is %d bytes\n", irq, host->fifo_width);
|
||||
|
||||
|
@ -452,6 +452,7 @@ struct msdc_host {
|
||||
struct clk *bus_clk; /* bus clock which used to access register */
|
||||
struct clk *src_clk_cg; /* msdc source clock control gate */
|
||||
struct clk *sys_clk_cg; /* msdc subsys clock control gate */
|
||||
struct clk *crypto_clk; /* msdc crypto clock control gate */
|
||||
struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS];
|
||||
u32 mclk; /* mmc subsystem clock frequency */
|
||||
u32 src_clk_freq; /* source clock frequency */
|
||||
@ -552,6 +553,19 @@ static const struct mtk_mmc_compatible mt7622_compat = {
|
||||
.support_64g = false,
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt7986_compat = {
|
||||
.clk_div_bits = 12,
|
||||
.recheck_sdio_irq = true,
|
||||
.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 mtk_mmc_compatible mt8135_compat = {
|
||||
.clk_div_bits = 8,
|
||||
.recheck_sdio_irq = true,
|
||||
@ -609,6 +623,7 @@ static const struct of_device_id msdc_of_ids[] = {
|
||||
{ .compatible = "mediatek,mt6795-mmc", .data = &mt6795_compat},
|
||||
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
|
||||
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
|
||||
{ .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat},
|
||||
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
|
||||
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
|
||||
{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
|
||||
@ -735,7 +750,7 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
|
||||
else
|
||||
bd[j].bd_info &= ~BDMA_DESC_EOL;
|
||||
|
||||
/* checksume need to clear first */
|
||||
/* checksum need to clear first */
|
||||
bd[j].bd_info &= ~BDMA_DESC_CHECKSUM;
|
||||
bd[j].bd_info |= msdc_dma_calcs((u8 *)(&bd[j]), 16) << 8;
|
||||
}
|
||||
@ -826,6 +841,7 @@ static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks)
|
||||
static void msdc_gate_clock(struct msdc_host *host)
|
||||
{
|
||||
clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks);
|
||||
clk_disable_unprepare(host->crypto_clk);
|
||||
clk_disable_unprepare(host->src_clk_cg);
|
||||
clk_disable_unprepare(host->src_clk);
|
||||
clk_disable_unprepare(host->bus_clk);
|
||||
@ -841,6 +857,7 @@ static int msdc_ungate_clock(struct msdc_host *host)
|
||||
clk_prepare_enable(host->bus_clk);
|
||||
clk_prepare_enable(host->src_clk);
|
||||
clk_prepare_enable(host->src_clk_cg);
|
||||
clk_prepare_enable(host->crypto_clk);
|
||||
ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n");
|
||||
@ -1207,12 +1224,10 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
|
||||
|
||||
if (!sbc_error && !(events & MSDC_INT_CMDRDY)) {
|
||||
if (events & MSDC_INT_CMDTMO ||
|
||||
(cmd->opcode != MMC_SEND_TUNING_BLOCK &&
|
||||
cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200 &&
|
||||
!host->hs400_tuning))
|
||||
(!mmc_op_tuning(cmd->opcode) && !host->hs400_tuning))
|
||||
/*
|
||||
* should not clear fifo/interrupt as the tune data
|
||||
* may have alreay come when cmd19/cmd21 gets response
|
||||
* may have already come when cmd19/cmd21 gets response
|
||||
* CRC error.
|
||||
*/
|
||||
msdc_reset_hw(host);
|
||||
@ -1303,9 +1318,7 @@ static void msdc_cmd_next(struct msdc_host *host,
|
||||
{
|
||||
if ((cmd->error &&
|
||||
!(cmd->error == -EILSEQ &&
|
||||
(cmd->opcode == MMC_SEND_TUNING_BLOCK ||
|
||||
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200 ||
|
||||
host->hs400_tuning))) ||
|
||||
(mmc_op_tuning(cmd->opcode) || host->hs400_tuning))) ||
|
||||
(mrq->sbc && mrq->sbc->error))
|
||||
msdc_request_done(host, mrq);
|
||||
else if (cmd == mrq->sbc)
|
||||
@ -2656,6 +2669,15 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
goto host_free;
|
||||
}
|
||||
|
||||
/* only eMMC has crypto property */
|
||||
if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
|
||||
host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
|
||||
if (IS_ERR(host->crypto_clk))
|
||||
host->crypto_clk = NULL;
|
||||
else
|
||||
mmc->caps2 |= MMC_CAP2_CRYPTO;
|
||||
}
|
||||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
if (host->irq < 0) {
|
||||
ret = -EINVAL;
|
||||
|
@ -1143,7 +1143,9 @@ static int mxcmci_probe(struct platform_device *pdev)
|
||||
|
||||
timer_setup(&host->watchdog, mxcmci_watchdog, 0);
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto out_free_dma;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -1946,7 +1946,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
||||
if (!ret)
|
||||
mmc->caps |= MMC_CAP_SDIO_IRQ;
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto err_irq;
|
||||
|
||||
if (mmc_pdata(host)->name != NULL) {
|
||||
ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
|
||||
|
@ -763,7 +763,12 @@ static int pxamci_probe(struct platform_device *pdev)
|
||||
dev_warn(dev, "gpio_ro and get_ro() both defined\n");
|
||||
}
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret) {
|
||||
if (host->pdata && host->pdata->exit)
|
||||
host->pdata->exit(dev, mmc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -38,12 +38,15 @@ struct renesas_sdhi_of_data {
|
||||
|
||||
#define SDHI_CALIB_TABLE_MAX 32
|
||||
|
||||
#define sdhi_has_quirk(p, q) ((p)->quirks && (p)->quirks->q)
|
||||
|
||||
struct renesas_sdhi_quirks {
|
||||
bool hs400_disabled;
|
||||
bool hs400_4taps;
|
||||
bool fixed_addr_mode;
|
||||
bool dma_one_rx_only;
|
||||
bool manual_tap_correction;
|
||||
bool old_info1_layout;
|
||||
u32 hs400_bad_taps;
|
||||
const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX];
|
||||
};
|
||||
@ -53,12 +56,17 @@ struct renesas_sdhi_of_data_with_quirks {
|
||||
const struct renesas_sdhi_quirks *quirks;
|
||||
};
|
||||
|
||||
struct tmio_mmc_dma {
|
||||
/* We want both end_flags to be set before we mark DMA as finished */
|
||||
#define SDHI_DMA_END_FLAG_DMA 0
|
||||
#define SDHI_DMA_END_FLAG_ACCESS 1
|
||||
|
||||
struct renesas_sdhi_dma {
|
||||
unsigned long end_flags;
|
||||
enum dma_slave_buswidth dma_buswidth;
|
||||
bool (*filter)(struct dma_chan *chan, void *arg);
|
||||
void (*enable)(struct tmio_mmc_host *host, bool enable);
|
||||
struct completion dma_dataend;
|
||||
struct tasklet_struct dma_complete;
|
||||
struct completion dma_dataend;
|
||||
struct tasklet_struct dma_complete;
|
||||
};
|
||||
|
||||
struct renesas_sdhi {
|
||||
@ -66,7 +74,7 @@ struct renesas_sdhi {
|
||||
struct clk *clkh;
|
||||
struct clk *clk_cd;
|
||||
struct tmio_mmc_data mmc_data;
|
||||
struct tmio_mmc_dma dma_priv;
|
||||
struct renesas_sdhi_dma dma_priv;
|
||||
const struct renesas_sdhi_quirks *quirks;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default, *pins_uhs;
|
||||
|
@ -141,7 +141,7 @@ static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
|
||||
|
||||
if (priv->clkh) {
|
||||
/* HS400 with 4TAP needs different clock settings */
|
||||
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
|
||||
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
|
||||
bool need_slow_clkh = host->mmc->ios.timing == MMC_TIMING_MMC_HS400;
|
||||
clkh_shift = use_4tap && need_slow_clkh ? 1 : 2;
|
||||
ref_clk = priv->clkh;
|
||||
@ -383,7 +383,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0;
|
||||
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
|
||||
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
@ -395,7 +395,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF,
|
||||
priv->scc_tappos_hs400);
|
||||
|
||||
if (priv->quirks && priv->quirks->manual_tap_correction)
|
||||
if (sdhi_has_quirk(priv, manual_tap_correction))
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
|
||||
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
|
||||
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
|
||||
@ -546,7 +546,7 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
|
||||
SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) &
|
||||
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
|
||||
|
||||
if (priv->adjust_hs400_calib_table)
|
||||
if (sdhi_has_quirk(priv, hs400_calib_table) || sdhi_has_quirk(priv, hs400_bad_taps))
|
||||
renesas_sdhi_adjust_hs400_mode_disable(host);
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
|
||||
@ -732,7 +732,7 @@ static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
|
||||
|
||||
/* Change TAP position according to correction status */
|
||||
if (priv->quirks && priv->quirks->manual_tap_correction &&
|
||||
if (sdhi_has_quirk(priv, manual_tap_correction) &&
|
||||
host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
u32 bad_taps = priv->quirks ? priv->quirks->hs400_bad_taps : 0;
|
||||
/*
|
||||
@ -796,7 +796,7 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host,
|
||||
struct mmc_request *mrq)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
bool use_4tap = priv->quirks && priv->quirks->hs400_4taps;
|
||||
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
|
||||
bool ret = false;
|
||||
|
||||
/*
|
||||
@ -908,7 +908,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
{
|
||||
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *mmc_data;
|
||||
struct tmio_mmc_dma *dma_priv;
|
||||
struct renesas_sdhi_dma *dma_priv;
|
||||
struct tmio_mmc_host *host;
|
||||
struct renesas_sdhi *priv;
|
||||
int num_irqs, irq, ret, i;
|
||||
@ -990,7 +990,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
|
||||
host->dma_ops = dma_ops;
|
||||
|
||||
if (quirks && quirks->hs400_disabled)
|
||||
if (sdhi_has_quirk(priv, hs400_disabled))
|
||||
host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
|
||||
|
||||
/* For some SoC, we disable internal WP. GPIO may override this */
|
||||
@ -1018,7 +1018,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
dma_priv->filter = shdma_chan_filter;
|
||||
dma_priv->enable = renesas_sdhi_enable_dma;
|
||||
|
||||
mmc_data->alignment_shift = 1; /* 2-byte alignment */
|
||||
mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED;
|
||||
|
||||
/*
|
||||
@ -1056,7 +1055,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
if (ver == SDHI_VER_GEN2_SDR50)
|
||||
mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY;
|
||||
|
||||
if (ver == SDHI_VER_GEN3_SDMMC && quirks && quirks->hs400_calib_table) {
|
||||
if (ver == SDHI_VER_GEN3_SDMMC && sdhi_has_quirk(priv, hs400_calib_table)) {
|
||||
host->fixup_request = renesas_sdhi_fixup_request;
|
||||
priv->adjust_hs400_calib_table = *(
|
||||
res->start == SDHI_GEN3_MMC0_ADDR ?
|
||||
@ -1068,13 +1067,15 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
if (ver >= SDHI_VER_GEN3_SD)
|
||||
host->get_timeout_cycles = renesas_sdhi_gen3_get_cycles;
|
||||
|
||||
/* Check for SCC so we can reset it if needed */
|
||||
if (of_data && of_data->scc_offset && ver >= SDHI_VER_GEN2_SDR104)
|
||||
priv->scc_ctl = host->ctl + of_data->scc_offset;
|
||||
|
||||
/* Enable tuning iff we have an SCC and a supported mode */
|
||||
if (of_data && of_data->scc_offset &&
|
||||
(host->mmc->caps & MMC_CAP_UHS_SDR104 ||
|
||||
host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR |
|
||||
MMC_CAP2_HS400_1_8V))) {
|
||||
if (priv->scc_ctl && (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
|
||||
host->mmc->caps2 & MMC_CAP2_HSX00_1_8V)) {
|
||||
const struct renesas_sdhi_scc *taps = of_data->taps;
|
||||
bool use_4tap = quirks && quirks->hs400_4taps;
|
||||
bool use_4tap = sdhi_has_quirk(priv, hs400_4taps);
|
||||
bool hit = false;
|
||||
|
||||
for (i = 0; i < of_data->taps_num; i++) {
|
||||
@ -1092,7 +1093,6 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
if (!hit)
|
||||
dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n");
|
||||
|
||||
priv->scc_ctl = host->ctl + of_data->scc_offset;
|
||||
host->check_retune = renesas_sdhi_check_scc_error;
|
||||
host->ops.execute_tuning = renesas_sdhi_execute_tuning;
|
||||
host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning;
|
||||
|
@ -47,9 +47,9 @@
|
||||
#define RST_RESERVED_BITS GENMASK_ULL(31, 0)
|
||||
|
||||
/* DM_CM_INFO1 and DM_CM_INFO1_MASK */
|
||||
#define INFO1_CLEAR 0
|
||||
#define INFO1_MASK_CLEAR GENMASK_ULL(31, 0)
|
||||
#define INFO1_DTRANEND1 BIT(17)
|
||||
#define INFO1_DTRANEND1 BIT(20)
|
||||
#define INFO1_DTRANEND1_OLD BIT(17)
|
||||
#define INFO1_DTRANEND0 BIT(16)
|
||||
|
||||
/* DM_CM_INFO2 and DM_CM_INFO2_MASK */
|
||||
@ -165,6 +165,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400_one_rx = {
|
||||
.hs400_disabled = true,
|
||||
.hs400_4taps = true,
|
||||
.dma_one_rx_only = true,
|
||||
.old_info1_layout = true,
|
||||
};
|
||||
|
||||
static const struct renesas_sdhi_quirks sdhi_quirks_4tap = {
|
||||
@ -279,24 +280,18 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
|
||||
|
||||
static void
|
||||
renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host,
|
||||
int addr, u64 val)
|
||||
{
|
||||
writeq(val, host->ctl + addr);
|
||||
}
|
||||
|
||||
static void
|
||||
renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
u32 dma_irqs = INFO1_DTRANEND0 |
|
||||
(sdhi_has_quirk(priv, old_info1_layout) ?
|
||||
INFO1_DTRANEND1_OLD : INFO1_DTRANEND1);
|
||||
|
||||
if (!host->chan_tx || !host->chan_rx)
|
||||
return;
|
||||
|
||||
if (!enable)
|
||||
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1,
|
||||
INFO1_CLEAR);
|
||||
writel(enable ? ~dma_irqs : INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK);
|
||||
|
||||
if (priv->dma_priv.enable)
|
||||
priv->dma_priv.enable(host, enable);
|
||||
@ -309,22 +304,44 @@ renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host)
|
||||
|
||||
renesas_sdhi_internal_dmac_enable_dma(host, false);
|
||||
|
||||
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
|
||||
RST_RESERVED_BITS & ~val);
|
||||
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
|
||||
RST_RESERVED_BITS | val);
|
||||
writel(RST_RESERVED_BITS & ~val, host->ctl + DM_CM_RST);
|
||||
writel(RST_RESERVED_BITS | val, host->ctl + DM_CM_RST);
|
||||
|
||||
clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
|
||||
|
||||
renesas_sdhi_internal_dmac_enable_dma(host, true);
|
||||
}
|
||||
|
||||
static bool renesas_sdhi_internal_dmac_dma_irq(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
struct renesas_sdhi_dma *dma_priv = &priv->dma_priv;
|
||||
|
||||
u32 dma_irqs = INFO1_DTRANEND0 |
|
||||
(sdhi_has_quirk(priv, old_info1_layout) ?
|
||||
INFO1_DTRANEND1_OLD : INFO1_DTRANEND1);
|
||||
u32 status = readl(host->ctl + DM_CM_INFO1);
|
||||
|
||||
if (status & dma_irqs) {
|
||||
writel(status ^ dma_irqs, host->ctl + DM_CM_INFO1);
|
||||
set_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags);
|
||||
if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags))
|
||||
tasklet_schedule(&dma_priv->dma_complete);
|
||||
}
|
||||
|
||||
return status & dma_irqs;
|
||||
}
|
||||
|
||||
static void
|
||||
renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
struct renesas_sdhi_dma *dma_priv = &priv->dma_priv;
|
||||
|
||||
tasklet_schedule(&priv->dma_priv.dma_complete);
|
||||
set_bit(SDHI_DMA_END_FLAG_ACCESS, &dma_priv->end_flags);
|
||||
if (test_bit(SDHI_DMA_END_FLAG_DMA, &dma_priv->end_flags) ||
|
||||
host->data->error)
|
||||
tasklet_schedule(&dma_priv->dma_complete);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -379,7 +396,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
|
||||
struct scatterlist *sg = host->sg_ptr;
|
||||
u32 dtran_mode = DTRAN_MODE_BUS_WIDTH;
|
||||
|
||||
if (!(priv->quirks && priv->quirks->fixed_addr_mode))
|
||||
if (!sdhi_has_quirk(priv, fixed_addr_mode))
|
||||
dtran_mode |= DTRAN_MODE_ADDR_MODE;
|
||||
|
||||
if (!renesas_sdhi_internal_dmac_map(host, data, COOKIE_MAPPED))
|
||||
@ -387,20 +404,19 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
|
||||
|
||||
if (data->flags & MMC_DATA_READ) {
|
||||
dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
|
||||
if (priv->quirks && priv->quirks->dma_one_rx_only &&
|
||||
if (sdhi_has_quirk(priv, dma_one_rx_only) &&
|
||||
test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
|
||||
goto force_pio_with_unmap;
|
||||
} else {
|
||||
dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
|
||||
}
|
||||
|
||||
priv->dma_priv.end_flags = 0;
|
||||
renesas_sdhi_internal_dmac_enable_dma(host, true);
|
||||
|
||||
/* set dma parameters */
|
||||
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
|
||||
dtran_mode);
|
||||
renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
|
||||
sg_dma_address(sg));
|
||||
writel(dtran_mode, host->ctl + DM_CM_DTRAN_MODE);
|
||||
writel(sg_dma_address(sg), host->ctl + DM_DTRAN_ADDR);
|
||||
|
||||
host->dma_on = true;
|
||||
|
||||
@ -416,12 +432,19 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
|
||||
static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
|
||||
{
|
||||
struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
|
||||
tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
|
||||
|
||||
/* start the DMAC */
|
||||
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL,
|
||||
DTRAN_CTRL_DM_START);
|
||||
if (!host->cmd->error) {
|
||||
/* start the DMAC */
|
||||
writel(DTRAN_CTRL_DM_START, host->ctl + DM_CM_DTRAN_CTRL);
|
||||
} else {
|
||||
/* on CMD errors, simulate DMA end immediately */
|
||||
set_bit(SDHI_DMA_END_FLAG_DMA, &priv->dma_priv.end_flags);
|
||||
if (test_bit(SDHI_DMA_END_FLAG_ACCESS, &priv->dma_priv.end_flags))
|
||||
tasklet_schedule(&priv->dma_priv.dma_complete);
|
||||
}
|
||||
}
|
||||
|
||||
static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host)
|
||||
@ -501,11 +524,11 @@ renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
|
||||
/* Disable DMAC interrupts, we don't use them */
|
||||
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1_MASK,
|
||||
INFO1_MASK_CLEAR);
|
||||
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO2_MASK,
|
||||
INFO2_MASK_CLEAR);
|
||||
/* Disable DMAC interrupts initially */
|
||||
writel(INFO1_MASK_CLEAR, host->ctl + DM_CM_INFO1_MASK);
|
||||
writel(INFO2_MASK_CLEAR, host->ctl + DM_CM_INFO2_MASK);
|
||||
writel(0, host->ctl + DM_CM_INFO1);
|
||||
writel(0, host->ctl + DM_CM_INFO2);
|
||||
|
||||
/* Each value is set to non-zero to assume "enabling" each DMA */
|
||||
host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
|
||||
@ -537,6 +560,7 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
|
||||
.abort = renesas_sdhi_internal_dmac_abort_dma,
|
||||
.dataend = renesas_sdhi_internal_dmac_dataend_dma,
|
||||
.end = renesas_sdhi_internal_dmac_end_dma,
|
||||
.dma_irq = renesas_sdhi_internal_dmac_dma_irq,
|
||||
};
|
||||
|
||||
static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
|
||||
|
@ -160,7 +160,7 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
|
||||
dma_cookie_t cookie;
|
||||
int ret, i;
|
||||
bool aligned = true, multiple = true;
|
||||
unsigned int align = (1 << host->pdata->alignment_shift) - 1;
|
||||
unsigned int align = 1; /* 2-byte alignment */
|
||||
|
||||
for_each_sg(sg, sg_tmp, host->sg_len, i) {
|
||||
if (sg_tmp->offset & align)
|
||||
@ -232,7 +232,7 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
|
||||
dma_cookie_t cookie;
|
||||
int ret, i;
|
||||
bool aligned = true, multiple = true;
|
||||
unsigned int align = (1 << host->pdata->alignment_shift) - 1;
|
||||
unsigned int align = 1; /* 2-byte alignment */
|
||||
|
||||
for_each_sg(sg, sg_tmp, host->sg_len, i) {
|
||||
if (sg_tmp->offset & align)
|
||||
@ -254,12 +254,11 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
|
||||
|
||||
/* The only sg element can be unaligned, use our bounce buffer then */
|
||||
if (!aligned) {
|
||||
unsigned long flags;
|
||||
void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
|
||||
void *sg_vaddr = kmap_local_page(sg_page(sg));
|
||||
|
||||
sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
|
||||
memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
|
||||
tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
|
||||
memcpy(host->bounce_buf, sg_vaddr + sg->offset, host->bounce_sg.length);
|
||||
kunmap_local(sg_vaddr);
|
||||
host->sg_ptr = &host->bounce_sg;
|
||||
sg = host->sg_ptr;
|
||||
}
|
||||
|
@ -1474,6 +1474,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
|
||||
struct realtek_pci_sdmmc *host;
|
||||
struct rtsx_pcr *pcr;
|
||||
struct pcr_handle *handle = pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
if (!handle)
|
||||
return -ENXIO;
|
||||
@ -1511,7 +1512,13 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret) {
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
mmc_free_host(mmc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1329,6 +1329,7 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
|
||||
#ifdef RTSX_USB_USE_LEDS_CLASS
|
||||
int err;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent));
|
||||
if (!ucr)
|
||||
@ -1365,7 +1366,15 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
|
||||
INIT_WORK(&host->led_work, rtsx_usb_update_led);
|
||||
|
||||
#endif
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret) {
|
||||
#ifdef RTSX_USB_USE_LEDS_CLASS
|
||||
led_classdev_unregister(&host->led);
|
||||
#endif
|
||||
mmc_free_host(mmc);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -648,10 +648,10 @@ static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
|
||||
* in reading a garbage value and using the wrong presets.
|
||||
*
|
||||
* Since HS400 and HS200 presets must be identical, we could
|
||||
* instead use the the SDR104 preset register.
|
||||
* instead use the SDR104 preset register.
|
||||
*
|
||||
* If the above issues are resolved we could remove this quirk for
|
||||
* firmware that that has valid presets (i.e., SDR12 <= 12 MHz).
|
||||
* firmware that has valid presets (i.e., SDR12 <= 12 MHz).
|
||||
*/
|
||||
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
|
||||
|
||||
|
@ -168,7 +168,7 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
|
||||
/*
|
||||
* JEDEC and SD spec specify supplying 74 continuous clocks to
|
||||
* device after power up. With minimum bus (100KHz) that
|
||||
* that translates to 740us
|
||||
* translates to 740us
|
||||
*/
|
||||
if (power_mode != MMC_POWER_OFF)
|
||||
udelay(740);
|
||||
|
@ -179,7 +179,7 @@ static const struct brcmstb_match_priv match_priv_7216 = {
|
||||
.ops = &sdhci_brcmstb_ops_7216,
|
||||
};
|
||||
|
||||
static const struct of_device_id sdhci_brcm_of_match[] = {
|
||||
static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = {
|
||||
{ .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
|
||||
{ .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
|
||||
{ .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
|
||||
|
@ -307,7 +307,8 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = {
|
||||
| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
|
||||
};
|
||||
static struct esdhc_soc_data usdhc_imxrt1050_data = {
|
||||
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_HS200 | ESDHC_FLAG_ERR004536,
|
||||
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
|
||||
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
|
||||
};
|
||||
|
||||
static struct esdhc_soc_data usdhc_imx8qxp_data = {
|
||||
@ -1012,6 +1013,44 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
|
||||
SDHCI_HOST_CONTROL);
|
||||
}
|
||||
|
||||
static void esdhc_reset_tuning(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
|
||||
u32 ctrl;
|
||||
int ret;
|
||||
|
||||
/* Reset the tuning circuit */
|
||||
if (esdhc_is_usdhc(imx_data)) {
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
|
||||
ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
|
||||
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
|
||||
ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
|
||||
writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
|
||||
writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
|
||||
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
|
||||
ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
|
||||
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
|
||||
ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE;
|
||||
writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
|
||||
/* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */
|
||||
ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS,
|
||||
ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50);
|
||||
if (ret == -ETIMEDOUT)
|
||||
dev_warn(mmc_dev(host->mmc),
|
||||
"Warning! clear execute tuning bit failed\n");
|
||||
/*
|
||||
* SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the
|
||||
* usdhc IP internal logic flag execute_tuning_with_clr_buf, which
|
||||
* will finally make sure the normal data transfer logic correct.
|
||||
*/
|
||||
ctrl = readl(host->ioaddr + SDHCI_INT_STATUS);
|
||||
ctrl |= SDHCI_INT_DATA_AVAIL;
|
||||
writel(ctrl, host->ioaddr + SDHCI_INT_STATUS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
@ -1023,6 +1062,12 @@ static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
if (host->timing == MMC_TIMING_UHS_DDR50)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Reset tuning circuit logic. If not, the previous tuning result
|
||||
* will impact current tuning, make current tuning can't set the
|
||||
* correct delay cell.
|
||||
*/
|
||||
esdhc_reset_tuning(host);
|
||||
return sdhci_execute_tuning(mmc, opcode);
|
||||
}
|
||||
|
||||
@ -1196,44 +1241,6 @@ static void esdhc_set_strobe_dll(struct sdhci_host *host)
|
||||
"warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v);
|
||||
}
|
||||
|
||||
static void esdhc_reset_tuning(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
|
||||
u32 ctrl;
|
||||
int ret;
|
||||
|
||||
/* Reset the tuning circuit */
|
||||
if (esdhc_is_usdhc(imx_data)) {
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
|
||||
ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
|
||||
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
|
||||
ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
|
||||
writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
|
||||
writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
|
||||
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
|
||||
ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
|
||||
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
|
||||
ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE;
|
||||
writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
|
||||
/* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */
|
||||
ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS,
|
||||
ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50);
|
||||
if (ret == -ETIMEDOUT)
|
||||
dev_warn(mmc_dev(host->mmc),
|
||||
"Warning! clear execute tuning bit failed\n");
|
||||
/*
|
||||
* SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the
|
||||
* usdhc IP internal logic flag execute_tuning_with_clr_buf, which
|
||||
* will finally make sure the normal data transfer logic correct.
|
||||
*/
|
||||
ctrl = readl(host->ioaddr + SDHCI_INT_STATUS);
|
||||
ctrl |= SDHCI_INT_DATA_AVAIL;
|
||||
writel(ctrl, host->ioaddr + SDHCI_INT_STATUS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
|
||||
{
|
||||
u32 m;
|
||||
@ -1454,7 +1461,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
|
||||
|
||||
/*
|
||||
* On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card
|
||||
* as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the
|
||||
* as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let
|
||||
* the 1st linux configure power/clock for the 2nd Linux.
|
||||
*
|
||||
* When the 2nd Linux is booting into rootfs stage, we let the 1st Linux
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "cqhci.h"
|
||||
|
||||
@ -2218,8 +2219,7 @@ static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
|
||||
if (!msm_host->use_cdr)
|
||||
break;
|
||||
if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
|
||||
SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 &&
|
||||
SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK)
|
||||
!mmc_op_tuning(SDHCI_GET_CMD(val)))
|
||||
sdhci_msm_set_cdr(host, true);
|
||||
else
|
||||
sdhci_msm_set_cdr(host, false);
|
||||
@ -2304,13 +2304,6 @@ static void sdhci_msm_set_regulator_caps(struct sdhci_msm_host *msm_host)
|
||||
pr_debug("%s: supported caps: 0x%08x\n", mmc_hostname(mmc), caps);
|
||||
}
|
||||
|
||||
static void sdhci_msm_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL))
|
||||
cqhci_deactivate(host->mmc);
|
||||
sdhci_reset(host, mask);
|
||||
}
|
||||
|
||||
static int sdhci_msm_register_vreg(struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
int ret;
|
||||
@ -2450,7 +2443,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
|
||||
|
||||
static const struct sdhci_ops sdhci_msm_ops = {
|
||||
.reset = sdhci_msm_reset,
|
||||
.reset = sdhci_and_cqhci_reset,
|
||||
.set_clock = sdhci_msm_set_clock,
|
||||
.get_min_clock = sdhci_msm_get_min_clock,
|
||||
.get_max_clock = sdhci_msm_get_max_clock,
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
|
||||
@ -1522,6 +1523,65 @@ static int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_zynqmp_set_dynamic_config(struct device *dev,
|
||||
struct sdhci_arasan_data *sdhci_arasan)
|
||||
{
|
||||
struct sdhci_host *host = sdhci_arasan->host;
|
||||
struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw;
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
const char *clk_name = clk_hw_get_name(hw);
|
||||
u32 mhz, node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1;
|
||||
struct reset_control *rstc;
|
||||
int ret;
|
||||
|
||||
/* Obtain SDHC reset control */
|
||||
rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
|
||||
if (IS_ERR(rstc)) {
|
||||
dev_err(dev, "Cannot get SDHC reset.\n");
|
||||
return PTR_ERR(rstc);
|
||||
}
|
||||
|
||||
ret = reset_control_assert(rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_FIXED, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_EMMC_SEL,
|
||||
!!(host->mmc->caps & MMC_CAP_NONREMOVABLE));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mhz = DIV_ROUND_CLOSEST_ULL(clk_get_rate(pltfm_host->clk), 1000000);
|
||||
if (mhz > 100 && mhz <= 200)
|
||||
mhz = 200;
|
||||
else if (mhz > 50 && mhz <= 100)
|
||||
mhz = 100;
|
||||
else if (mhz > 25 && mhz <= 50)
|
||||
mhz = 50;
|
||||
else
|
||||
mhz = 25;
|
||||
|
||||
ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_BASECLK, mhz);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = zynqmp_pm_set_sd_config(node_id, SD_CONFIG_8BIT,
|
||||
!!(host->mmc->caps & MMC_CAP_8_BIT_DATA));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_control_deassert(rstc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usleep_range(1000, 1500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan)
|
||||
{
|
||||
struct sdhci_host *host = sdhci_arasan->host;
|
||||
@ -1686,6 +1746,15 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
|
||||
goto unreg_clk;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
|
||||
ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_SD_CONFIG);
|
||||
if (!ret) {
|
||||
ret = sdhci_zynqmp_set_dynamic_config(dev, sdhci_arasan);
|
||||
if (ret)
|
||||
goto unreg_clk;
|
||||
}
|
||||
}
|
||||
|
||||
sdhci_arasan->phy = ERR_PTR(-ENODEV);
|
||||
if (of_device_is_compatible(np, "arasan,sdhci-5.1")) {
|
||||
sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan");
|
||||
|
@ -42,6 +42,12 @@ static const struct esdhc_clk_fixup ls1021a_esdhc_clk = {
|
||||
.max_clk[MMC_TIMING_SD_HS] = 46500000,
|
||||
};
|
||||
|
||||
static const struct esdhc_clk_fixup ls1043a_esdhc_clk = {
|
||||
.sd_dflt_max_clk = 25000000,
|
||||
.max_clk[MMC_TIMING_UHS_SDR104] = 116700000,
|
||||
.max_clk[MMC_TIMING_MMC_HS200] = 116700000,
|
||||
};
|
||||
|
||||
static const struct esdhc_clk_fixup ls1046a_esdhc_clk = {
|
||||
.sd_dflt_max_clk = 25000000,
|
||||
.max_clk[MMC_TIMING_UHS_SDR104] = 167000000,
|
||||
@ -63,6 +69,7 @@ static const struct esdhc_clk_fixup p1010_esdhc_clk = {
|
||||
|
||||
static const struct of_device_id sdhci_esdhc_of_match[] = {
|
||||
{ .compatible = "fsl,ls1021a-esdhc", .data = &ls1021a_esdhc_clk},
|
||||
{ .compatible = "fsl,ls1043a-esdhc", .data = &ls1043a_esdhc_clk},
|
||||
{ .compatible = "fsl,ls1046a-esdhc", .data = &ls1046a_esdhc_clk},
|
||||
{ .compatible = "fsl,ls1012a-esdhc", .data = &ls1012a_esdhc_clk},
|
||||
{ .compatible = "fsl,p1010-esdhc", .data = &p1010_esdhc_clk},
|
||||
@ -91,7 +98,7 @@ struct sdhci_esdhc {
|
||||
};
|
||||
|
||||
/**
|
||||
* esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register
|
||||
* esdhc_readl_fixup - Fixup the value read from incompatible eSDHC register
|
||||
* to make it compatible with SD spec.
|
||||
*
|
||||
* @host: pointer to sdhci_host
|
||||
@ -216,7 +223,7 @@ static u8 esdhc_readb_fixup(struct sdhci_host *host,
|
||||
}
|
||||
|
||||
/**
|
||||
* esdhc_write*_fixup - Fixup the SD spec register value so that it could be
|
||||
* esdhc_writel_fixup - Fixup the SD spec register value so that it could be
|
||||
* written into eSDHC register.
|
||||
*
|
||||
* @host: pointer to sdhci_host
|
||||
|
@ -370,7 +370,7 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
|
||||
/*
|
||||
* Stage 1: Search for a maximum pass window ignoring any
|
||||
* any single point failures. If the tuning value ends up
|
||||
* single point failures. If the tuning value ends up
|
||||
* near it, move away from it in stage 2 below
|
||||
*/
|
||||
while (phase_delay <= MAX_PHASE_DELAY) {
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "cqhci.h"
|
||||
|
||||
#include "sdhci.h"
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pci.h"
|
||||
|
||||
static void sdhci_pci_hw_reset(struct sdhci_host *host);
|
||||
@ -234,14 +235,6 @@ static void sdhci_pci_dumpregs(struct mmc_host *mmc)
|
||||
sdhci_dumpregs(mmc_priv(mmc));
|
||||
}
|
||||
|
||||
static void sdhci_cqhci_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
|
||||
host->mmc->cqe_private)
|
||||
cqhci_deactivate(host->mmc);
|
||||
sdhci_reset(host, mask);
|
||||
}
|
||||
|
||||
/*****************************************************************************\
|
||||
* *
|
||||
* Hardware specific quirk handling *
|
||||
@ -703,7 +696,7 @@ static const struct sdhci_ops sdhci_intel_glk_ops = {
|
||||
.set_power = sdhci_intel_set_power,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_cqhci_reset,
|
||||
.reset = sdhci_and_cqhci_reset,
|
||||
.set_uhs_signaling = sdhci_intel_set_uhs_signaling,
|
||||
.hw_reset = sdhci_pci_hw_reset,
|
||||
.irq = sdhci_cqhci_irq,
|
||||
@ -2283,7 +2276,8 @@ static struct pci_driver sdhci_driver = {
|
||||
.probe = sdhci_pci_probe,
|
||||
.remove = sdhci_pci_remove,
|
||||
.driver = {
|
||||
.pm = &sdhci_pci_pm_ops
|
||||
.pm = &sdhci_pci_pm_ops,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include "sdhci.h"
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pci.h"
|
||||
#include "cqhci.h"
|
||||
|
||||
@ -922,14 +923,6 @@ static int gl9763e_add_host(struct sdhci_pci_slot *slot)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sdhci_gl9763e_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
|
||||
host->mmc->cqe_private)
|
||||
cqhci_deactivate(host->mmc);
|
||||
sdhci_reset(host, mask);
|
||||
}
|
||||
|
||||
static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
@ -1136,7 +1129,7 @@ static const struct sdhci_ops sdhci_gl9763e_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_gl9763e_reset,
|
||||
.reset = sdhci_and_cqhci_reset,
|
||||
.set_uhs_signaling = sdhci_set_gl9763e_signaling,
|
||||
.voltage_switch = sdhci_gli_voltage_switch,
|
||||
.irq = sdhci_gl9763e_cqhci_irq,
|
||||
|
@ -326,8 +326,7 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
(host->timing != MMC_TIMING_UHS_SDR50))
|
||||
return sdhci_execute_tuning(mmc, opcode);
|
||||
|
||||
if (WARN_ON((opcode != MMC_SEND_TUNING_BLOCK_HS200) &&
|
||||
(opcode != MMC_SEND_TUNING_BLOCK)))
|
||||
if (WARN_ON(!mmc_op_tuning(opcode)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Force power mode enter L0 */
|
||||
|
@ -228,13 +228,15 @@ static inline void _sdhci_sprd_set_clock(struct sdhci_host *host,
|
||||
div = ((div & 0x300) >> 2) | ((div & 0xFF) << 8);
|
||||
sdhci_enable_clk(host, div);
|
||||
|
||||
/* enable auto gate sdhc_enable_auto_gate */
|
||||
val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI);
|
||||
mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN |
|
||||
SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN;
|
||||
if (mask != (val & mask)) {
|
||||
val |= mask;
|
||||
sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);
|
||||
/* Enable CLK_AUTO when the clock is greater than 400K. */
|
||||
if (clk > 400000) {
|
||||
val = sdhci_readl(host, SDHCI_SPRD_REG_32_BUSY_POSI);
|
||||
mask = SDHCI_SPRD_BIT_OUTR_CLK_AUTO_EN |
|
||||
SDHCI_SPRD_BIT_INNR_CLK_AUTO_EN;
|
||||
if (mask != (val & mask)) {
|
||||
val |= mask;
|
||||
sdhci_writel(host, val, SDHCI_SPRD_REG_32_BUSY_POSI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,28 +3,30 @@
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <soc/tegra/common.h>
|
||||
|
||||
@ -95,6 +97,8 @@
|
||||
#define SDHCI_TEGRA_AUTO_CAL_STATUS 0x1ec
|
||||
#define SDHCI_TEGRA_AUTO_CAL_ACTIVE BIT(31)
|
||||
|
||||
#define SDHCI_TEGRA_CIF2AXI_CTRL_0 0x1fc
|
||||
|
||||
#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
|
||||
#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
|
||||
#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
|
||||
@ -122,6 +126,7 @@
|
||||
#define NVQUIRK_HAS_TMCLK BIT(10)
|
||||
|
||||
#define NVQUIRK_HAS_ANDROID_GPT_SECTOR BIT(11)
|
||||
#define NVQUIRK_PROGRAM_STREAMID BIT(12)
|
||||
|
||||
/* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */
|
||||
#define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000
|
||||
@ -178,6 +183,7 @@ struct sdhci_tegra {
|
||||
bool enable_hwcq;
|
||||
unsigned long curr_clk_rate;
|
||||
u8 tuned_tap_delay;
|
||||
u32 stream_id;
|
||||
};
|
||||
|
||||
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
|
||||
@ -268,13 +274,9 @@ static void tegra210_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
|
||||
{
|
||||
bool is_tuning_cmd = 0;
|
||||
bool clk_enabled;
|
||||
u8 cmd;
|
||||
|
||||
if (reg == SDHCI_COMMAND) {
|
||||
cmd = SDHCI_GET_CMD(val);
|
||||
is_tuning_cmd = cmd == MMC_SEND_TUNING_BLOCK ||
|
||||
cmd == MMC_SEND_TUNING_BLOCK_HS200;
|
||||
}
|
||||
if (reg == SDHCI_COMMAND)
|
||||
is_tuning_cmd = mmc_op_tuning(SDHCI_GET_CMD(val));
|
||||
|
||||
if (is_tuning_cmd)
|
||||
clk_enabled = tegra_sdhci_configure_card_clk(host, 0);
|
||||
@ -1526,7 +1528,8 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
|
||||
SDHCI_QUIRK_NO_HISPD_BIT |
|
||||
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
|
||||
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER,
|
||||
.ops = &tegra186_sdhci_ops,
|
||||
};
|
||||
|
||||
@ -1557,7 +1560,22 @@ static const struct sdhci_tegra_soc_data soc_data_tegra194 = {
|
||||
.max_tap_delay = 139,
|
||||
};
|
||||
|
||||
static const struct sdhci_tegra_soc_data soc_data_tegra234 = {
|
||||
.pdata = &sdhci_tegra186_pdata,
|
||||
.dma_mask = DMA_BIT_MASK(39),
|
||||
.nvquirks = NVQUIRK_NEEDS_PAD_CONTROL |
|
||||
NVQUIRK_HAS_PADCALIB |
|
||||
NVQUIRK_DIS_CARD_CLK_CONFIG_TAP |
|
||||
NVQUIRK_ENABLE_SDR50 |
|
||||
NVQUIRK_ENABLE_SDR104 |
|
||||
NVQUIRK_PROGRAM_STREAMID |
|
||||
NVQUIRK_HAS_TMCLK,
|
||||
.min_tap_delay = 95,
|
||||
.max_tap_delay = 111,
|
||||
};
|
||||
|
||||
static const struct of_device_id sdhci_tegra_dt_match[] = {
|
||||
{ .compatible = "nvidia,tegra234-sdhci", .data = &soc_data_tegra234 },
|
||||
{ .compatible = "nvidia,tegra194-sdhci", .data = &soc_data_tegra194 },
|
||||
{ .compatible = "nvidia,tegra186-sdhci", .data = &soc_data_tegra186 },
|
||||
{ .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 },
|
||||
@ -1617,6 +1635,19 @@ static int sdhci_tegra_add_host(struct sdhci_host *host)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Program MC streamID for DMA transfers */
|
||||
static void sdhci_tegra_program_stream_id(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
if (tegra_host->soc_data->nvquirks & NVQUIRK_PROGRAM_STREAMID) {
|
||||
tegra_sdhci_writel(host, FIELD_PREP(GENMASK(15, 8), tegra_host->stream_id) |
|
||||
FIELD_PREP(GENMASK(7, 0), tegra_host->stream_id),
|
||||
SDHCI_TEGRA_CIF2AXI_CTRL_0);
|
||||
}
|
||||
}
|
||||
|
||||
static int sdhci_tegra_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct sdhci_tegra_soc_data *soc_data;
|
||||
@ -1677,6 +1708,12 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
|
||||
|
||||
tegra_sdhci_parse_dt(host);
|
||||
|
||||
if (tegra_host->soc_data->nvquirks & NVQUIRK_PROGRAM_STREAMID &&
|
||||
!tegra_dev_iommu_get_stream_id(&pdev->dev, &tegra_host->stream_id)) {
|
||||
dev_warn(mmc_dev(host->mmc), "missing IOMMU stream ID\n");
|
||||
tegra_host->stream_id = 0x7f;
|
||||
}
|
||||
|
||||
tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(tegra_host->power_gpio)) {
|
||||
@ -1762,6 +1799,8 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
|
||||
if (rc)
|
||||
goto err_add_host;
|
||||
|
||||
sdhci_tegra_program_stream_id(host);
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_host:
|
||||
@ -1858,6 +1897,8 @@ static int sdhci_tegra_resume(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sdhci_tegra_program_stream_id(host);
|
||||
|
||||
ret = sdhci_resume_host(host);
|
||||
if (ret)
|
||||
goto disable_clk;
|
||||
|
@ -270,6 +270,11 @@ enum sdhci_reset_reason {
|
||||
|
||||
static void sdhci_reset_for_reason(struct sdhci_host *host, enum sdhci_reset_reason reason)
|
||||
{
|
||||
if (host->quirks2 & SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER) {
|
||||
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (reason) {
|
||||
case SDHCI_RESET_FOR_INIT:
|
||||
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||
@ -526,7 +531,6 @@ static inline bool sdhci_has_requests(struct sdhci_host *host)
|
||||
|
||||
static void sdhci_read_block_pio(struct sdhci_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
size_t blksize, len, chunk;
|
||||
u32 scratch;
|
||||
u8 *buf;
|
||||
@ -536,8 +540,6 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
|
||||
blksize = host->data->blksz;
|
||||
chunk = 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
while (blksize) {
|
||||
BUG_ON(!sg_miter_next(&host->sg_miter));
|
||||
|
||||
@ -564,13 +566,10 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
|
||||
}
|
||||
|
||||
sg_miter_stop(&host->sg_miter);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void sdhci_write_block_pio(struct sdhci_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
size_t blksize, len, chunk;
|
||||
u32 scratch;
|
||||
u8 *buf;
|
||||
@ -581,8 +580,6 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
|
||||
chunk = 0;
|
||||
scratch = 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
while (blksize) {
|
||||
BUG_ON(!sg_miter_next(&host->sg_miter));
|
||||
|
||||
@ -609,8 +606,6 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
|
||||
}
|
||||
|
||||
sg_miter_stop(&host->sg_miter);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void sdhci_transfer_pio(struct sdhci_host *host)
|
||||
@ -706,16 +701,14 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
|
||||
return sg_count;
|
||||
}
|
||||
|
||||
static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
|
||||
static char *sdhci_kmap_atomic(struct scatterlist *sg)
|
||||
{
|
||||
local_irq_save(*flags);
|
||||
return kmap_atomic(sg_page(sg)) + sg->offset;
|
||||
return kmap_local_page(sg_page(sg)) + sg->offset;
|
||||
}
|
||||
|
||||
static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
|
||||
static void sdhci_kunmap_atomic(void *buffer)
|
||||
{
|
||||
kunmap_atomic(buffer);
|
||||
local_irq_restore(*flags);
|
||||
kunmap_local(buffer);
|
||||
}
|
||||
|
||||
void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
|
||||
@ -757,7 +750,6 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
|
||||
struct mmc_data *data, int sg_count)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
unsigned long flags;
|
||||
dma_addr_t addr, align_addr;
|
||||
void *desc, *align;
|
||||
char *buffer;
|
||||
@ -789,9 +781,9 @@ static void sdhci_adma_table_pre(struct sdhci_host *host,
|
||||
SDHCI_ADMA2_MASK;
|
||||
if (offset) {
|
||||
if (data->flags & MMC_DATA_WRITE) {
|
||||
buffer = sdhci_kmap_atomic(sg, &flags);
|
||||
buffer = sdhci_kmap_atomic(sg);
|
||||
memcpy(align, buffer, offset);
|
||||
sdhci_kunmap_atomic(buffer, &flags);
|
||||
sdhci_kunmap_atomic(buffer);
|
||||
}
|
||||
|
||||
/* tran, valid */
|
||||
@ -852,7 +844,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
|
||||
int i, size;
|
||||
void *align;
|
||||
char *buffer;
|
||||
unsigned long flags;
|
||||
|
||||
if (data->flags & MMC_DATA_READ) {
|
||||
bool has_unaligned = false;
|
||||
@ -875,9 +866,9 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
|
||||
size = SDHCI_ADMA2_ALIGN -
|
||||
(sg_dma_address(sg) & SDHCI_ADMA2_MASK);
|
||||
|
||||
buffer = sdhci_kmap_atomic(sg, &flags);
|
||||
buffer = sdhci_kmap_atomic(sg);
|
||||
memcpy(buffer, align, size);
|
||||
sdhci_kunmap_atomic(buffer, &flags);
|
||||
sdhci_kunmap_atomic(buffer);
|
||||
|
||||
align += SDHCI_ADMA2_ALIGN;
|
||||
}
|
||||
@ -1466,7 +1457,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
|
||||
if (host->quirks2 &
|
||||
SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
|
||||
/* must not clear SDHCI_TRANSFER_MODE when tuning */
|
||||
if (cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)
|
||||
if (!mmc_op_tuning(cmd->opcode))
|
||||
sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
|
||||
} else {
|
||||
/* clear Auto CMD settings for no data CMDs */
|
||||
@ -1707,8 +1698,7 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
|
||||
flags |= SDHCI_CMD_INDEX;
|
||||
|
||||
/* CMD19 is special in that the Data Present Select should be set */
|
||||
if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
|
||||
cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
|
||||
if (cmd->data || mmc_op_tuning(cmd->opcode))
|
||||
flags |= SDHCI_CMD_DATA;
|
||||
|
||||
timeout = jiffies;
|
||||
@ -2304,7 +2294,7 @@ static bool sdhci_timing_has_preset(unsigned char timing)
|
||||
case MMC_TIMING_UHS_DDR50:
|
||||
case MMC_TIMING_MMC_DDR52:
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2418,8 +2408,21 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
if (host->version >= SDHCI_SPEC_300) {
|
||||
u16 clk, ctrl_2;
|
||||
|
||||
/*
|
||||
* According to SDHCI Spec v3.00, if the Preset Value
|
||||
* Enable in the Host Control 2 register is set, we
|
||||
* need to reset SD Clock Enable before changing High
|
||||
* Speed Enable to avoid generating clock glitches.
|
||||
*/
|
||||
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||
if (clk & SDHCI_CLOCK_CARD_EN) {
|
||||
clk &= ~SDHCI_CLOCK_CARD_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
}
|
||||
|
||||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
|
||||
if (!host->preset_enabled) {
|
||||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
/*
|
||||
* We only need to set Driver Strength if the
|
||||
* preset value enable is not set.
|
||||
@ -2442,30 +2445,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
|
||||
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
||||
host->drv_type = ios->drv_type;
|
||||
} else {
|
||||
/*
|
||||
* According to SDHC Spec v3.00, if the Preset Value
|
||||
* Enable in the Host Control 2 register is set, we
|
||||
* need to reset SD Clock Enable before changing High
|
||||
* Speed Enable to avoid generating clock gliches.
|
||||
*/
|
||||
|
||||
/* Reset SD Clock Enable */
|
||||
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||
clk &= ~SDHCI_CLOCK_CARD_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
|
||||
/* Re-enable SD Clock */
|
||||
host->ops->set_clock(host, host->clock);
|
||||
}
|
||||
|
||||
/* Reset SD Clock Enable */
|
||||
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||
clk &= ~SDHCI_CLOCK_CARD_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
host->ops->set_uhs_signaling(host, ios->timing);
|
||||
host->timing = ios->timing;
|
||||
|
||||
@ -3388,8 +3369,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
|
||||
|
||||
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
|
||||
{
|
||||
u32 command;
|
||||
|
||||
/*
|
||||
* CMD19 generates _only_ Buffer Read Ready interrupt if
|
||||
* use sdhci_send_tuning.
|
||||
@ -3398,9 +3377,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
|
||||
* SDHCI_INT_DATA_AVAIL always there, stuck in irq storm.
|
||||
*/
|
||||
if (intmask & SDHCI_INT_DATA_AVAIL && !host->data) {
|
||||
command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
|
||||
if (command == MMC_SEND_TUNING_BLOCK ||
|
||||
command == MMC_SEND_TUNING_BLOCK_HS200) {
|
||||
if (mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) {
|
||||
host->tuning_done = 1;
|
||||
wake_up(&host->buf_ready_int);
|
||||
return;
|
||||
|
@ -345,7 +345,7 @@ struct sdhci_adma2_64_desc {
|
||||
*/
|
||||
#define SDHCI_MAX_SEGS 128
|
||||
|
||||
/* Allow for a a command request and a data request at the same time */
|
||||
/* Allow for a command request and a data request at the same time */
|
||||
#define SDHCI_MAX_MRQS 2
|
||||
|
||||
/*
|
||||
@ -478,6 +478,8 @@ struct sdhci_host {
|
||||
* block count.
|
||||
*/
|
||||
#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18)
|
||||
/* Issue CMD and DATA reset together */
|
||||
#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19)
|
||||
|
||||
int irq; /* Device IRQ */
|
||||
void __iomem *ioaddr; /* Mapped address */
|
||||
|
@ -836,7 +836,7 @@ static int sdhci_am654_probe(struct platform_device *pdev)
|
||||
|
||||
ret = mmc_of_parse(host->mmc);
|
||||
if (ret) {
|
||||
dev_err(dev, "parsing dt failed (%d)\n", ret);
|
||||
dev_err_probe(dev, ret, "parsing dt failed\n");
|
||||
goto pm_runtime_put;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
|
||||
* Vincent Yang <vincent.yang@tw.fujitsu.com>
|
||||
* Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@linaro.org>
|
||||
* Copyright (C) 2019 Socionext Inc.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
@ -14,6 +15,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "sdhci_f_sdh30.h"
|
||||
@ -21,6 +23,7 @@
|
||||
struct f_sdhost_priv {
|
||||
struct clk *clk_iface;
|
||||
struct clk *clk;
|
||||
struct reset_control *rst;
|
||||
u32 vendor_hs200;
|
||||
struct device *dev;
|
||||
bool enable_cmd_dat_delay;
|
||||
@ -74,6 +77,13 @@ static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
|
||||
ctl |= F_SDH30_CMD_DAT_DELAY;
|
||||
sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
|
||||
}
|
||||
|
||||
if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) &&
|
||||
!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
|
||||
ctl = sdhci_readl(host, F_SDH30_TEST);
|
||||
ctl |= F_SDH30_FORCE_CARD_INSERT;
|
||||
sdhci_writel(host, ctl, F_SDH30_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_f_sdh30_ops = {
|
||||
@ -150,6 +160,16 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
priv->rst = devm_reset_control_get_optional_shared(dev, NULL);
|
||||
if (IS_ERR(priv->rst)) {
|
||||
ret = PTR_ERR(priv->rst);
|
||||
goto err_rst;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(priv->rst);
|
||||
if (ret)
|
||||
goto err_rst;
|
||||
}
|
||||
|
||||
/* init vendor specific regs */
|
||||
@ -168,6 +188,9 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
|
||||
if (reg & SDHCI_CAN_DO_8BIT)
|
||||
priv->vendor_hs200 = F_SDH30_EMMC_HS200;
|
||||
|
||||
if (!(reg & SDHCI_TIMEOUT_CLK_MASK))
|
||||
host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
|
||||
|
||||
ret = sdhci_add_host(host);
|
||||
if (ret)
|
||||
goto err_add_host;
|
||||
@ -175,6 +198,8 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_add_host:
|
||||
reset_control_assert(priv->rst);
|
||||
err_rst:
|
||||
clk_disable_unprepare(priv->clk);
|
||||
err_clk:
|
||||
clk_disable_unprepare(priv->clk_iface);
|
||||
@ -191,8 +216,9 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev)
|
||||
sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
|
||||
0xffffffff);
|
||||
|
||||
clk_disable_unprepare(priv->clk_iface);
|
||||
reset_control_assert(priv->rst);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
clk_disable_unprepare(priv->clk_iface);
|
||||
|
||||
sdhci_free_host(host);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
@ -203,6 +229,7 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id f_sdh30_dt_ids[] = {
|
||||
{ .compatible = "fujitsu,mb86s70-sdhci-3.0" },
|
||||
{ .compatible = "socionext,f-sdh30-e51-mmc" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids);
|
||||
@ -232,5 +259,5 @@ module_platform_driver(sdhci_f_sdh30_driver);
|
||||
|
||||
MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD.");
|
||||
MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD., Socionext Inc.");
|
||||
MODULE_ALIAS("platform:f_sdh30");
|
||||
|
@ -29,4 +29,7 @@
|
||||
#define F_SDH30_CMD_DAT_DELAY BIT(9)
|
||||
#define F_SDH30_EMMC_HS200 BIT(24)
|
||||
|
||||
#define F_SDH30_TEST 0x158
|
||||
#define F_SDH30_FORCE_CARD_INSERT BIT(6)
|
||||
|
||||
#define F_SDH30_MIN_CLOCK 400000
|
||||
|
1000
drivers/mmc/host/sunplus-mmc.c
Normal file
1000
drivers/mmc/host/sunplus-mmc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -116,7 +116,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
|
||||
unsigned char *buf;
|
||||
unsigned int pos = 0, val;
|
||||
|
||||
buf = kmap_atomic(pg) + off;
|
||||
buf = kmap_local_page(pg) + off;
|
||||
if (host->cmd_flags & DATA_CARRY) {
|
||||
buf[pos++] = host->bounce_buf_data[0];
|
||||
host->cmd_flags &= ~DATA_CARRY;
|
||||
@ -132,7 +132,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
|
||||
}
|
||||
buf[pos++] = (val >> 8) & 0xff;
|
||||
}
|
||||
kunmap_atomic(buf - off);
|
||||
kunmap_local(buf - off);
|
||||
}
|
||||
|
||||
static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
|
||||
@ -142,7 +142,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
|
||||
unsigned char *buf;
|
||||
unsigned int pos = 0, val;
|
||||
|
||||
buf = kmap_atomic(pg) + off;
|
||||
buf = kmap_local_page(pg) + off;
|
||||
if (host->cmd_flags & DATA_CARRY) {
|
||||
val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
|
||||
writel(val, sock->addr + SOCK_MMCSD_DATA);
|
||||
@ -159,7 +159,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
|
||||
val |= (buf[pos++] << 8) & 0xff00;
|
||||
writel(val, sock->addr + SOCK_MMCSD_DATA);
|
||||
}
|
||||
kunmap_atomic(buf - off);
|
||||
kunmap_local(buf - off);
|
||||
}
|
||||
|
||||
static void tifm_sd_transfer_data(struct tifm_sd *host)
|
||||
@ -210,13 +210,13 @@ static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
|
||||
struct page *src, unsigned int src_off,
|
||||
unsigned int count)
|
||||
{
|
||||
unsigned char *src_buf = kmap_atomic(src) + src_off;
|
||||
unsigned char *dst_buf = kmap_atomic(dst) + dst_off;
|
||||
unsigned char *src_buf = kmap_local_page(src) + src_off;
|
||||
unsigned char *dst_buf = kmap_local_page(dst) + dst_off;
|
||||
|
||||
memcpy(dst_buf, src_buf, count);
|
||||
|
||||
kunmap_atomic(dst_buf - dst_off);
|
||||
kunmap_atomic(src_buf - src_off);
|
||||
kunmap_local(dst_buf - dst_off);
|
||||
kunmap_local(src_buf - src_off);
|
||||
}
|
||||
|
||||
static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
|
||||
@ -264,16 +264,13 @@ static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
|
||||
unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz;
|
||||
unsigned int dma_len, dma_blk_cnt, dma_off;
|
||||
struct scatterlist *sg = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
if (host->sg_pos == host->sg_len)
|
||||
return 1;
|
||||
|
||||
if (host->cmd_flags & DATA_CARRY) {
|
||||
host->cmd_flags &= ~DATA_CARRY;
|
||||
local_irq_save(flags);
|
||||
tifm_sd_bounce_block(host, r_data);
|
||||
local_irq_restore(flags);
|
||||
if (host->sg_pos == host->sg_len)
|
||||
return 1;
|
||||
}
|
||||
@ -300,11 +297,9 @@ static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
|
||||
if (dma_blk_cnt)
|
||||
sg = &r_data->sg[host->sg_pos];
|
||||
else if (dma_len) {
|
||||
if (r_data->flags & MMC_DATA_WRITE) {
|
||||
local_irq_save(flags);
|
||||
if (r_data->flags & MMC_DATA_WRITE)
|
||||
tifm_sd_bounce_block(host, r_data);
|
||||
local_irq_restore(flags);
|
||||
} else
|
||||
else
|
||||
host->cmd_flags |= DATA_CARRY;
|
||||
|
||||
sg = &host->bounce_buf;
|
||||
@ -506,7 +501,6 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
|
||||
unsigned int host_status = 0;
|
||||
int cmd_error = 0;
|
||||
struct mmc_command *cmd = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&sock->lock);
|
||||
host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
|
||||
@ -570,9 +564,7 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
|
||||
|
||||
if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
|
||||
| TIFM_MMCSD_BRS)) {
|
||||
local_irq_save(flags);
|
||||
tifm_sd_transfer_data(host);
|
||||
local_irq_restore(flags);
|
||||
host_status &= ~TIFM_MMCSD_AE;
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ struct tmio_mmc_dma_ops {
|
||||
|
||||
/* optional */
|
||||
void (*end)(struct tmio_mmc_host *host); /* held host->lock */
|
||||
bool (*dma_irq)(struct tmio_mmc_host *host);
|
||||
};
|
||||
|
||||
struct tmio_mmc_host {
|
||||
@ -204,20 +205,6 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
|
||||
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
|
||||
irqreturn_t tmio_mmc_irq(int irq, void *devid);
|
||||
|
||||
static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
|
||||
unsigned long *flags)
|
||||
{
|
||||
local_irq_save(*flags);
|
||||
return kmap_atomic(sg_page(sg)) + sg->offset;
|
||||
}
|
||||
|
||||
static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
|
||||
unsigned long *flags, void *virt)
|
||||
{
|
||||
kunmap_atomic(virt - sg->offset);
|
||||
local_irq_restore(*flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int tmio_mmc_host_runtime_suspend(struct device *dev);
|
||||
int tmio_mmc_host_runtime_resume(struct device *dev);
|
||||
|
@ -412,7 +412,6 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
|
||||
void *sg_virt;
|
||||
unsigned short *buf;
|
||||
unsigned int count;
|
||||
unsigned long flags;
|
||||
|
||||
if (host->dma_on) {
|
||||
pr_err("PIO IRQ in DMA mode!\n");
|
||||
@ -422,8 +421,8 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
|
||||
return;
|
||||
}
|
||||
|
||||
sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags);
|
||||
buf = (unsigned short *)(sg_virt + host->sg_off);
|
||||
sg_virt = kmap_local_page(sg_page(host->sg_ptr));
|
||||
buf = (unsigned short *)(sg_virt + host->sg_ptr->offset + host->sg_off);
|
||||
|
||||
count = host->sg_ptr->length - host->sg_off;
|
||||
if (count > data->blksz)
|
||||
@ -437,7 +436,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
|
||||
|
||||
host->sg_off += count;
|
||||
|
||||
tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt);
|
||||
kunmap_local(sg_virt);
|
||||
|
||||
if (host->sg_off == host->sg_ptr->length)
|
||||
tmio_mmc_next_sg(host);
|
||||
@ -446,11 +445,11 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
|
||||
static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host)
|
||||
{
|
||||
if (host->sg_ptr == &host->bounce_sg) {
|
||||
unsigned long flags;
|
||||
void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags);
|
||||
void *sg_virt = kmap_local_page(sg_page(host->sg_orig));
|
||||
|
||||
memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
|
||||
tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr);
|
||||
memcpy(sg_virt + host->sg_orig->offset, host->bounce_buf,
|
||||
host->bounce_sg.length);
|
||||
kunmap_local(sg_virt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -670,6 +669,9 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (host->dma_ops && host->dma_ops->dma_irq && host->dma_ops->dma_irq(host))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -651,7 +651,9 @@ static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
if (ret)
|
||||
goto unmap;
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto free_irq;
|
||||
|
||||
base = pci_resource_start(pdev, 0);
|
||||
dev_dbg(&pdev->dev, "MMIO %pa, IRQ %d\n", &base, pdev->irq);
|
||||
@ -660,6 +662,8 @@ static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
return 0;
|
||||
|
||||
free_irq:
|
||||
free_irq(pdev->irq, host);
|
||||
unmap:
|
||||
pci_iounmap(pdev, host->ioaddr);
|
||||
release:
|
||||
|
@ -1151,7 +1151,9 @@ static int via_sd_probe(struct pci_dev *pcidev,
|
||||
pcidev->subsystem_device == 0x3891)
|
||||
sdhost->quirks = VIA_CRDR_QUIRK_300MS_PWRDELAY;
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto unmap;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -2049,6 +2049,7 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||
return;
|
||||
kref_get(&vub300->kref);
|
||||
if (enable) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
mutex_lock(&vub300->irq_mutex);
|
||||
if (vub300->irqs_queued) {
|
||||
vub300->irqs_queued -= 1;
|
||||
@ -2064,6 +2065,7 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||
vub300_queue_poll_work(vub300, 0);
|
||||
}
|
||||
mutex_unlock(&vub300->irq_mutex);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
} else {
|
||||
vub300->irq_enabled = 0;
|
||||
}
|
||||
@ -2299,14 +2301,14 @@ static int vub300_probe(struct usb_interface *interface,
|
||||
0x0000, 0x0000, &vub300->system_port_status,
|
||||
sizeof(vub300->system_port_status), 1000);
|
||||
if (retval < 0) {
|
||||
goto error4;
|
||||
goto error5;
|
||||
} else if (sizeof(vub300->system_port_status) == retval) {
|
||||
vub300->card_present =
|
||||
(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
|
||||
vub300->read_only =
|
||||
(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
|
||||
} else {
|
||||
goto error4;
|
||||
goto error5;
|
||||
}
|
||||
usb_set_intfdata(interface, vub300);
|
||||
INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
|
||||
@ -2329,8 +2331,13 @@ static int vub300_probe(struct usb_interface *interface,
|
||||
"USB vub300 remote SDIO host controller[%d]"
|
||||
"connected with no SD/SDIO card inserted\n",
|
||||
interface_to_InterfaceNumber(interface));
|
||||
mmc_add_host(mmc);
|
||||
retval = mmc_add_host(mmc);
|
||||
if (retval)
|
||||
goto error6;
|
||||
|
||||
return 0;
|
||||
error6:
|
||||
del_timer_sync(&vub300->inactivity_timer);
|
||||
error5:
|
||||
mmc_free_host(mmc);
|
||||
/*
|
||||
|
@ -267,7 +267,7 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
|
||||
|
||||
static inline char *wbsd_map_sg(struct wbsd_host *host)
|
||||
{
|
||||
return kmap_atomic(sg_page(host->cur_sg)) + host->cur_sg->offset;
|
||||
return kmap_local_page(sg_page(host->cur_sg)) + host->cur_sg->offset;
|
||||
}
|
||||
|
||||
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
|
||||
@ -439,7 +439,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
|
||||
* End of scatter list entry?
|
||||
*/
|
||||
if (host->remain == 0) {
|
||||
kunmap_atomic(buffer);
|
||||
kunmap_local(buffer);
|
||||
/*
|
||||
* Get next entry. Check if last.
|
||||
*/
|
||||
@ -451,7 +451,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
|
||||
}
|
||||
}
|
||||
}
|
||||
kunmap_atomic(buffer);
|
||||
kunmap_local(buffer);
|
||||
|
||||
/*
|
||||
* This is a very dirty hack to solve a
|
||||
@ -505,7 +505,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
|
||||
* End of scatter list entry?
|
||||
*/
|
||||
if (host->remain == 0) {
|
||||
kunmap_atomic(buffer);
|
||||
kunmap_local(buffer);
|
||||
/*
|
||||
* Get next entry. Check if last.
|
||||
*/
|
||||
@ -517,7 +517,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
|
||||
}
|
||||
}
|
||||
}
|
||||
kunmap_atomic(buffer);
|
||||
kunmap_local(buffer);
|
||||
|
||||
/*
|
||||
* The controller stops sending interrupts for
|
||||
@ -1698,7 +1698,17 @@ static int wbsd_init(struct device *dev, int base, int irq, int dma,
|
||||
*/
|
||||
wbsd_init_device(host);
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret) {
|
||||
if (!pnp)
|
||||
wbsd_chip_poweroff(host);
|
||||
|
||||
wbsd_release_resources(host);
|
||||
wbsd_free_mmc(dev);
|
||||
|
||||
mmc_free_host(mmc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_info("%s: W83L51xD", mmc_hostname(mmc));
|
||||
if (host->chip_id != 0)
|
||||
|
@ -856,11 +856,15 @@ static int wmt_mci_probe(struct platform_device *pdev)
|
||||
/* configure the controller to a known 'ready' state */
|
||||
wmt_reset_hardware(mmc);
|
||||
|
||||
mmc_add_host(mmc);
|
||||
ret = mmc_add_host(mmc);
|
||||
if (ret)
|
||||
goto fail7;
|
||||
|
||||
dev_info(&pdev->dev, "WMT SDHC Controller initialized\n");
|
||||
|
||||
return 0;
|
||||
fail7:
|
||||
clk_disable_unprepare(priv->clk_sdmmc);
|
||||
fail6:
|
||||
clk_put(priv->clk_sdmmc);
|
||||
fail5_and_a_half:
|
||||
|
@ -605,6 +605,10 @@ struct iommu_group *fsl_mc_device_group(struct device *dev);
|
||||
* @flags: IOMMU_FWSPEC_* flags
|
||||
* @num_ids: number of associated device IDs
|
||||
* @ids: IDs which this device may present to the IOMMU
|
||||
*
|
||||
* Note that the IDs (and any other information, really) stored in this structure should be
|
||||
* considered private to the IOMMU device driver and are not to be used directly by IOMMU
|
||||
* consumers.
|
||||
*/
|
||||
struct iommu_fwspec {
|
||||
const struct iommu_ops *ops;
|
||||
@ -1099,4 +1103,25 @@ static inline void iommu_dma_compose_msi_msg(struct msi_desc *desc, struct msi_m
|
||||
|
||||
#endif /* CONFIG_IOMMU_DMA */
|
||||
|
||||
/*
|
||||
* Newer generations of Tegra SoCs require devices' stream IDs to be directly programmed into
|
||||
* some registers. These are always paired with a Tegra SMMU or ARM SMMU, for which the contents
|
||||
* of the struct iommu_fwspec are known. Use this helper to formalize access to these internals.
|
||||
*/
|
||||
#define TEGRA_STREAM_ID_BYPASS 0x7f
|
||||
|
||||
static inline bool tegra_dev_iommu_get_stream_id(struct device *dev, u32 *stream_id)
|
||||
{
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
|
||||
|
||||
if (fwspec && fwspec->num_ids == 1) {
|
||||
*stream_id = fwspec->ids[0] & 0xffff;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* __LINUX_IOMMU_H */
|
||||
|
@ -102,7 +102,6 @@ struct tmio_mmc_data {
|
||||
unsigned long capabilities2;
|
||||
unsigned long flags;
|
||||
u32 ocr_mask; /* available voltages */
|
||||
int alignment_shift;
|
||||
dma_addr_t dma_rx_offset;
|
||||
unsigned int max_blk_count;
|
||||
unsigned short max_segs;
|
||||
|
Loading…
Reference in New Issue
Block a user