Commit bbd60bff authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mmc-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "Updates for MMC for v4.19.

  MMC core:
   - Add some fine-grained hooks to further support HS400 tuning
   - Improve error path for bus width setting for HS400es
   - Use a common method when checking R1 status

  MMC host:
   - renesas_sdhi: Add r8a77990 support
   - renesas_sdhi: Add eMMC HS400 mode support
   - tmio/renesas_sdhi: Improve tuning/clock management
   - tmio: Add eMMC HS400 mode support
   - sunxi: Add support for 3.3V eMMC DDR mode
   - mmci: Initial support to manage variant specific callbacks
   - sdhci: Don't try 3.3V I/O voltage if not supported
   - sdhci-pci-dwc-mshc: Add driver to support Synopsys dwc mshc SDHCI PCI
   - sdhci-of-dwcmshc: Add driver to support Synopsys DWC MSHC SDHCI
   - sdhci-msm: Add support for new version sdcc V5
   - sdhci-pci-o2micro: Add support for O2 eMMC HS200 mode
   - sdhci-pci-o2micro: Add support for O2 hardware tuning
   - sdhci-pci-o2micro: Add MSI interrupt support for O2 SD host
   - sdhci-pci: Add support for Intel ICP
   - sdhci-tegra: Prevent ACMD23 and HS200 mode on Tegra 3
   - sdhci-tegra: Fix eMMC DDR52 mode
   - sdhci-tegra: Improve clock management
   - dw_mmc-rockchip: Document compatible string for px30
   - sdhci-esdhc-imx: Add support for 3.3V eMMC DDR mode
   - sdhci-of-esdhc: Set proper DMA mask for ls104x chips
   - sdhci-of-esdhc: Improve clock management
   - sdhci-of-arasan: Add a quirk to manage unstable clocks
   - dw_mmc-exynos: Address potential external abort during system resume
   - pxamci: Add support for common MMC DT bindings
   - pxamci: Several cleanups and improvements
   - pxamci: Merge immutable branch for pxa to switch to DMA slave maps"

* tag 'mmc-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (56 commits)
  mmc: core: improve reasonableness of bus width setting for HS400es
  mmc: tmio: remove unneeded variable in tmio_mmc_start_command()
  mmc: renesas_sdhi: Fix sampling clock position selecting
  mmc: tmio: Fix tuning flow
  mmc: sunxi: remove output of virtual base address
  dt-bindings: mmc: rockchip-dw-mshc: add description for px30
  mmc: renesas_sdhi: Add r8a77990 support
  mmc: sunxi: allow 3.3V DDR when DDR is available
  mmc: mmci: Add and implement a ->dma_setup() callback for qcom dml
  mmc: mmci: Initial support to manage variant specific callbacks
  mmc: tegra: Force correct divider calculation on DDR50/52
  mmc: sdhci: Add MSI interrupt support for O2 SD host
  mmc: sdhci: Add support for O2 hardware tuning
  mmc: sdhci: Export sdhci tuning function symbol
  mmc: sdhci: Change O2 Host HS200 mode clock frequency to 200MHz
  mmc: sdhci: Add support for O2 eMMC HS200 mode
  mmc: tegra: Add and use tegra_sdhci_get_max_clock()
  mmc: sdhci-esdhc-imx: fix indent
  mmc: sdhci-esdhc-imx: disable clocks before changing frequency
  mmc: tegra: prevent ACMD23 on Tegra 3
  ...
