diff options
42 files changed, 885 insertions, 277 deletions
diff --git a/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt new file mode 100644 index 000000000000..a0693b7145f2 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/hi3798cv200-dw-mshc.txt @@ -0,0 +1,40 @@ +* Hisilicon Hi3798CV200 specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +Read synopsys-dw-mshc.txt for more details + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Hisilicon Hi3798CV200 +specific extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: +- compatible: Should contain "hisilicon,hi3798cv200-dw-mshc". +- clocks: A list of phandle + clock-specifier pairs for the clocks listed + in clock-names. +- clock-names: Should contain the following: + "ciu" - The ciu clock described in synopsys-dw-mshc.txt. + "biu" - The biu clock described in synopsys-dw-mshc.txt. + "ciu-sample" - Hi3798CV200 extended phase clock for ciu sampling. + "ciu-drive" - Hi3798CV200 extended phase clock for ciu driving. + +Example: + + emmc: mmc@9830000 { + compatible = "hisilicon,hi3798cv200-dw-mshc"; + reg = <0x9830000 0x10000>; + interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg HISTB_MMC_CIU_CLK>, + <&crg HISTB_MMC_BIU_CLK>, + <&crg HISTB_MMC_SAMPLE_CLK>, + <&crg HISTB_MMC_DRV_CLK>; + clock-names = "ciu", "biu", "ciu-sample", "ciu-drive"; + fifo-depth = <256>; + clock-frequency = <200000000>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + non-removable; + bus-width = <8>; + }; diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt index 9b8017670870..f33467a54a05 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.txt +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.txt @@ -12,6 +12,7 @@ Required properties: "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173 "mediatek,mt2701-mmc": for mmc host ip compatible with mt2701 "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712 + "mediatek,mt7622-mmc": for MT7622 SoC "mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC - reg: physical base address of the controller and length diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt index ef3e5f14067a..7e5e427a22ce 100644 --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt @@ -59,15 +59,6 @@ Optional properties: is specified and the ciu clock is specified then we'll try to set the ciu clock to this at probe time. -* clock-freq-min-max (DEPRECATED): Minimum and Maximum clock frequency for card output - clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default. - (Use the "max-frequency" instead of "clock-freq-min-max".) - -* num-slots (DEPRECATED): specifies the number of slots supported by the controller. - The number of physical slots actually used could be equal or less than the - value specified by num-slots. If this property is not specified, the value - of num-slot property is assumed to be 1. - * fifo-depth: The maximum size of the tx/rx fifo's. If this property is not specified, the default value of the fifo size is determined from the controller registers. diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt index d8685cb83325..2d5287eeed95 100644 --- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt +++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt @@ -50,7 +50,6 @@ Required properties: 2: R7S72100 Optional properties: -- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable - pinctrl-names: should be "default", "state_uhs" - pinctrl-0: should contain default/high speed pin ctrl - pinctrl-1: should contain uhs mode pin ctrl diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi index 7cae9c5e27db..10b8249b8ab6 100644 --- a/arch/arm/boot/dts/lpc18xx.dtsi +++ b/arch/arm/boot/dts/lpc18xx.dtsi @@ -115,7 +115,6 @@ compatible = "snps,dw-mshc"; reg = <0x40004000 0x1000>; interrupts = <6>; - num-slots = <1>; clocks = <&ccu2 CLK_SDIO>, <&ccu1 CLK_CPU_SDIO>; clock-names = "ciu", "biu"; resets = <&rgu 20>; diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts index 040a164ba148..5822fd2085db 100644 --- a/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts +++ b/arch/arm/boot/dts/socfpga_arria10_socdk_sdmmc.dts @@ -20,7 +20,6 @@ &mmc { status = "okay"; - num-slots = <1>; cap-sd-highspeed; broken-cd; bus-width = <4>; diff --git a/arch/arm/boot/dts/socfpga_arria5.dtsi b/arch/arm/boot/dts/socfpga_arria5.dtsi index 8c037297296c..e59461f5416e 100644 --- a/arch/arm/boot/dts/socfpga_arria5.dtsi +++ b/arch/arm/boot/dts/socfpga_arria5.dtsi @@ -30,7 +30,6 @@ }; mmc0: dwmmc0@ff704000 { - num-slots = <1>; broken-cd; bus-width = <4>; cap-mmc-highspeed; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi index a05e3df23103..68ced67f8bfb 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi +++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi @@ -31,7 +31,6 @@ }; mmc0: dwmmc0@ff704000 { - num-slots = <1>; broken-cd; bus-width = <4>; cap-mmc-highspeed; diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index dfe2193cd4d5..547c38632c68 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -42,7 +42,6 @@ }; dwmmc0@ff704000 { - num-slots = <1>; broken-cd; bus-width = <4>; cap-mmc-highspeed; diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts index 000756429b77..51ce5832ee1d 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts @@ -88,7 +88,6 @@ &mmc { status = "okay"; - num-slots = <1>; cap-sd-highspeed; broken-cd; bus-width = <4>; diff --git a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi index 63d4f9dca77f..a7ecd9074ea2 100644 --- a/arch/arm64/boot/dts/hisilicon/hi3660.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi3660.dtsi @@ -922,7 +922,6 @@ #size-cells = <0>; cd-inverted; compatible = "hisilicon,hi3660-dw-mshc"; - num-slots = <1>; bus-width = <0x4>; disable-wp; cap-sd-highspeed; @@ -960,7 +959,6 @@ compatible = "hisilicon,hi3660-dw-mshc"; reg = <0x0 0xff3ff000 0x0 0x1000>; interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; - num-slots = <1>; clocks = <&crg_ctrl HI3660_CLK_GATE_SDIO0>, <&crg_ctrl HI3660_HCLK_GATE_SDIO0>; clock-names = "ciu", "biu"; diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 5deb2d82f19f..6af7777332fc 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -375,8 +375,8 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = { static struct tmio_mmc_data sh7724_sdhi0_data = { .chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX, .chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX, - .flags = TMIO_MMC_WRPROTECT_DISABLE, .capabilities = MMC_CAP_SDIO_IRQ, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, }; static struct platform_device kfr2r09_sh_sdhi0_device = { diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 2cfb963d9f37..a2b9c2500c4c 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -376,22 +376,15 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( return idata; } - idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL); - if (!idata->buf) { - err = -ENOMEM; + idata->buf = memdup_user((void __user *)(unsigned long) + idata->ic.data_ptr, idata->buf_bytes); + if (IS_ERR(idata->buf)) { + err = PTR_ERR(idata->buf); goto idata_err; } - if (copy_from_user(idata->buf, (void __user *)(unsigned long) - idata->ic.data_ptr, idata->buf_bytes)) { - err = -EFAULT; - goto copy_err; - } - return idata; -copy_err: - kfree(idata->buf); idata_err: kfree(idata); out: diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index c0ba6d8823b7..121ce50b6d5e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2369,7 +2369,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) return card->pref_erase; max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG); - if (mmc_can_trim(card)) { + if (max_discard && mmc_can_trim(card)) { max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG); if (max_trim < max_discard) max_discard = max_trim; @@ -2655,8 +2655,7 @@ void mmc_start_host(struct mmc_host *host) void mmc_stop_host(struct mmc_host *host) { if (host->slot.cd_irq >= 0) { - if (host->slot.cd_wake_enabled) - disable_irq_wake(host->slot.cd_irq); + mmc_gpio_set_cd_wake(host, false); disable_irq(host->slot.cd_irq); } diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 0f4a7d7b2626..d2275c5a2311 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -196,18 +196,7 @@ static int mmc_ios_show(struct seq_file *s, void *data) return 0; } - -static int mmc_ios_open(struct inode *inode, struct file *file) -{ - return single_open(file, mmc_ios_show, inode->i_private); -} - -static const struct file_operations mmc_ios_fops = { - .open = mmc_ios_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(mmc_ios); static int mmc_clock_opt_get(void *data, u64 *val) { @@ -254,6 +243,12 @@ void mmc_add_host_debugfs(struct mmc_host *host) if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops)) goto err_node; + if (!debugfs_create_x32("caps", S_IRUSR, root, &host->caps)) + goto err_node; + + if (!debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2)) + goto err_node; + if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host, &mmc_clock_fops)) goto err_node; diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h index 06ec19b5bf9f..4805438c02ff 100644 --- a/drivers/mmc/core/host.h +++ b/drivers/mmc/core/host.h @@ -56,7 +56,8 @@ static inline int mmc_host_uhs(struct mmc_host *host) return host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | - MMC_CAP_UHS_DDR50); + MMC_CAP_UHS_DDR50) && + host->caps & MMC_CAP_4_BIT_DATA; } static inline bool mmc_card_hs200(struct mmc_card *card) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 208a762b87ef..6f8ebd6caa4c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -792,6 +792,7 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); +MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en); static ssize_t mmc_fwrev_show(struct device *dev, @@ -848,6 +849,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_raw_rpmb_size_mult.attr, &dev_attr_rel_sectors.attr, &dev_attr_ocr.attr, + &dev_attr_rca.attr, &dev_attr_dsr.attr, &dev_attr_cmdq_en.attr, NULL, diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 62b84dd8f9fe..baf3d5da4ccb 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -291,8 +291,6 @@ static int mmc_read_switch(struct mmc_card *card) return 0; } - err = -EIO; - status = kmalloc(64, GFP_KERNEL); if (!status) return -ENOMEM; @@ -582,9 +580,6 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) int err; u8 *status; - if (!card->scr.sda_spec3) - return 0; - if (!(card->csd.cmdclass & CCC_SWITCH)) return 0; @@ -593,14 +588,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) return -ENOMEM; /* Set 4-bit bus width */ - if ((card->host->caps & MMC_CAP_4_BIT_DATA) && - (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { - err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); - if (err) - goto out; + err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); + if (err) + goto out; - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - } + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); /* * Select the bus speed mode depending on host @@ -676,6 +668,7 @@ MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr); +MMC_DEV_ATTR(rca, "0x%04x\n", card->rca); static ssize_t mmc_dsr_show(struct device *dev, @@ -709,6 +702,7 @@ static struct attribute *sd_std_attrs[] = { &dev_attr_oemid.attr, &dev_attr_serial.attr, &dev_attr_ocr.attr, + &dev_attr_rca.attr, &dev_attr_dsr.attr, NULL, }; @@ -1033,7 +1027,7 @@ retry: } /* Initialization sequence for UHS-I cards */ - if (rocr & SD_ROCR_S18A) { + if (rocr & SD_ROCR_S18A && mmc_host_uhs(host)) { err = mmc_sd_init_uhs_card(card); if (err) goto free_card; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index cc43687ca241..c599a628a387 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -518,11 +518,10 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) if (!card->scr.sda_spec3) return 0; - /* - * Switch to wider bus (if supported). - */ - if (card->host->caps & MMC_CAP_4_BIT_DATA) - err = sdio_enable_4bit_bus(card); + /* Switch to wider bus */ + err = sdio_enable_4bit_bus(card); + if (err) + goto out; /* Set the driver strength for the card */ sdio_select_driver_type(card); diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 7a2eaf8410a3..7ca7b99413f0 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -277,8 +277,8 @@ static void sdio_single_irq_set(struct mmc_card *card) * * Claim and activate the IRQ for the given SDIO function. The provided * handler will be called when that IRQ is asserted. The host is always - * claimed already when the handler is called so the handler must not - * call sdio_claim_host() nor sdio_release_host(). + * claimed already when the handler is called so the handler should not + * call sdio_claim_host() or sdio_release_host(). */ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler) { diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 3698b0576009..31f7dbb15668 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -149,11 +149,30 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) if (irq < 0) host->caps |= MMC_CAP_NEEDS_POLL; - else if ((host->caps & MMC_CAP_CD_WAKE) && !enable_irq_wake(irq)) - host->slot.cd_wake_enabled = true; } EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); +int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on) +{ + int ret = 0; + + if (!(host->caps & MMC_CAP_CD_WAKE) || + host->slot.cd_irq < 0 || + on == host->slot.cd_wake_enabled) + return 0; + + if (on) { + ret = enable_irq_wake(host->slot.cd_irq); + host->slot.cd_wake_enabled = !ret; + } else { + disable_irq_wake(host->slot.cd_irq); + host->slot.cd_wake_enabled = false; + } + + return ret; +} +EXPORT_SYMBOL(mmc_gpio_set_cd_wake); + /* Register an alternate interrupt service routine for * the card-detect GPIO. */ diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index b4fd5d48dd35..9589f9c9046f 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -699,6 +699,15 @@ config MMC_DW_EXYNOS Synopsys DesignWare Memory Card Interface driver. Select this option for platforms based on Exynos4 and Exynos5 SoC's. +config MMC_DW_HI3798CV200 + tristate "Hi3798CV200 specific extensions for Synopsys DW Memory Card Interface" + depends on MMC_DW + select MMC_DW_PLTFM + help + This selects support for HiSilicon Hi3798CV200 SoC specific extensions to the + Synopsys DesignWare Memory Card Interface driver. Select this option + for platforms based on HiSilicon Hi3798CV200 SoC. + config MMC_DW_K3 tristate "K3 specific extensions for Synopsys DW Memory Card Interface" depends on MMC_DW diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index f563cc0b7f93..6aead24879b4 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_MMC_CAVIUM_THUNDERX) += thunderx-mmc.o obj-$(CONFIG_MMC_DW) += dw_mmc.o obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o +obj-$(CONFIG_MMC_DW_HI3798CV200) += dw_mmc-hi3798cv200.o obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c new file mode 100644 index 000000000000..f9b333ff259e --- /dev/null +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 HiSilicon Technologies Co., Ltd. + */ + +#include <linux/clk.h> +#include <linux/mfd/syscon.h> +#include <linux/mmc/host.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#include "dw_mmc.h" +#include "dw_mmc-pltfm.h" + +#define ALL_INT_CLR 0x1ffff + +struct hi3798cv200_priv { + struct clk *sample_clk; + struct clk *drive_clk; +}; + +static void dw_mci_hi3798cv200_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ + struct hi3798cv200_priv *priv = host->priv; + u32 val; + + val = mci_readl(host, UHS_REG); + if (ios->timing == MMC_TIMING_MMC_DDR52 || + ios->timing == MMC_TIMING_UHS_DDR50) + val |= SDMMC_UHS_DDR; + else + val &= ~SDMMC_UHS_DDR; + mci_writel(host, UHS_REG, val); + + val = mci_readl(host, ENABLE_SHIFT); + if (ios->timing == MMC_TIMING_MMC_DDR52) + val |= SDMMC_ENABLE_PHASE; + else + val &= ~SDMMC_ENABLE_PHASE; + mci_writel(host, ENABLE_SHIFT, val); + + val = mci_readl(host, DDR_REG); + if (ios->timing == MMC_TIMING_MMC_HS400) + val |= SDMMC_DDR_HS400; + else + val &= ~SDMMC_DDR_HS400; + mci_writel(host, DDR_REG, val); + + if (ios->timing == MMC_TIMING_MMC_HS || + ios->timing == MMC_TIMING_LEGACY) + clk_set_phase(priv->drive_clk, 180); + else if (ios->timing == MMC_TIMING_MMC_HS200) + clk_set_phase(priv->drive_clk, 135); +} + +static int dw_mci_hi3798cv200_execute_tuning(struct dw_mci_slot *slot, + u32 opcode) +{ + int degrees[] = { 0, 45, 90, 135, 180, 225, 270, 315 }; + struct dw_mci *host = slot->host; + struct hi3798cv200_priv *priv = host->priv; + int raise_point = -1, fall_point = -1; + int err, prev_err = -1; + int found = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(degrees); i++) { + clk_set_phase(priv->sample_clk, degrees[i]); + mci_writel(host, RINTSTS, ALL_INT_CLR); + + err = mmc_send_tuning(slot->mmc, opcode, NULL); + if (!err) + found = 1; + + if (i > 0) { + if (err && !prev_err) + fall_point = i - 1; + if (!err && prev_err) + raise_point = i; + } + + if (raise_point != -1 && fall_point != -1) + goto tuning_out; + + prev_err = err; + err = 0; + } + +tuning_out: + if (found) { + if (raise_point == -1) + raise_point = 0; + if (fall_point == -1) + fall_point = ARRAY_SIZE(degrees) - 1; + if (fall_point < raise_point) { + if ((raise_point + fall_point) > + (ARRAY_SIZE(degrees) - 1)) + i = fall_point / 2; + else + i = (raise_point + ARRAY_SIZE(degrees) - 1) / 2; + } else { + i = (raise_point + fall_point) / 2; + } + + clk_set_phase(priv->sample_clk, degrees[i]); + dev_dbg(host->dev, "Tuning clk_sample[%d, %d], set[%d]\n", + raise_point, fall_point, degrees[i]); + } else { + dev_err(host->dev, "No valid clk_sample shift! use default\n"); + err = -EINVAL; + } + + mci_writel(host, RINTSTS, ALL_INT_CLR); + return err; +} + +static int dw_mci_hi3798cv200_init(struct dw_mci *host) +{ + struct hi3798cv200_priv *priv; + int ret; + + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->sample_clk = devm_clk_get(host->dev, "ciu-sample"); + if (IS_ERR(priv->sample_clk)) { + dev_err(host->dev, "failed to get ciu-sample clock\n"); + return PTR_ERR(priv->sample_clk); + } + + priv->drive_clk = devm_clk_get(host->dev, "ciu-drive"); + if (IS_ERR(priv->drive_clk)) { + dev_err(host->dev, "failed to get ciu-drive clock\n"); + return PTR_ERR(priv->drive_clk); + } + + ret = clk_prepare_enable(priv->sample_clk); + if (ret) { + dev_err(host->dev, "failed to enable ciu-sample clock\n"); + return ret; + } + + ret = clk_prepare_enable(priv->drive_clk); + if (ret) { + dev_err(host->dev, "failed to enable ciu-drive clock\n"); + goto disable_sample_clk; + } + + host->priv = priv; + return 0; + +disable_sample_clk: + clk_disable_unprepare(priv->sample_clk); + return ret; +} + +static const struct dw_mci_drv_data hi3798cv200_data = { + .init = dw_mci_hi3798cv200_init, + .set_ios = dw_mci_hi3798cv200_set_ios, + .execute_tuning = dw_mci_hi3798cv200_execute_tuning, +}; + +static int dw_mci_hi3798cv200_probe(struct platform_device *pdev) +{ + return dw_mci_pltfm_register(pdev, &hi3798cv200_data); +} + +static int dw_mci_hi3798cv200_remove(struct platform_device *pdev) +{ + struct dw_mci *host = platform_get_drvdata(pdev); + struct hi3798cv200_priv *priv = host->priv; + + clk_disable_unprepare(priv->drive_clk); + clk_disable_unprepare(priv->sample_clk); + + return dw_mci_pltfm_remove(pdev); +} + +static const struct of_device_id dw_mci_hi3798cv200_match[] = { + { .compatible = "hisilicon,hi3798cv200-dw-mshc", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dw_mci_hi3798cv200_match); +static struct platform_driver dw_mci_hi3798cv200_driver = { + .probe = dw_mci_hi3798cv200_probe, + .remove = dw_mci_hi3798cv200_remove, + .driver = { + .name = "dwmmc_hi3798cv200", + .of_match_table = dw_mci_hi3798cv200_match, + }, +}; +module_platform_driver(dw_mci_hi3798cv200_driver); + +MODULE_DESCRIPTION("HiSilicon Hi3798CV200 Specific DW-MSHC Driver Extension"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dwmmc_hi3798cv200"); diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c index ab8713297edb..3ad07d7b2c97 100644 --- a/drivers/mmc/host/dw_mmc-pci.c +++ b/drivers/mmc/host/dw_mmc-pci.c @@ -29,7 +29,6 @@ MMC_CAP_SDIO_IRQ) static struct dw_mci_board pci_board_data = { - .num_slots = 1, .caps = DW_MCI_CAPABILITIES, .bus_hz = 33 * 1000 * 1000, .detect_delay_ms = 200, |