Merge tag 'mmc-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson: "MMC host: - atmel-mci: Convert DT bindings to json schema - dw_mmc: Add support for the Exynos7870 variant - dw_mmc-rockchip: Add support for the RK3562/3528 variants - omap: Fix potential memory leak in the probe error path - renesas_sdhi: Add support for RZ/G3E variants - sdhci: Disable SD card clock before changing parameters - sdhci-esdhc-imx: Add support for the i.MX94 variant - sdhci-of-dwcmshc: Add support for the RK3562/RK3528 variants - sdhci-omap: Disable aggressive PM for eMMC/SD-cards - sdhci-pci-core: Wait for VDD to settle on card power off - sdhci-pxav3: Fix busy-signalling by using MMC_CAP_NEED_RSP_BUSY - sunxi-mmc: Add support for the A523 variant MEMSTICK: - rtsx_usb_ms: Fix potential use-after-free during remove" * tag 'mmc-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (27 commits) mmc: core: Remove redundant null check mmc: host: Wait for Vdd to settle on card power off mmc: omap: Fix memory leak in mmc_omap_new_slot memstick: rtsx_usb_ms: Fix slab-use-after-free in rtsx_usb_ms_drv_remove mmc: renesas_sdhi: fix error code in renesas_sdhi_probe() mmc: sdhci-pxav3: set NEED_RSP_BUSY capability mmc: sdhci-omap: Disable MMC_CAP_AGGRESSIVE_PM for eMMC/SD tty: mmc: sdio: use bool for cts and remove parentheses dt-bindings: mmc: sunxi: add compatible strings for Allwinner A523 dt-bindings: mmc: sunxi: Simplify compatible string listing dt-bindings: mmc: sdhci-of-dwcmhsc: Add compatible string for RK3528 dt-bindings: mmc: rockchip-dw-mshc: Add compatible string for RK3528 mmc: renesas_sdhi: Add support for RZ/G3E SoC dt-bindings: mmc: renesas,sdhi: Document RZ/G3E support dt-bindings: mmc: rockchip-dw-mshc: Add support for rk3562 dt-bindings: mmc: Add support for rk3562 eMMC mmc: core: Trim trailing whitespace from card product names dt-bindings: mmc: atmel,hsmci: Convert to json schema dt-bindings: mmc: mmc-slot: Make compatible property optional dt-bindings: mmc: fsl-imx-esdhc: Add i.MX94 support ...
This commit is contained in:
@@ -30,38 +30,34 @@ properties:
|
||||
- const: allwinner,sun50i-a100-emmc
|
||||
- const: allwinner,sun50i-a100-mmc
|
||||
- items:
|
||||
- const: allwinner,sun8i-a83t-mmc
|
||||
- enum:
|
||||
- allwinner,sun8i-a83t-mmc
|
||||
- allwinner,suniv-f1c100s-mmc
|
||||
- const: allwinner,sun7i-a20-mmc
|
||||
- items:
|
||||
- const: allwinner,sun8i-r40-emmc
|
||||
- enum:
|
||||
- allwinner,sun8i-r40-emmc
|
||||
- allwinner,sun50i-h5-emmc
|
||||
- allwinner,sun50i-h6-emmc
|
||||
- const: allwinner,sun50i-a64-emmc
|
||||
- items:
|
||||
- const: allwinner,sun8i-r40-mmc
|
||||
- enum:
|
||||
- allwinner,sun8i-r40-mmc
|
||||
- allwinner,sun50i-h5-mmc
|
||||
- allwinner,sun50i-h6-mmc
|
||||
- const: allwinner,sun50i-a64-mmc
|
||||
- items:
|
||||
- const: allwinner,sun50i-h5-emmc
|
||||
- const: allwinner,sun50i-a64-emmc
|
||||
- items:
|
||||
- const: allwinner,sun50i-h5-mmc
|
||||
- const: allwinner,sun50i-a64-mmc
|
||||
- items:
|
||||
- const: allwinner,sun50i-h6-emmc
|
||||
- const: allwinner,sun50i-a64-emmc
|
||||
- items:
|
||||
- const: allwinner,sun50i-h6-mmc
|
||||
- const: allwinner,sun50i-a64-mmc
|
||||
- items:
|
||||
- const: allwinner,sun20i-d1-emmc
|
||||
- const: allwinner,sun50i-a100-emmc
|
||||
- items:
|
||||
- const: allwinner,sun50i-h616-emmc
|
||||
- enum:
|
||||
- allwinner,sun20i-d1-emmc
|
||||
- allwinner,sun50i-h616-emmc
|
||||
- allwinner,sun55i-a523-emmc
|
||||
- const: allwinner,sun50i-a100-emmc
|
||||
- items:
|
||||
- const: allwinner,sun50i-h616-mmc
|
||||
- const: allwinner,sun50i-a100-mmc
|
||||
- items:
|
||||
- const: allwinner,suniv-f1c100s-mmc
|
||||
- const: allwinner,sun7i-a20-mmc
|
||||
- const: allwinner,sun55i-a523-mmc
|
||||
- const: allwinner,sun20i-d1-mmc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -60,6 +60,9 @@ patternProperties:
|
||||
bus-width:
|
||||
enum: [1, 4]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/atmel,hsmci.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Atmel High-Speed MultiMedia Card Interface (HSMCI)
|
||||
|
||||
description:
|
||||
The Atmel HSMCI controller provides an interface for MMC, SD, and SDIO memory
|
||||
cards.
|
||||
|
||||
maintainers:
|
||||
- Nicolas Ferre <nicolas.ferre@microchip.com>
|
||||
- Aubin Constans <aubin.constans@microchip.com>
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: atmel,hsmci
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
maxItems: 1
|
||||
|
||||
dma-names:
|
||||
const: rxtx
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: mci_clk
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
description: Used for slot IDs.
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"slot@[0-2]$":
|
||||
$ref: mmc-slot.yaml
|
||||
description: A slot node representing an MMC, SD, or SDIO slot.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
enum: [0, 1]
|
||||
|
||||
required:
|
||||
- reg
|
||||
- bus-width
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
anyOf:
|
||||
- required:
|
||||
- slot@0
|
||||
- required:
|
||||
- slot@1
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/at91.h>
|
||||
mmc@f0008000 {
|
||||
compatible = "atmel,hsmci";
|
||||
reg = <0xf0008000 0x600>;
|
||||
interrupts = <12 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mci0_clk>;
|
||||
clock-names = "mci_clk";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
slot@0 {
|
||||
reg = <0>;
|
||||
bus-width = <4>;
|
||||
cd-gpios = <&pioD 15 0>;
|
||||
cd-inverted;
|
||||
};
|
||||
|
||||
slot@1 {
|
||||
reg = <1>;
|
||||
bus-width = <4>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -1,73 +0,0 @@
|
||||
* Atmel High Speed MultiMedia Card Interface
|
||||
|
||||
This controller on atmel products provides an interface for MMC, SD and SDIO
|
||||
types of memory cards.
|
||||
|
||||
This file documents differences between the core properties described
|
||||
by mmc.txt and the properties used by the atmel-mci driver.
|
||||
|
||||
1) MCI node
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "atmel,hsmci"
|
||||
- #address-cells: should be one. The cell is the slot id.
|
||||
- #size-cells: should be zero.
|
||||
- at least one slot node
|
||||
- clock-names: tuple listing input clock names.
|
||||
Required elements: "mci_clk"
|
||||
- clocks: phandles to input clocks.
|
||||
|
||||
The node contains child nodes for each slot that the platform uses
|
||||
|
||||
Example MCI node:
|
||||
|
||||
mmc0: mmc@f0008000 {
|
||||
compatible = "atmel,hsmci";
|
||||
reg = <0xf0008000 0x600>;
|
||||
interrupts = <12 4>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clock-names = "mci_clk";
|
||||
clocks = <&mci0_clk>;
|
||||
|
||||
[ child node definitions...]
|
||||
};
|
||||
|
||||
2) slot nodes
|
||||
|
||||
Required properties:
|
||||
- reg: should contain the slot id.
|
||||
- bus-width: number of data lines connected to the controller
|
||||
|
||||
Optional properties:
|
||||
- cd-gpios: specify GPIOs for card detection
|
||||
- cd-inverted: invert the value of external card detect gpio line
|
||||
- wp-gpios: specify GPIOs for write protection
|
||||
|
||||
Example slot node:
|
||||
|
||||
slot@0 {
|
||||
reg = <0>;
|
||||
bus-width = <4>;
|
||||
cd-gpios = <&pioD 15 0>
|
||||
cd-inverted;
|
||||
};
|
||||
|
||||
Example full MCI node:
|
||||
mmc0: mmc@f0008000 {
|
||||
compatible = "atmel,hsmci";
|
||||
reg = <0xf0008000 0x600>;
|
||||
interrupts = <12 4>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
slot@0 {
|
||||
reg = <0>;
|
||||
bus-width = <4>;
|
||||
cd-gpios = <&pioD 15 0>
|
||||
cd-inverted;
|
||||
};
|
||||
slot@1 {
|
||||
reg = <1>;
|
||||
bus-width = <4>;
|
||||
};
|
||||
};
|
||||
@@ -57,6 +57,7 @@ properties:
|
||||
- fsl,imx8mp-usdhc
|
||||
- fsl,imx8ulp-usdhc
|
||||
- fsl,imx93-usdhc
|
||||
- fsl,imx94-usdhc
|
||||
- fsl,imx95-usdhc
|
||||
- const: fsl,imx8mm-usdhc
|
||||
- items:
|
||||
|
||||
@@ -24,7 +24,7 @@ properties:
|
||||
$nodename:
|
||||
pattern: "^mmc(@.*)?$"
|
||||
|
||||
unevaluatedProperties: true
|
||||
additionalProperties: true
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -29,7 +29,6 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
@@ -68,6 +68,9 @@ properties:
|
||||
- renesas,sdhi-r9a08g045 # RZ/G3S
|
||||
- renesas,sdhi-r9a09g011 # RZ/V2M
|
||||
- const: renesas,rzg2l-sdhi
|
||||
- items:
|
||||
- const: renesas,sdhi-r9a09g047 # RZ/G3E
|
||||
- const: renesas,sdhi-r9a09g057 # RZ/V2H(P)
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -211,6 +214,19 @@ allOf:
|
||||
sectioned off to be run by a separate second clock source to allow
|
||||
the main core clock to be turned off to save power.
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,sdhi-r9a09g057
|
||||
then:
|
||||
properties:
|
||||
vqmmc-regulator:
|
||||
type: object
|
||||
description: VQMMC SD regulator
|
||||
$ref: /schemas/regulator/regulator.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -38,6 +38,8 @@ properties:
|
||||
- rockchip,rk3328-dw-mshc
|
||||
- rockchip,rk3368-dw-mshc
|
||||
- rockchip,rk3399-dw-mshc
|
||||
- rockchip,rk3528-dw-mshc
|
||||
- rockchip,rk3562-dw-mshc
|
||||
- rockchip,rk3568-dw-mshc
|
||||
- rockchip,rk3588-dw-mshc
|
||||
- rockchip,rv1108-dw-mshc
|
||||
|
||||
@@ -24,6 +24,8 @@ properties:
|
||||
- samsung,exynos5420-dw-mshc-smu
|
||||
- samsung,exynos7-dw-mshc
|
||||
- samsung,exynos7-dw-mshc-smu
|
||||
- samsung,exynos7870-dw-mshc
|
||||
- samsung,exynos7870-dw-mshc-smu
|
||||
- items:
|
||||
- enum:
|
||||
- samsung,exynos5433-dw-mshc-smu
|
||||
|
||||
@@ -14,7 +14,10 @@ properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: rockchip,rk3576-dwcmshc
|
||||
- enum:
|
||||
- rockchip,rk3528-dwcmshc
|
||||
- rockchip,rk3562-dwcmshc
|
||||
- rockchip,rk3576-dwcmshc
|
||||
- const: rockchip,rk3588-dwcmshc
|
||||
- enum:
|
||||
- rockchip,rk3568-dwcmshc
|
||||
|
||||
@@ -813,6 +813,7 @@ static void rtsx_usb_ms_drv_remove(struct platform_device *pdev)
|
||||
|
||||
host->eject = true;
|
||||
cancel_work_sync(&host->handle_req);
|
||||
cancel_delayed_work_sync(&host->poll_card);
|
||||
|
||||
mutex_lock(&host->host_mutex);
|
||||
if (host->req) {
|
||||
|
||||
@@ -335,7 +335,7 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (mrq->cmd && mrq->cmd->has_ext_addr)
|
||||
if (mrq->cmd->has_ext_addr)
|
||||
mmc_send_ext_addr(host, mrq->cmd->ext_addr);
|
||||
|
||||
init_completion(&mrq->cmd_completion);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/sysfs.h>
|
||||
@@ -66,7 +67,7 @@ static int mmc_decode_cid(struct mmc_card *card)
|
||||
|
||||
/*
|
||||
* The selection of the format here is based upon published
|
||||
* specs from sandisk and from what people have reported.
|
||||
* specs from SanDisk and from what people have reported.
|
||||
*/
|
||||
switch (card->csd.mmca_vsn) {
|
||||
case 0: /* MMC v1.0 - v1.2 */
|
||||
@@ -109,6 +110,9 @@ static int mmc_decode_cid(struct mmc_card *card)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* some product names include trailing whitespace */
|
||||
strim(card->cid.prod_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/scatterlist.h>
|
||||
@@ -95,6 +96,9 @@ void mmc_decode_cid(struct mmc_card *card)
|
||||
card->cid.month = unstuff_bits(resp, 8, 4);
|
||||
|
||||
card->cid.year += 2000; /* SD cards year offset */
|
||||
|
||||
/* some product names may include trailing whitespace */
|
||||
strim(card->cid.prod_name);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -471,7 +471,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
|
||||
port->icount.cts++;
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty && C_CRTSCTS(tty)) {
|
||||
int cts = (status & UART_MSR_CTS);
|
||||
bool cts = status & UART_MSR_CTS;
|
||||
if (tty->hw_stopped) {
|
||||
if (cts) {
|
||||
tty->hw_stopped = false;
|
||||
|
||||
@@ -159,18 +159,6 @@ int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_set_cd_wake);
|
||||
|
||||
/* Register an alternate interrupt service routine for
|
||||
* the card-detect GPIO.
|
||||
*/
|
||||
void mmc_gpio_set_cd_isr(struct mmc_host *host, irq_handler_t isr)
|
||||
{
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
|
||||
WARN_ON(ctx->cd_gpio_isr);
|
||||
ctx->cd_gpio_isr = isr;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_set_cd_isr);
|
||||
|
||||
/**
|
||||
* mmc_gpiod_request_cd - request a gpio descriptor for card-detection
|
||||
* @host: mmc host
|
||||
|
||||
@@ -27,6 +27,8 @@ enum dw_mci_exynos_type {
|
||||
DW_MCI_TYPE_EXYNOS5420_SMU,
|
||||
DW_MCI_TYPE_EXYNOS7,
|
||||
DW_MCI_TYPE_EXYNOS7_SMU,
|
||||
DW_MCI_TYPE_EXYNOS7870,
|
||||
DW_MCI_TYPE_EXYNOS7870_SMU,
|
||||
DW_MCI_TYPE_ARTPEC8,
|
||||
};
|
||||
|
||||
@@ -69,6 +71,12 @@ static struct dw_mci_exynos_compatible {
|
||||
}, {
|
||||
.compatible = "samsung,exynos7-dw-mshc-smu",
|
||||
.ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU,
|
||||
}, {
|
||||
.compatible = "samsung,exynos7870-dw-mshc",
|
||||
.ctrl_type = DW_MCI_TYPE_EXYNOS7870,
|
||||
}, {
|
||||
.compatible = "samsung,exynos7870-dw-mshc-smu",
|
||||
.ctrl_type = DW_MCI_TYPE_EXYNOS7870_SMU,
|
||||
}, {
|
||||
.compatible = "axis,artpec8-dw-mshc",
|
||||
.ctrl_type = DW_MCI_TYPE_ARTPEC8,
|
||||
@@ -85,6 +93,8 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
|
||||
return EXYNOS4210_FIXED_CIU_CLK_DIV;
|
||||
else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
|
||||
else
|
||||
@@ -100,7 +110,8 @@ static void dw_mci_exynos_config_smu(struct dw_mci *host)
|
||||
* set for non-ecryption mode at this time.
|
||||
*/
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) {
|
||||
mci_writel(host, MPSBEGIN0, 0);
|
||||
mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX);
|
||||
mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT |
|
||||
@@ -126,6 +137,12 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
|
||||
DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
|
||||
}
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU) {
|
||||
/* Quirk needed for certain Exynos SoCs */
|
||||
host->quirks |= DW_MMC_QUIRK_FIFO64_32;
|
||||
}
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) {
|
||||
/* Quirk needed for the ARTPEC-8 SoC */
|
||||
host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT;
|
||||
@@ -143,6 +160,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
clksel = mci_readl(host, CLKSEL64);
|
||||
else
|
||||
@@ -152,6 +171,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
mci_writel(host, CLKSEL64, clksel);
|
||||
else
|
||||
@@ -222,6 +243,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
clksel = mci_readl(host, CLKSEL64);
|
||||
else
|
||||
@@ -230,6 +253,8 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
|
||||
if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
mci_writel(host, CLKSEL64, clksel);
|
||||
else
|
||||
@@ -409,6 +434,8 @@ static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64));
|
||||
else
|
||||
@@ -422,6 +449,8 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
clksel = mci_readl(host, CLKSEL64);
|
||||
else
|
||||
@@ -429,6 +458,8 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
|
||||
clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
mci_writel(host, CLKSEL64, clksel);
|
||||
else
|
||||
@@ -443,6 +474,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
clksel = mci_readl(host, CLKSEL64);
|
||||
else
|
||||
@@ -453,6 +486,8 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7870_SMU ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
|
||||
mci_writel(host, CLKSEL64, clksel);
|
||||
else
|
||||
@@ -632,6 +667,10 @@ static const struct of_device_id dw_mci_exynos_match[] = {
|
||||
.data = &exynos_drv_data, },
|
||||
{ .compatible = "samsung,exynos7-dw-mshc-smu",
|
||||
.data = &exynos_drv_data, },
|
||||
{ .compatible = "samsung,exynos7870-dw-mshc",
|
||||
.data = &exynos_drv_data, },
|
||||
{ .compatible = "samsung,exynos7870-dw-mshc-smu",
|
||||
.data = &exynos_drv_data, },
|
||||
{ .compatible = "axis,artpec8-dw-mshc",
|
||||
.data = &artpec_drv_data, },
|
||||
{},
|
||||
|
||||
@@ -2578,6 +2578,91 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_mci_push_data64_32(struct dw_mci *host, void *buf, int cnt)
|
||||
{
|
||||
struct mmc_data *data = host->data;
|
||||
int init_cnt = cnt;
|
||||
|
||||
/* try and push anything in the part_buf */
|
||||
if (unlikely(host->part_buf_count)) {
|
||||
int len = dw_mci_push_part_bytes(host, buf, cnt);
|
||||
|
||||
buf += len;
|
||||
cnt -= len;
|
||||
|
||||
if (host->part_buf_count == 8) {
|
||||
mci_fifo_l_writeq(host->fifo_reg, host->part_buf);
|
||||
host->part_buf_count = 0;
|
||||
}
|
||||
}
|
||||
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
if (unlikely((unsigned long)buf & 0x7)) {
|
||||
while (cnt >= 8) {
|
||||
u64 aligned_buf[16];
|
||||
int len = min(cnt & -8, (int)sizeof(aligned_buf));
|
||||
int items = len >> 3;
|
||||
int i;
|
||||
/* memcpy from input buffer into aligned buffer */
|
||||
memcpy(aligned_buf, buf, len);
|
||||
buf += len;
|
||||
cnt -= len;
|
||||
/* push data from aligned buffer into fifo */
|
||||
for (i = 0; i < items; ++i)
|
||||
mci_fifo_l_writeq(host->fifo_reg, aligned_buf[i]);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
u64 *pdata = buf;
|
||||
|
||||
for (; cnt >= 8; cnt -= 8)
|
||||
mci_fifo_l_writeq(host->fifo_reg, *pdata++);
|
||||
buf = pdata;
|
||||
}
|
||||
/* put anything remaining in the part_buf */
|
||||
if (cnt) {
|
||||
dw_mci_set_part_bytes(host, buf, cnt);
|
||||
/* Push data if we have reached the expected data length */
|
||||
if ((data->bytes_xfered + init_cnt) ==
|
||||
(data->blksz * data->blocks))
|
||||
mci_fifo_l_writeq(host->fifo_reg, host->part_buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_mci_pull_data64_32(struct dw_mci *host, void *buf, int cnt)
|
||||
{
|
||||
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
if (unlikely((unsigned long)buf & 0x7)) {
|
||||
while (cnt >= 8) {
|
||||
/* pull data from fifo into aligned buffer */
|
||||
u64 aligned_buf[16];
|
||||
int len = min(cnt & -8, (int)sizeof(aligned_buf));
|
||||
int items = len >> 3;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < items; ++i)
|
||||
aligned_buf[i] = mci_fifo_l_readq(host->fifo_reg);
|
||||
|
||||
/* memcpy from aligned buffer into output buffer */
|
||||
memcpy(buf, aligned_buf, len);
|
||||
buf += len;
|
||||
cnt -= len;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
u64 *pdata = buf;
|
||||
|
||||
for (; cnt >= 8; cnt -= 8)
|
||||
*pdata++ = mci_fifo_l_readq(host->fifo_reg);
|
||||
buf = pdata;
|
||||
}
|
||||
if (cnt) {
|
||||
host->part_buf = mci_fifo_l_readq(host->fifo_reg);
|
||||
dw_mci_pull_final_bytes(host, buf, cnt);
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
|
||||
{
|
||||
int len;
|
||||
@@ -3378,8 +3463,13 @@ int dw_mci_probe(struct dw_mci *host)
|
||||
width = 16;
|
||||
host->data_shift = 1;
|
||||
} else if (i == 2) {
|
||||
host->push_data = dw_mci_push_data64;
|
||||
host->pull_data = dw_mci_pull_data64;
|
||||
if ((host->quirks & DW_MMC_QUIRK_FIFO64_32)) {
|
||||
host->push_data = dw_mci_push_data64_32;
|
||||
host->pull_data = dw_mci_pull_data64_32;
|
||||
} else {
|
||||
host->push_data = dw_mci_push_data64;
|
||||
host->pull_data = dw_mci_pull_data64;
|
||||
}
|
||||
width = 64;
|
||||
host->data_shift = 3;
|
||||
} else {
|
||||
|
||||
@@ -281,6 +281,8 @@ struct dw_mci_board {
|
||||
|
||||
/* Support for longer data read timeout */
|
||||
#define DW_MMC_QUIRK_EXTENDED_TMOUT BIT(0)
|
||||
/* Force 32-bit access to the FIFO */
|
||||
#define DW_MMC_QUIRK_FIFO64_32 BIT(1)
|
||||
|
||||
#define DW_MMC_240A 0x240a
|
||||
#define DW_MMC_280A 0x280a
|
||||
@@ -472,6 +474,31 @@ struct dw_mci_board {
|
||||
#define mci_fifo_writel(__value, __reg) __raw_writel(__reg, __value)
|
||||
#define mci_fifo_writeq(__value, __reg) __raw_writeq(__reg, __value)
|
||||
|
||||
/*
|
||||
* Some dw_mmc devices have 64-bit FIFOs, but expect them to be
|
||||
* accessed using two 32-bit accesses. If such controller is used
|
||||
* with a 64-bit kernel, this has to be done explicitly.
|
||||
*/
|
||||
static inline u64 mci_fifo_l_readq(void __iomem *addr)
|
||||
{
|
||||
u64 ans;
|
||||
u32 proxy[2];
|
||||
|
||||
proxy[0] = mci_fifo_readl(addr);
|
||||
proxy[1] = mci_fifo_readl(addr + 4);
|
||||
memcpy(&ans, proxy, 8);
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline void mci_fifo_l_writeq(void __iomem *addr, u64 value)
|
||||
{
|
||||
u32 proxy[2];
|
||||
|
||||
memcpy(proxy, &value, 8);
|
||||
mci_fifo_writel(addr, proxy[0]);
|
||||
mci_fifo_writel(addr + 4, proxy[1]);
|
||||
}
|
||||
|
||||
/* Register access macros */
|
||||
#define mci_readl(dev, reg) \
|
||||
readl_relaxed((dev)->regs + SDMMC_##reg)
|
||||
|
||||
+13
-6
@@ -1272,19 +1272,25 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
|
||||
/* Check for some optional GPIO controls */
|
||||
slot->vsd = devm_gpiod_get_index_optional(host->dev, "vsd",
|
||||
id, GPIOD_OUT_LOW);
|
||||
if (IS_ERR(slot->vsd))
|
||||
return dev_err_probe(host->dev, PTR_ERR(slot->vsd),
|
||||
if (IS_ERR(slot->vsd)) {
|
||||
r = dev_err_probe(host->dev, PTR_ERR(slot->vsd),
|
||||
"error looking up VSD GPIO\n");
|
||||
goto err_free_host;
|
||||
}
|
||||
slot->vio = devm_gpiod_get_index_optional(host->dev, "vio",
|
||||
id, GPIOD_OUT_LOW);
|
||||
if (IS_ERR(slot->vio))
|
||||
return dev_err_probe(host->dev, PTR_ERR(slot->vio),
|
||||
if (IS_ERR(slot->vio)) {
|
||||
r = dev_err_probe(host->dev, PTR_ERR(slot->vio),
|
||||
"error looking up VIO GPIO\n");
|
||||
goto err_free_host;
|
||||
}
|
||||
slot->cover = devm_gpiod_get_index_optional(host->dev, "cover",
|
||||
id, GPIOD_IN);
|
||||
if (IS_ERR(slot->cover))
|
||||
return dev_err_probe(host->dev, PTR_ERR(slot->cover),
|
||||
if (IS_ERR(slot->cover)) {
|
||||
r = dev_err_probe(host->dev, PTR_ERR(slot->cover),
|
||||
"error looking up cover switch GPIO\n");
|
||||
goto err_free_host;
|
||||
}
|
||||
|
||||
host->slots[id] = slot;
|
||||
|
||||
@@ -1344,6 +1350,7 @@ err_remove_slot_name:
|
||||
device_remove_file(&mmc->class_dev, &dev_attr_slot_name);
|
||||
err_remove_host:
|
||||
mmc_remove_host(mmc);
|
||||
err_free_host:
|
||||
mmc_free_host(mmc);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ struct renesas_sdhi {
|
||||
|
||||
struct reset_control *rstc;
|
||||
struct tmio_mmc_host *host;
|
||||
struct regulator_dev *rdev;
|
||||
};
|
||||
|
||||
#define host_to_priv(host) \
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -581,12 +583,24 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve)
|
||||
|
||||
if (!preserve) {
|
||||
if (priv->rstc) {
|
||||
u32 sd_status;
|
||||
/*
|
||||
* HW reset might have toggled the regulator state in
|
||||
* HW which regulator core might be unaware of so save
|
||||
* and restore the regulator state during HW reset.
|
||||
*/
|
||||
if (priv->rdev)
|
||||
sd_status = sd_ctrl_read32(host, CTL_SD_STATUS);
|
||||
|
||||
reset_control_reset(priv->rstc);
|
||||
/* Unknown why but without polling reset status, it will hang */
|
||||
read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
|
||||
false, priv->rstc);
|
||||
/* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */
|
||||
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
|
||||
if (priv->rdev)
|
||||
sd_ctrl_write32(host, CTL_SD_STATUS, sd_status);
|
||||
|
||||
priv->needs_adjust_hs400 = false;
|
||||
renesas_sdhi_set_clock(host, host->clk_cache);
|
||||
|
||||
@@ -904,6 +918,102 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
|
||||
renesas_sdhi_sdbuf_width(host, enable ? width : 16);
|
||||
}
|
||||
|
||||
static const unsigned int renesas_sdhi_vqmmc_voltages[] = {
|
||||
3300000, 1800000
|
||||
};
|
||||
|
||||
static int renesas_sdhi_regulator_disable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tmio_mmc_host *host = rdev_get_drvdata(rdev);
|
||||
u32 sd_status;
|
||||
|
||||
sd_status = sd_ctrl_read32(host, CTL_SD_STATUS);
|
||||
sd_status &= ~SD_STATUS_PWEN;
|
||||
sd_ctrl_write32(host, CTL_SD_STATUS, sd_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int renesas_sdhi_regulator_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tmio_mmc_host *host = rdev_get_drvdata(rdev);
|
||||
u32 sd_status;
|
||||
|
||||
sd_status = sd_ctrl_read32(host, CTL_SD_STATUS);
|
||||
sd_status |= SD_STATUS_PWEN;
|
||||
sd_ctrl_write32(host, CTL_SD_STATUS, sd_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int renesas_sdhi_regulator_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tmio_mmc_host *host = rdev_get_drvdata(rdev);
|
||||
u32 sd_status;
|
||||
|
||||
sd_status = sd_ctrl_read32(host, CTL_SD_STATUS);
|
||||
|
||||
return (sd_status & SD_STATUS_PWEN) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int renesas_sdhi_regulator_get_voltage(struct regulator_dev *rdev)
|
||||
{
|
||||
struct tmio_mmc_host *host = rdev_get_drvdata(rdev);
|
||||
u32 sd_status;
|
||||
|
||||
sd_status = sd_ctrl_read32(host, CTL_SD_STATUS);
|
||||
|
||||
return (sd_status & SD_STATUS_IOVS) ? 1800000 : 3300000;
|
||||
}
|
||||
|
||||
static int renesas_sdhi_regulator_set_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV,
|
||||
unsigned int *selector)
|
||||
{
|
||||
struct tmio_mmc_host *host = rdev_get_drvdata(rdev);
|
||||
u32 sd_status;
|
||||
|
||||
sd_status = sd_ctrl_read32(host, CTL_SD_STATUS);
|
||||
if (min_uV >= 1700000 && max_uV <= 1950000) {
|
||||
sd_status |= SD_STATUS_IOVS;
|
||||
*selector = 1;
|
||||
} else {
|
||||
sd_status &= ~SD_STATUS_IOVS;
|
||||
*selector = 0;
|
||||
}
|
||||
sd_ctrl_write32(host, CTL_SD_STATUS, sd_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int renesas_sdhi_regulator_list_voltage(struct regulator_dev *rdev,
|
||||
unsigned int selector)
|
||||
{
|
||||
if (selector >= ARRAY_SIZE(renesas_sdhi_vqmmc_voltages))
|
||||
return -EINVAL;
|
||||
|
||||
return renesas_sdhi_vqmmc_voltages[selector];
|
||||
}
|
||||
|
||||
static const struct regulator_ops renesas_sdhi_regulator_voltage_ops = {
|
||||
.enable = renesas_sdhi_regulator_enable,
|
||||
.disable = renesas_sdhi_regulator_disable,
|
||||
.is_enabled = renesas_sdhi_regulator_is_enabled,
|
||||
.list_voltage = renesas_sdhi_regulator_list_voltage,
|
||||
.get_voltage = renesas_sdhi_regulator_get_voltage,
|
||||
.set_voltage = renesas_sdhi_regulator_set_voltage,
|
||||
};
|
||||
|
||||
static const struct regulator_desc renesas_sdhi_vqmmc_regulator = {
|
||||
.name = "sdhi-vqmmc-regulator",
|
||||
.of_match = of_match_ptr("vqmmc-regulator"),
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.ops = &renesas_sdhi_regulator_voltage_ops,
|
||||
.volt_table = renesas_sdhi_vqmmc_voltages,
|
||||
.n_voltages = ARRAY_SIZE(renesas_sdhi_vqmmc_voltages),
|
||||
};
|
||||
|
||||
int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
const struct tmio_mmc_dma_ops *dma_ops,
|
||||
const struct renesas_sdhi_of_data *of_data,
|
||||
@@ -911,7 +1021,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
{
|
||||
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
|
||||
struct tmio_mmc_data *mmc_data;
|
||||
struct regulator_config rcfg = { .dev = &pdev->dev, };
|
||||
struct regulator_dev *rdev;
|
||||
struct renesas_sdhi_dma *dma_priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tmio_mmc_host *host;
|
||||
struct renesas_sdhi *priv;
|
||||
int num_irqs, irq, ret, i;
|
||||
@@ -1053,6 +1166,24 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
if (ret)
|
||||
goto efree;
|
||||
|
||||
rcfg.of_node = of_get_child_by_name(dev->of_node, "vqmmc-regulator");
|
||||
if (!of_device_is_available(rcfg.of_node)) {
|
||||
of_node_put(rcfg.of_node);
|
||||
rcfg.of_node = NULL;
|
||||
}
|
||||
|
||||
if (rcfg.of_node) {
|
||||
rcfg.driver_data = priv->host;
|
||||
rdev = devm_regulator_register(dev, &renesas_sdhi_vqmmc_regulator, &rcfg);
|
||||
of_node_put(rcfg.of_node);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(dev, "regulator register failed err=%ld", PTR_ERR(rdev));
|
||||
ret = PTR_ERR(rdev);
|
||||
goto efree;
|
||||
}
|
||||
priv->rdev = rdev;
|
||||
}
|
||||
|
||||
ver = sd_ctrl_read16(host, CTL_VERSION);
|
||||
/* GEN2_SDR104 is first known SDHI to use 32bit block count */
|
||||
if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX)
|
||||
|
||||
@@ -328,12 +328,17 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
sdhci_request(mmc, mrq);
|
||||
}
|
||||
|
||||
static void dwcmshc_phy_1_8v_init(struct sdhci_host *host)
|
||||
static void dwcmshc_phy_init(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
u32 rxsel = PHY_PAD_RXSEL_3V3;
|
||||
u32 val;
|
||||
|
||||
if (priv->flags & FLAG_IO_FIXED_1V8 ||
|
||||
host->mmc->ios.timing & MMC_SIGNAL_VOLTAGE_180)
|
||||
rxsel = PHY_PAD_RXSEL_1V8;
|
||||
|
||||
/* deassert phy reset & set tx drive strength */
|
||||
val = PHY_CNFG_RSTN_DEASSERT;
|
||||
val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP);
|
||||
@@ -353,7 +358,7 @@ static void dwcmshc_phy_1_8v_init(struct sdhci_host *host)
|
||||
sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
|
||||
|
||||
/* configure phy pads */
|
||||
val = PHY_PAD_RXSEL_1V8;
|
||||
val = rxsel;
|
||||
val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
||||
@@ -365,65 +370,22 @@ static void dwcmshc_phy_1_8v_init(struct sdhci_host *host)
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
||||
sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
|
||||
|
||||
val = PHY_PAD_RXSEL_1V8;
|
||||
val = rxsel;
|
||||
val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
||||
sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
|
||||
|
||||
/* enable data strobe mode */
|
||||
sdhci_writeb(host, FIELD_PREP(PHY_DLLDL_CNFG_SLV_INPSEL_MASK, PHY_DLLDL_CNFG_SLV_INPSEL),
|
||||
PHY_DLLDL_CNFG_R);
|
||||
if (rxsel == PHY_PAD_RXSEL_1V8) {
|
||||
u8 sel = FIELD_PREP(PHY_DLLDL_CNFG_SLV_INPSEL_MASK, PHY_DLLDL_CNFG_SLV_INPSEL);
|
||||
|
||||
sdhci_writeb(host, sel, PHY_DLLDL_CNFG_R);
|
||||
}
|
||||
|
||||
/* enable phy dll */
|
||||
sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R);
|
||||
}
|
||||
|
||||
static void dwcmshc_phy_3_3v_init(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
u32 val;
|
||||
|
||||
/* deassert phy reset & set tx drive strength */
|
||||
val = PHY_CNFG_RSTN_DEASSERT;
|
||||
val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP);
|
||||
val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN);
|
||||
sdhci_writel(host, val, PHY_CNFG_R);
|
||||
|
||||
/* disable delay line */
|
||||
sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R);
|
||||
|
||||
/* set delay line */
|
||||
sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R);
|
||||
sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R);
|
||||
|
||||
/* enable delay lane */
|
||||
val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
|
||||
val &= ~(PHY_SDCLKDL_CNFG_UPDATE);
|
||||
sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
|
||||
|
||||
/* configure phy pads */
|
||||
val = PHY_PAD_RXSEL_3V3;
|
||||
val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
||||
sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
|
||||
sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
|
||||
sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
|
||||
|
||||
val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
||||
sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
|
||||
|
||||
val = PHY_PAD_RXSEL_3V3;
|
||||
val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
|
||||
val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
|
||||
sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
|
||||
|
||||
/* enable phy dll */
|
||||
sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R);
|
||||
}
|
||||
|
||||
static void th1520_sdhci_set_phy(struct sdhci_host *host)
|
||||
@@ -433,11 +395,7 @@ static void th1520_sdhci_set_phy(struct sdhci_host *host)
|
||||
u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
|
||||
u16 emmc_ctrl;
|
||||
|
||||
/* Before power on, set PHY configs */
|
||||
if (priv->flags & FLAG_IO_FIXED_1V8)
|
||||
dwcmshc_phy_1_8v_init(host);
|
||||
else
|
||||
dwcmshc_phy_3_3v_init(host);
|
||||
dwcmshc_phy_init(host);
|
||||
|
||||
if ((host->mmc->caps2 & emmc_caps) == emmc_caps) {
|
||||
emmc_ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
|
||||
@@ -1163,7 +1121,7 @@ static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = {
|
||||
.get_max_clock = dwcmshc_get_max_clock,
|
||||
.reset = th1520_sdhci_reset,
|
||||
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||
.voltage_switch = dwcmshc_phy_1_8v_init,
|
||||
.voltage_switch = dwcmshc_phy_init,
|
||||
.platform_execute_tuning = th1520_execute_tuning,
|
||||
};
|
||||
|
||||
|
||||
@@ -1339,8 +1339,8 @@ static int sdhci_omap_probe(struct platform_device *pdev)
|
||||
/* R1B responses is required to properly manage HW busy detection. */
|
||||
mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
|
||||
|
||||
/* Allow card power off and runtime PM for eMMC/SD card devices */
|
||||
mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_AGGRESSIVE_PM;
|
||||
/* Enable SDIO card power off. */
|
||||
mmc->caps |= MMC_CAP_POWER_OFF_CARD;
|
||||
|
||||
ret = sdhci_setup_host(host);
|
||||
if (ret)
|
||||
|
||||
@@ -610,8 +610,12 @@ static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
|
||||
|
||||
sdhci_set_power(host, mode, vdd);
|
||||
|
||||
if (mode == MMC_POWER_OFF)
|
||||
if (mode == MMC_POWER_OFF) {
|
||||
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD ||
|
||||
slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BYT_SD)
|
||||
usleep_range(15000, 17500);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bus power might not enable after D3 -> D0 transition due to the
|
||||
|
||||
@@ -399,6 +399,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
|
||||
if (!IS_ERR(pxa->clk_core))
|
||||
clk_prepare_enable(pxa->clk_core);
|
||||
|
||||
host->mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
|
||||
/* enable 1/8V DDR capable */
|
||||
host->mmc->caps |= MMC_CAP_1_8V_DDR;
|
||||
|
||||
|
||||
@@ -2065,10 +2065,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
|
||||
host->mmc->actual_clock = 0;
|
||||
|
||||
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
||||
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
|
||||
if (clk & SDHCI_CLOCK_CARD_EN)
|
||||
sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN,
|
||||
SDHCI_CLOCK_CONTROL);
|
||||
|
||||
if (clock == 0)
|
||||
if (clock == 0) {
|
||||
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
||||
return;
|
||||
}
|
||||
|
||||
clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
|
||||
sdhci_enable_clk(host, clk);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#define CTL_RESET_SD 0xe0
|
||||
#define CTL_VERSION 0xe2
|
||||
#define CTL_SDIF_MODE 0xe6 /* only known on R-Car 2+ */
|
||||
#define CTL_SD_STATUS 0xf2 /* only known on RZ/{G2L,G3E,V2H} */
|
||||
|
||||
/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
|
||||
#define TMIO_STOP_STP BIT(0)
|
||||
@@ -103,6 +104,10 @@
|
||||
/* Definitions for values the CTL_SDIF_MODE register can take */
|
||||
#define SDIF_MODE_HS400 BIT(0) /* only known on R-Car 2+ */
|
||||
|
||||
/* Definitions for values the CTL_SD_STATUS register can take */
|
||||
#define SD_STATUS_PWEN BIT(0) /* only known on RZ/{G3E,V2H} */
|
||||
#define SD_STATUS_IOVS BIT(16) /* only known on RZ/{G3E,V2H} */
|
||||
|
||||
/* Define some IRQ masks */
|
||||
/* This is the mask used at reset by the chip */
|
||||
#define TMIO_MASK_ALL 0x837f031d
|
||||
@@ -226,6 +231,11 @@ static inline u32 sd_ctrl_read16_and_16_as_32(struct tmio_mmc_host *host,
|
||||
ioread16(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
|
||||
}
|
||||
|
||||
static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
|
||||
{
|
||||
return ioread32(host->ctl + (addr << host->bus_shift));
|
||||
}
|
||||
|
||||
static inline void sd_ctrl_read32_rep(struct tmio_mmc_host *host, int addr,
|
||||
u32 *buf, int count)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,6 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
|
||||
int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
|
||||
unsigned int idx, unsigned int debounce);
|
||||
int mmc_gpiod_set_cd_config(struct mmc_host *host, unsigned long config);
|
||||
void mmc_gpio_set_cd_isr(struct mmc_host *host, irq_handler_t isr);
|
||||
int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on);
|
||||
void mmc_gpiod_request_cd_irq(struct mmc_host *host);
|
||||
bool mmc_can_gpio_cd(struct mmc_host *host);
|
||||
|
||||
Reference in New Issue
Block a user