parents 30779715 7f38abf2
......@@ -37,6 +37,8 @@ Optional Properties:
- xlnx,fails-without-test-cd: when present, the controller doesn't work when
the CD line is not connected properly, and the line is not connected
properly. Test mode can be used to force the controller to function.
- xlnx,int-clock-stable-broken: when present, the controller always reports
that the internal clock is stable even when it is not.
Example:
sdhci@e0100000 {
......
......@@ -8,10 +8,9 @@ Required properties:
Optional properties:
- marvell,detect-delay-ms: sets the detection delay timeout in ms.
- marvell,gpio-power: GPIO spec for the card power enable pin
This file documents differences between the core properties in mmc.txt
and the properties used by the pxa-mmc driver.
In addition to the properties described in this docuent, the details
described in mmc.txt are supported.
Examples:
......@@ -19,6 +18,7 @@ mmc0: mmc@41100000 {
compatible = "marvell,pxa-mmc";
reg = <0x41100000 0x1000>;
interrupts = <23>;
vmmc-supply = <&mmc_regulator>;
cd-gpios = <&gpio 23 0>;
wp-gpios = <&gpio 24 0>;
};
......
......@@ -14,6 +14,7 @@ Required Properties:
before RK3288
- "rockchip,rk3288-dw-mshc": for Rockchip RK3288
- "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RV1108
- "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip PX30
- "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3036
- "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK322x
- "rockchip,rk3328-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3328
......
......@@ -4,7 +4,12 @@ This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci-msm driver.
Required properties:
- compatible: Should contain "qcom,sdhci-msm-v4".
- compatible: Should contain:
"qcom,sdhci-msm-v4" for sdcc versions less than 5.0
"qcom,sdhci-msm-v5" for sdcc versions >= 5.0
For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC. New compatible
string is added to support this change - "qcom,sdhci-msm-v5".
- reg: Base address and length of the register in the following order:
- Host controller register map (required)
- SD Core register map (required)
......
* Synopsys DesignWare Cores Mobile Storage Host Controller
Required properties:
- compatible: should be one of the following:
"snps,dwcmshc-sdhci"
- reg: offset and length of the register set for the device.
- interrupts: a single interrupt specifier.
- clocks: Array of clocks required for SDHCI; requires at least one for
core clock.
- clock-names: Array of names corresponding to clocks property; shall be
"core" for core clock and "bus" for optional bus clock.
Example:
sdhci2: sdhci@aa0000 {
compatible = "snps,dwcmshc-sdhci";
reg = <0xaa0000 0x1000>;
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&emmcclk>;
bus-width = <8>;
}
......@@ -28,6 +28,7 @@ Required properties:
"renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
"renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC
"renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC
"renesas,sdhi-r8a77990" - SDHI IP on R8A77990 SoC
"renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC
"renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
"renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
......
......@@ -12916,6 +12916,13 @@ S: Maintained
F: drivers/mmc/host/sdhci*
F: include/linux/mmc/sdhci*
SYNOPSYS SDHCI COMPLIANT DWC MSHC DRIVER
M: Prabu Thangamuthu <prabu.t@synopsys.com>
M: Manjunath M B <manjumb@synopsys.com>
L: linux-mmc@vger.kernel.org
S: Maintained
F: drivers/mmc/host/sdhci-pci-dwc-mshc.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
M: Ben Dooks <ben-linux@fluff.org>
M: Jaehoon Chung <jh80.chung@samsung.com>
......
......@@ -2078,7 +2078,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
/* Do not retry else we can't see errors */
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err || (cmd.resp[0] & 0xFDF92000)) {
if (err || R1_STATUS(cmd.resp[0])) {
pr_err("error %d requesting status %#x\n",
err, cmd.resp[0]);
err = -EIO;
......@@ -2716,52 +2716,6 @@ void mmc_stop_host(struct mmc_host *host)
mmc_release_host(host);
}
int mmc_power_save_host(struct mmc_host *host)
{
int ret = 0;
pr_debug("%s: %s: powering down\n", mmc_hostname(host), __func__);
mmc_bus_get(host);
if (!host->bus_ops || host->bus_dead) {
mmc_bus_put(host);
return -EINVAL;
}
if (host->bus_ops->power_save)
ret = host->bus_ops->power_save(host);
mmc_bus_put(host);
mmc_power_off(host);
return ret;
}
EXPORT_SYMBOL(mmc_power_save_host);
int mmc_power_restore_host(struct mmc_host *host)
{
int ret;
pr_debug("%s: %s: powering up\n", mmc_hostname(host), __func__);
mmc_bus_get(host);
if (!host->bus_ops || host->bus_dead) {
mmc_bus_put(host);
return -EINVAL;
}
mmc_power_up(host, host->card->ocr);
ret = host->bus_ops->power_restore(host);
mmc_bus_put(host);
return ret;
}
EXPORT_SYMBOL(mmc_power_restore_host);
#ifdef CONFIG_PM_SLEEP
/* Do the card removal on suspend if card is assumed removeable
* Do that in pm notifier while userspace isn't yet frozen, so we will be able
......
......@@ -28,8 +28,6 @@ struct mmc_bus_ops {
int (*resume)(struct mmc_host *);
int (*runtime_suspend)(struct mmc_host *);
int (*runtime_resume)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
int (*shutdown)(struct mmc_host *);
int (*hw_reset)(struct mmc_host *);
......
......@@ -1169,6 +1169,10 @@ static int mmc_select_hs400(struct mmc_card *card)
/* Set host controller to HS timing */
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
/* Prepare host to downgrade to HS timing */
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
/* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr);
......@@ -1209,6 +1213,9 @@ static int mmc_select_hs400(struct mmc_card *card)
if (err)
goto out_err;
if (host->ops->hs400_complete)
host->ops->hs400_complete(host);
return 0;
out_err:
......@@ -1256,6 +1263,9 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS);
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
err = mmc_switch_status(card);
if (err)
goto out_err;
......@@ -1338,8 +1348,12 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err;
err = mmc_select_bus_width(card);
if (err < 0)
if (err != MMC_BUS_WIDTH_8) {
pr_err("%s: switch to 8bit bus width failed, err:%d\n",
mmc_hostname(host), err);
err = err < 0 ? err : -ENOTSUPP;
goto out_err;
}
/* Switch card to HS mode */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
......
......@@ -417,7 +417,7 @@ static int mmc_switch_status_error(struct mmc_host *host, u32 status)
if (status & R1_SPI_ILLEGAL_COMMAND)
return -EBADMSG;
} else {
if (status & 0xFDFFA000)
if (R1_STATUS(status))
pr_warn("%s: unexpected status %#x after switch\n",
mmc_hostname(host), status);
if (status & R1_SWITCH_ERROR)
......
......@@ -1076,7 +1076,6 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
.resume = mmc_sdio_resume,
.runtime_suspend = mmc_sdio_runtime_suspend,
.runtime_resume = mmc_sdio_runtime_resume,
.power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive,
.hw_reset = mmc_sdio_hw_reset,
.sw_reset = mmc_sdio_sw_reset,
......
......@@ -176,6 +176,17 @@ config MMC_SDHCI_OF_HLWD
If unsure, say N.
config MMC_SDHCI_OF_DWCMSHC
tristate "SDHCI OF support for the Synopsys DWC MSHC"
depends on MMC_SDHCI_PLTFM
depends on OF
depends on COMMON_CLK
help
This selects Synopsys DesignWare Cores Mobile Storage Controller
support.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_SDHCI_CADENCE
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
depends on MMC_SDHCI_PLTFM
......
......@@ -11,7 +11,8 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o
sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
sdhci-pci-dwc-mshc.o
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
......@@ -82,6 +83,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o
obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
......
......@@ -175,6 +175,20 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
return ret;
}
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
/**
* dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
*
* This ensures that device will be in runtime active state in
* dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume()
*/
static int dw_mci_exynos_suspend_noirq(struct device *dev)
{
pm_runtime_get_noresume(dev);
return pm_runtime_force_suspend(dev);
}
/**
* dw_mci_exynos_resume_noirq - Exynos-specific resume code
......@@ -186,12 +200,16 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
*
* We run this code on all exynos variants because it doesn't hurt.
*/
static int dw_mci_exynos_resume_noirq(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel;
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
......@@ -207,11 +225,11 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
mci_writel(host, CLKSEL, clksel);
}
pm_runtime_put(dev);
return 0;
}
#else
#define dw_mci_exynos_resume_noirq NULL
#endif /* CONFIG_PM */
#endif /* CONFIG_PM_SLEEP */
static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
{
......@@ -553,14 +571,11 @@ static int dw_mci_exynos_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops dw_mci_exynos_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq,
dw_mci_exynos_resume_noirq)
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
dw_mci_exynos_runtime_resume,
NULL)
.resume_noirq = dw_mci_exynos_resume_noirq,
.thaw_noirq = dw_mci_exynos_resume_noirq,
.restore_noirq = dw_mci_exynos_resume_noirq,
};
static struct platform_driver dw_mci_exynos_pltfm_driver = {
......
......@@ -48,78 +48,6 @@
static unsigned int fmax = 515633;
/**
* struct variant_data - MMCI variant-specific quirks
* @clkreg: default value for MCICLOCK register
* @clkreg_enable: enable value for MMCICLOCK register
* @clkreg_8bit_bus_enable: enable value for 8 bit bus
* @clkreg_neg_edge_enable: enable value for inverted data/cmd output
* @datalength_bits: number of bits in the MMCIDATALENGTH register
* @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
* is asserted (likewise for RX)
* @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
* is asserted (likewise for RX)
* @data_cmd_enable: enable value for data commands.
* @st_sdio: enable ST specific SDIO logic
* @st_clkdiv: true if using a ST-specific clock divider algorithm
* @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
* register
* @datactrl_mask_sdio: SDIO enable mask in datactrl register
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
* @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
* @busy_detect: true if the variant supports busy detection on DAT0.
* @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
* @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
* indicating that the card is busy
* @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
* getting busy end detection interrupts
* @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
* @explicit_mclk_control: enable explicit mclk control in driver.
* @qcom_fifo: enables qcom specific fifo pio read logic.
* @qcom_dml: enables qcom specific dma glue for dma transfers.
* @reversed_irq_handling: handle data irq before cmd irq.
* @mmcimask1: true if variant have a MMCIMASK1 register.
* @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
*/
struct variant_data {
unsigned int clkreg;
unsigned int clkreg_enable;
unsigned int clkreg_8bit_bus_enable;
unsigned int clkreg_neg_edge_enable;
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;
unsigned int data_cmd_enable;
unsigned int datactrl_mask_ddrmode;
unsigned int datactrl_mask_sdio;
bool st_sdio;
bool st_clkdiv;
bool blksz_datactrl16;
bool blksz_datactrl4;
u32 pwrreg_powerup;
u32 f_max;
bool signal_direction;
bool pwrreg_clkgate;
bool busy_detect;
u32 busy_dpsm_flag;
u32 busy_detect_flag;
u32 busy_detect_mask;
bool pwrreg_nopower;
bool explicit_mclk_control;
bool qcom_fifo;
bool qcom_dml;
bool reversed_irq_handling;
bool mmcimask1;
u32 start_err;
u32 opendrain;
};
static struct variant_data variant_arm = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
......@@ -280,6 +208,7 @@ static struct variant_data variant_qcom = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
.init = qcom_variant_init,
};
/* Busy detection for the ST Micro variant */
......@@ -489,7 +418,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
static void mmci_dma_setup(struct mmci_host *host)
{
const char *rxname, *txname;
struct variant_data *variant = host->variant;
host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
......@@ -537,9 +465,8 @@ static void mmci_dma_setup(struct mmci_host *host)
host->mmc->max_seg_size = max_seg_size;
}
if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel)
if (dml_hw_init(host, host->mmc->parent->of_node))
variant->qcom_dml = false;
if (host->ops && host->ops->dma_setup)
host->ops->dma_setup(host);
}
/*
......@@ -1706,6 +1633,9 @@ static int mmci_probe(struct amba_device *dev,
goto clk_disable;
}
if (variant->init)
variant->init(host);
/*
* The ARM and ST versions of the block have slightly different
* clock divider equations which means that the minimum divider
......
......@@ -195,8 +195,86 @@
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
struct clk;
struct variant_data;
struct dma_chan;
struct mmci_host;
/**
* struct variant_data - MMCI variant-specific quirks
* @clkreg: default value for MCICLOCK register
* @clkreg_enable: enable value for MMCICLOCK register
* @clkreg_8bit_bus_enable: enable value for 8 bit bus
* @clkreg_neg_edge_enable: enable value for inverted data/cmd output
* @datalength_bits: number of bits in the MMCIDATALENGTH register
* @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
* is asserted (likewise for RX)
* @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
* is asserted (likewise for RX)
* @data_cmd_enable: enable value for data commands.
* @st_sdio: enable ST specific SDIO logic
* @st_clkdiv: true if using a ST-specific clock divider algorithm
* @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
* register
* @datactrl_mask_sdio: SDIO enable mask in datactrl register
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
* @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
* @busy_detect: true if the variant supports busy detection on DAT0.
* @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
* @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
* indicating that the card is busy
* @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
* getting busy end detection interrupts
* @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
* @explicit_mclk_control: enable explicit mclk control in driver.
* @qcom_fifo: enables qcom specific fifo pio read logic.
* @qcom_dml: enables qcom specific dma glue for dma transfers.
* @reversed_irq_handling: handle data irq before cmd irq.
* @mmcimask1: true if variant have a MMCIMASK1 register.
* @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
*/
struct variant_data {
unsigned int clkreg;
unsigned int clkreg_enable;
unsigned int clkreg_8bit_bus_enable;
unsigned int clkreg_neg_edge_enable;
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;
unsigned int data_cmd_enable;
unsigned int datactrl_mask_ddrmode;
unsigned int datactrl_mask_sdio;
bool st_sdio;
bool st_clkdiv;
bool blksz_datactrl16;
bool blksz_datactrl4;
u32 pwrreg_powerup;
u32 f_max;
bool signal_direction;
bool pwrreg_clkgate;
bool busy_detect;
u32 busy_dpsm_flag;
u32 busy_detect_flag;
u32 busy_detect_mask;
bool pwrreg_nopower;
bool explicit_mclk_control;
bool qcom_fifo;
bool qcom_dml;
bool reversed_irq_handling;
bool mmcimask1;
u32 start_err;
u32 opendrain;
void (*init)(struct mmci_host *host);
};
/* mmci variant callbacks */
struct mmci_host_ops {
void (*dma_setup)(struct mmci_host *host);
};
struct mmci_host_next {
struct dma_async_tx_descriptor *dma_desc;
......@@ -228,6 +306,7 @@ struct mmci_host {
u32 mask1_reg;
bool vqmmc_enabled;
struct mmci_platform_data *plat;
struct mmci_host_ops *ops;
struct variant_data *variant;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
......
......@@ -119,17 +119,20 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name)
}
/* Initialize the dml hardware connected to SD Card controller */
int dml_hw_init(struct mmci_host *host, struct device_node *np)
static void qcom_dma_setup(struct mmci_host *host)
{
u32 config;
void __iomem *base;
int consumer_id, producer_id;
struct device_node *np = host->mmc->parent->of_node;
consumer_id = of_get_dml_pipe_index(np, "tx");
producer_id = of_get_dml_pipe_index(np, "rx");
if (producer_id < 0 || consumer_id < 0)
return -ENODEV;
if (producer_id < 0 || consumer_id < 0) {
host->variant->qcom_dml = false;
return;
}
base = host->base + DML_OFFSET;
......@@ -172,6 +175,13 @@ int dml_hw_init(struct mmci_host *host, struct device_node *np)
/* Make sure dml initialization is finished */
mb();
}
return 0;
static struct mmci_host_ops qcom_variant_ops = {
.dma_setup = qcom_dma_setup,
};
void qcom_variant_init(struct mmci_host *host)
{
host->ops = &qcom_variant_ops;
}
......@@ -16,12 +16,11 @@
#define __MMC_QCOM_DML_H__
#ifdef CONFIG_MMC_QCOM_DML
int dml_hw_init(struct mmci_host *host, struct device_node *np);
void qcom_variant_init(struct mmci_host *host);
void dml_start_xfer(struct mmci_host *host, struct mmc_data *data);
#else
static inline int dml_hw_init(struct mmci_host *host, struct device_node *np)
static inline void qcom_variant_init(struct mmci_host *host)
{
return -ENOSYS;
}
static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
{
......
......@@ -58,11 +58,11 @@ struct pxamci_host {
void __iomem *base;
struct clk *clk;
unsigned long clkrate;
int irq;
unsigned int clkrt;
unsigned int cmdat;
unsigned int imask;
unsigned int power_mode;
unsigned long detect_delay_ms;
struct pxamci_platform_data *pdata;
struct mmc_request *mrq;
......@@ -72,64 +72,48 @@ struct pxamci_host {
struct dma_chan *dma_chan_rx;
struct dma_chan *dma_chan_tx;
dma_cookie_t dma_cookie;
dma_addr_t sg_dma;
unsigned int dma_len;
unsigned int dma_dir;
unsigned int dma_drcmrrx;
unsigned int dma_drcmrtx;
struct regulator *vcc;
};
static inline void pxamci_init_ocr(struct pxamci_host *host)
static int pxamci_init_ocr(struct pxamci_host *host)
{
#ifdef CONFIG_REGULATOR
host->vcc = devm_regulator_get_optional(mmc_dev(host->mmc), "vmmc");
if (IS_ERR(host->vcc))
host->vcc = NULL;
else {
host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
if (host->pdata && host->pdata->ocr_mask)
dev_warn(mmc_dev(host->mmc),
"ocr_mask/setpower will not be used\n");
}
#endif
if (host->vcc == NULL) {
struct mmc_host *mmc = host->mmc;
int ret;
ret = mmc_regulator_get_supply(mmc);
if (ret < 0)
return ret;
if (IS_ERR(mmc->supply.vmmc)) {
/* fall-back to platform data */
host->mmc->ocr_avail = host->pdata ?
mmc->ocr_avail = host->pdata ?
host->pdata->ocr_mask :
MMC_VDD_32_33 | MMC_VDD_33_34;
}
return 0;
}
static inline int pxamci_set_power(struct pxamci_host *host,
unsigned char power_mode,
unsigned int vdd)
{
struct mmc_host *mmc = host->mmc;
struct regulator *supply = mmc->supply.vmmc;
int on;
if (host->vcc) {
int ret;
if (!IS_ERR(supply))
return mmc_regulator_set_ocr(mmc, supply, vdd);
if (power_mode == MMC_POWER_UP) {
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
if (ret)
return ret;
} else if (power_mode == MMC_POWER_OFF) {
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
if (ret)
return ret;
}
}
if (!host->vcc && host->pdata &&
if (host->pdata &&
gpio_is_valid(host->pdata->gpio_power)) {
on = ((1 << vdd) & host->pdata->ocr_mask);
gpio_set_value(host->pdata->gpio_power,
!!on ^ host->pdata->gpio_power_invert);
}
if (!host->vcc && host->pdata && host->pdata->setpower)
if (host->pdata && host->pdata->setpower)
return host->pdata->setpower(mmc_dev(host->mmc), vdd);
return 0;
......@@ -584,7 +568,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid)
{
struct pxamci_host *host = mmc_priv(devid);
mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms));
mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms));
return IRQ_HANDLED;
}
......@@ -596,37 +580,30 @@ static const struct of_device_id pxa_mmc_dt_ids[] = {
MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
static int pxamci_of_init(struct platform_device *pdev)
static int pxamci_of_init(struct platform_device *pdev,
struct mmc_host *mmc)
{
struct device_node *np = pdev->dev.of_node;
struct pxamci_platform_data *pdata;
u32 tmp;
if (!np)
return 0;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
struct device_node *np = pdev->dev.of_node;
struct pxamci_host *host = mmc_priv(mmc);
u32 tmp;
int ret;
pdata->gpio_card_detect =
of_get_named_gpio(np, "cd-gpios", 0);
pdata->gpio_card_ro =
of_get_named_gpio(np, "wp-gpios", 0);
if (!np)
return 0;
/* pxa-mmc specific */
pdata->gpio_power =
of_get_named_gpio(np, "pxa-mmc,gpio-power", 0);
if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0)
pdata->detect_delay_ms = tmp;
host->detect_delay_ms = tmp;
pdev->dev.platform_data = pdata;
ret = mmc_of_parse(mmc);
if (ret < 0)
return ret;
return 0;
return 0;
}
#else
static int pxamci_of_init(struct platform_device *pdev)
static int pxamci_of_init(struct platform_device *pdev,
struct mmc_host *mmc)
{
return 0;
}
......@@ -636,19 +613,16 @@ static int pxamci_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
struct pxamci_host *host = NULL;
struct device *dev = &pdev->dev;
struct resource *r;
int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
ret = pxamci_of_init(pdev);
if (ret)
return ret;
int ret, irq;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev);
if (!mmc) {
ret = -ENOMEM;
goto out;
......@@ -677,12 +651,16 @@ static int pxamci_probe(struct platform_device *pdev)
*/
mmc->max_blk_count = 65535;
ret = pxamci_of_init(pdev, mmc);
if (ret)
return ret;
host = mmc_priv(mmc);
host->mmc = mmc;
host->pdata = pdev->dev.platform_data;
host->clkrt = CLKRT_OFF;
host->clk = devm_clk_get(&pdev->dev, NULL);
host->clk = devm_clk_get(dev, NULL);
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
host->clk = NULL;
......@@ -697,7 +675,9 @@ static int pxamci_probe(struct platform_device *pdev)
mmc->f_min = (host->clkrate + 63) / 64;
mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate;
pxamci_init_ocr(host);
ret = pxamci_init_ocr(host);
if (ret < 0)
return ret;
mmc->caps = 0;
host->cmdat = 0;
......@@ -711,10 +691,9 @@ static int pxamci_probe(struct platform_device *pdev)
spin_lock_init(&host->lock);
host->res = r;
host->irq = irq;
host->imask = MMC_I_MASK_ALL;
host->base = devm_ioremap_resource(&pdev->dev, r);
host->base = devm_ioremap_resource(dev, r);
if (IS_ERR(host->base)) {
ret = PTR_ERR(host->base);
goto out;
......@@ -729,69 +708,76 @@ static int pxamci_probe(struct platform_device *pdev)
writel(64, host->base + MMC_RESTO);
writel(host->imask, host->base + MMC_I_MASK);
ret = devm_request_irq(&pdev->dev, host->irq, pxamci_irq, 0,
ret = devm_request_irq(dev, irq, pxamci_irq, 0,
DRIVER_NAME, host);
if (ret)
goto out;
platform_set_drvdata(pdev, mmc);
host->dma_chan_rx = dma_request_slave_channel(&pdev->dev, "rx");
host->dma_chan_rx = dma_request_slave_channel(dev, "rx");
if (host->dma_chan_rx == NULL) {
dev_err(&pdev->dev, "unable to request rx dma channel\n");
dev_err(dev, "unable to request rx dma channel\n");
ret = -ENODEV;
goto out;
}
host->dma_chan_tx = dma_request_slave_channel(&pdev->dev, "tx");
host->dma_chan_tx = dma_request_slave_channel(dev, "tx");
if (host->dma_chan_tx == NULL) {
dev_err(&pdev->dev, "unable to request tx dma channel\n");
dev_err(dev, "unable to request tx dma channel\n");
ret = -ENODEV;
goto out;
}
if (host->pdata) {
gpio_cd = host->pdata->gpio_card_detect;
gpio_ro = host->pdata->gpio_card_ro;
gpio_power = host->pdata->gpio_power;
}
if (gpio_is_valid(gpio_power)) {
ret = devm_gpio_request(&pdev->dev, gpio_power,
"mmc card power");
if (ret) {
dev_err(&pdev->dev, "Failed requesting gpio_power %d\n",
gpio_power);
goto out;
int gpio_cd = host->pdata->gpio_card_detect;
int gpio_ro = host->pdata->gpio_card_ro;
int gpio_power = host->pdata->gpio_power;
host->detect_delay_ms = host->pdata->detect_delay_ms;
if (gpio_is_valid(gpio_power)) {
ret = devm_gpio_request(dev, gpio_power,
"mmc card power");
if (ret) {
dev_err(dev,
"Failed requesting gpio_power %d\n",
gpio_power);
goto out;
}
gpio_direction_output(gpio_power,
host->pdata->gpio_power_invert);
}
gpio_direction_output(gpio_power,
host->pdata->gpio_power_invert);
}
if (gpio_is_valid(gpio_ro)) {
ret = mmc_gpio_request_ro(mmc, gpio_ro);
if (gpio_is_valid(gpio_ro)) {
ret = mmc_gpio_request_ro(mmc, gpio_ro);
if (ret) {
dev_err(dev,
"Failed requesting gpio_ro %d\n",
gpio_ro);
goto out;
} else {
mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
0 : MMC_CAP2_RO_ACTIVE_HIGH;
}
}
if (gpio_is_valid(gpio_cd))
ret = mmc_gpio_request_cd(mmc, gpio_cd, 0);
if (ret) {
dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n",
gpio_ro);
dev_err(dev, "Failed requesting gpio_cd %d\n",
gpio_cd);
goto out;
} else {
mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
0 : MMC_CAP2_RO_ACTIVE_HIGH;
}
}
if (gpio_is_valid(gpio_cd))
ret = mmc_gpio_request_cd(mmc, gpio_cd, 0);
if (ret) {
dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd);
goto out;
}
if (host->pdata && host->pdata->init)
host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
if (host->pdata->init)
host->pdata->init(dev, pxamci_detect_irq, mmc);
if (gpio_is_valid(gpio_power) && host->pdata->setpower)
dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n");
if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n");
if (gpio_is_valid(gpio_power) && host->pdata->setpower)
dev_warn(dev, "gpio_power and setpower() both defined\n");
if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
dev_warn(dev, "gpio_ro and get_ro() both defined\n");
}
mmc_add_host(mmc);
......@@ -812,18 +798,12 @@ static int pxamci_probe(struct platform_device *pdev)
static int pxamci_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
if (mmc) {
struct pxamci_host *host = mmc_priv(mmc);
mmc_remove_host(mmc);
if (host->pdata) {
gpio_cd = host->pdata->gpio_card_detect;
gpio_ro = host->pdata->gpio_card_ro;
gpio_power = host->pdata->gpio_power;
}
if (host->pdata && host->pdata->exit)
host->pdata->exit(&pdev->dev, mmc);
......@@ -839,6 +819,7 @@ static int pxamci_remove(struct platform_device *pdev)
mmc_free_host(mmc);
}
return 0;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment