diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-07 12:56:19 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-07 12:56:19 -0700 |
| commit | 01e5d1830cf54ac45768ef9ceb3e79cea2e1198c (patch) | |
| tree | 139cab6f6ea7e927d07e75028a74e7a98d554055 /drivers/mmc | |
| parent | b4b52b881cf08e13d110eac811d4becc0775abbf (diff) | |
| parent | 0a49a619e7e1aeb3f5f5511ca59314423c83dae2 (diff) | |
| download | linux-01e5d1830cf54ac45768ef9ceb3e79cea2e1198c.tar.gz linux-01e5d1830cf54ac45768ef9ceb3e79cea2e1198c.tar.bz2 linux-01e5d1830cf54ac45768ef9ceb3e79cea2e1198c.zip | |
Merge tag 'mmc-v5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"MMC core:
- Fix a few memoryleaks
- Minor improvements to the card initialization sequence
- Partially support sleepy GPIO controllers for pwrseq eMMC
MMC host:
- alcor: Work with multiple-entry sglists
- alcor: Enable DMA for writes
- meson-gx: Improve tuning support
- meson-gx: Avoid clock glitch when switching to DDR modes
- meson-gx: Disable unreliable HS400 mode
- mmci: Minor updates for support of HW busy detection
- mmci: Support data transfers for the stm32_sdmmc variant
- mmci: Restructure code to better support different variants
- mtk-sd: Add support for version found on MT7620 family SOCs
- mtk-sd: Add support for the MT8516 version
- mtk-sd: Add Chaotian Jing as the maintainer
- sdhci: Reorganize request-code to convert from tasklet to workqueue
- sdhci_am654: Stabilize support for lower speed modes
- sdhci-esdhc-imx: Add HS400 support for iMX7ULP
- sdhci-esdhc-imx: Add support for iMX7ULP version
- sdhci-of-arasan: Allow to disable DCMDs via DT for CQE
- sdhci-of-esdhc: Add support for the ls1028a version
- sdhci-of-esdhc: Several fixups for errata
- sdhci-pci: Fix BYT OCP setting
- sdhci-pci: Add support for Intel CML
- sdhci-tegra: Add support for system suspend/resume
- sdhci-tegra: Add CQE support for Tegra186 WAR
- sdhci-tegra: Add support for Tegra194
- sdhci-tegra: Update HW tuning process
MEMSTICK:
- I volunteered to help as a maintainer for the memstick subsystem,
which is reflected by an update to the MAINTAINERS file. Changes
are funneled through my MMC git and we will use the linux-mmc
mailing list.
MEMSTICK host:
- A few minor cleanups"
* tag 'mmc-v5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (87 commits)
mmc: sdhci-pci: Fix BYT OCP setting
dt-bindings: mmc: add DT bindings for ls1028a eSDHC host controller
mmc: alcor: Drop pointer to mmc_host from alcor_sdmmc_host
mmc: mtk-sd: select REGULATOR
mmc: mtk-sd: enable internal card-detect logic.
mmc: mtk-sd: add support for config found in mt7620 family SOCs.
mmc: mtk-sd: don't hard-code interrupt trigger type
mmc: core: Fix tag set memory leak
dt-bindings: mmc: Add support for MT8516 to mtk-sd
mmc: mmci: Prevent polling for busy detection in IRQ context
mmc: mmci: Cleanup mmci_cmd_irq() for busy detect
mmc: usdhi6rol0: mark expected switch fall-throughs
mmc: core: Verify SD bus width
mmc: sdhci-esdhc-imx: Add HS400 support for iMX7ULP
mmc: sdhci-esdhc-imx: add pm_qos to interact with cpuidle
dt-bindings: mmc: fsl-imx-esdhc: add imx7ulp compatible string
mmc: meson-gx: add signal resampling tuning
mmc: meson-gx: remove Rx phase tuning
mmc: meson-gx: avoid clock glitch when switching to DDR modes
mmc: meson-gx: disable HS400
...
Diffstat (limited to 'drivers/mmc')
37 files changed, 1146 insertions, 650 deletions
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 3a4402a79904..6a51f7a06ce7 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -363,11 +363,11 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask) int num_ranges, i; voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); - num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; if (!voltage_ranges) { pr_debug("%pOF: voltage-ranges unspecified\n", np); return 0; } + num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; if (!num_ranges) { pr_err("%pOF: voltage-ranges empty\n", np); return -EINVAL; @@ -429,8 +429,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) if (mmc_gpio_alloc(host)) { put_device(&host->class_dev); - ida_simple_remove(&mmc_host_ida, host->index); - kfree(host); return NULL; } diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index c5208fb312ae..a533cab8fccc 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -184,11 +184,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) if (err) break; - /* if we're just probing, do a single pass */ - if (ocr == 0) - break; - - /* otherwise wait until reset completes */ + /* wait until reset completes */ if (mmc_host_is_spi(host)) { if (!(cmd.resp[0] & R1_SPI_IDLE)) break; @@ -200,6 +196,16 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) err = -ETIMEDOUT; mmc_delay(10); + + /* + * According to eMMC specification v5.1 section 6.4.3, we + * should issue CMD1 repeatedly in the idle state until + * the eMMC is ready. Otherwise some eMMC devices seem to enter + * the inactive mode after mmc_init_card() issued CMD0 when + * the eMMC device is busy. + */ + if (!ocr && !mmc_host_is_spi(host)) + cmd.arg = cmd.resp[0] | BIT(30); } if (rocr && !mmc_host_is_spi(host)) diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index efb8a7965dd4..154f4204d58c 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -30,19 +30,14 @@ struct mmc_pwrseq_emmc { #define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq) -static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) -{ - gpiod_set_value(pwrseq->reset_gpio, 1); - udelay(1); - gpiod_set_value(pwrseq->reset_gpio, 0); - udelay(200); -} - static void mmc_pwrseq_emmc_reset(struct mmc_host *host) { struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq); - __mmc_pwrseq_emmc_reset(pwrseq); + gpiod_set_value_cansleep(pwrseq->reset_gpio, 1); + udelay(1); + gpiod_set_value_cansleep(pwrseq->reset_gpio, 0); + udelay(200); } static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, @@ -50,8 +45,11 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, { struct mmc_pwrseq_emmc *pwrseq = container_of(this, struct mmc_pwrseq_emmc, reset_nb); + gpiod_set_value(pwrseq->reset_gpio, 1); + udelay(1); + gpiod_set_value(pwrseq->reset_gpio, 0); + udelay(200); - __mmc_pwrseq_emmc_reset(pwrseq); return NOTIFY_DONE; } @@ -72,14 +70,18 @@ static int mmc_pwrseq_emmc_probe(struct platform_device *pdev) if (IS_ERR(pwrseq->reset_gpio)) return PTR_ERR(pwrseq->reset_gpio); - /* - * register reset handler to ensure emmc reset also from - * emergency_reboot(), priority 255 is the highest priority - * so it will be executed before any system reboot handler. - */ - pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; - pwrseq->reset_nb.priority = 255; - register_restart_handler(&pwrseq->reset_nb); + if (!gpiod_cansleep(pwrseq->reset_gpio)) { + /* + * register reset handler to ensure emmc reset also from + * emergency_reboot(), priority 255 is the highest priority + * so it will be executed before any system reboot handler. + */ + pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb; + pwrseq->reset_nb.priority = 255; + register_restart_handler(&pwrseq->reset_nb); + } else { + dev_notice(dev, "EMMC reset pin tied to a sleepy GPIO driver; reset on emergency-reboot disabled\n"); + } pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; pwrseq->pwrseq.dev = dev; diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 7c364a9c4eeb..b5b9c6142f08 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -472,6 +472,7 @@ void mmc_cleanup_queue(struct mmc_queue *mq) blk_mq_unquiesce_queue(q); blk_cleanup_queue(q); + blk_mq_free_tag_set(&mq->tag_set); /* * A request can be completed before the next request, potentially diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 265e1aeeb9d8..d3d32f9a2cb1 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -221,6 +221,14 @@ static int mmc_decode_scr(struct mmc_card *card) if (scr->sda_spec3) scr->cmds = UNSTUFF_BITS(resp, 32, 2); + + /* SD Spec says: any SD Card shall set at least bits 0 and 2 */ + if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) || + !(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) { + pr_err("%s: invalid bus width\n", mmc_hostname(card->host)); + return -EINVAL; + } + return 0; } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 28fcd8f580a1..0e86340536b6 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -92,6 +92,7 @@ config MMC_SDHCI_PCI tristate "SDHCI support on PCI bus" depends on MMC_SDHCI && PCI select MMC_CQHCI + select IOSF_MBI if X86 help This selects the PCI Secure Digital Host Controller Interface. Most controllers found today are PCI devices. @@ -437,7 +438,7 @@ config MMC_WBSD depends on ISA_DMA_API help This selects the Winbond(R) W83L51xD Secure digital and - Multimedia card Interface. + Multimedia card Interface. If you have a machine with a integrated W83L518D or W83L519D SD/MMC card reader, say Y or M here. @@ -515,7 +516,7 @@ config MMC_TIFM_SD 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support (TIFM_7XX1)'. - To compile this driver as a module, choose M here: the + To compile this driver as a module, choose M here: the module will be called tifm_sd. config MMC_MVSDIO @@ -531,12 +532,12 @@ config MMC_MVSDIO module will be called mvsdio. config MMC_DAVINCI - tristate "TI DAVINCI Multimedia Card Interface support" - depends on ARCH_DAVINCI - help - This selects the TI DAVINCI Multimedia card Interface. - If you have an DAVINCI board with a Multimedia Card slot, - say Y or M here. If unsure, say N. + tristate "TI DAVINCI Multimedia Card Interface support" + depends on ARCH_DAVINCI + help + This selects the TI DAVINCI Multimedia card Interface. + If you have an DAVINCI board with a Multimedia Card slot, + say Y or M here. If unsure, say N. config MMC_GOLDFISH tristate "goldfish qemu Multimedia Card Interface support" @@ -565,18 +566,18 @@ config MMC_S3C depends on S3C24XX_DMAC help This selects a driver for the MCI interface found in - Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. + Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. If you have a board based on one of those and a MMC/SD slot, say Y or M here. If unsure, say N. config MMC_S3C_HW_SDIO_IRQ - bool "Hardware support for SDIO IRQ" - depends on MMC_S3C - help - Enable the hardware support for SDIO interrupts instead of using - the generic polling code. + bool "Hardware support for SDIO IRQ" + depends on MMC_S3C + help + Enable the hardware support for SDIO interrupts instead of using + the generic polling code. choice prompt "Samsung S3C SD/MMC transfer code" @@ -941,6 +942,7 @@ config MMC_BCM2835 config MMC_MTK tristate "MediaTek SD/MMC Card Interface support" depends on HAS_DMA + select REGULATOR help This selects the MediaTek(R) Secure digital and Multimedia card Interface. If you have a machine with a integrated SD/MMC card reader, say Y or M here. @@ -948,15 +950,16 @@ config MMC_MTK If unsure, say N. config MMC_SDHCI_MICROCHIP_PIC32 - tristate "Microchip PIC32MZDA SDHCI support" - depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM - help - This selects the Secure Digital Host Controller Interface (SDHCI) - for PIC32MZDA platform. + tristate "Microchip PIC32MZDA SDHCI support" + depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM + help + This selects the Secure Digital Host Controller Interface (SDHCI) + for PIC32MZDA platform. - If you have a controller with this interface, say Y or M here. + If you have a controller with this interface, say Y or M here. + + If unsure, say N. - If unsure, say N. config MMC_SDHCI_BRCMSTB tristate "Broadcom SDIO/SD/MMC support" depends on ARCH_BRCMSTB || BMIPS_GENERIC @@ -993,6 +996,7 @@ config MMC_SDHCI_OMAP config MMC_SDHCI_AM654 tristate "Support for the SDHCI Controller in TI's AM654 SOCs" depends on MMC_SDHCI_PLTFM && OF + select MMC_SDHCI_IO_ACCESSORS help This selects the Secure Digital Host Controller Interface (SDHCI) support present in TI's AM654 SOCs. The controller supports diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c index 6e6b7ade4b60..e481535cba2b 100644 --- a/drivers/mmc/host/alcor.c +++ b/drivers/mmc/host/alcor.c @@ -43,7 +43,6 @@ struct alcor_sdmmc_host { struct device *dev; struct alcor_pci_priv *alcor_pci; - struct mmc_host *mmc; struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; @@ -117,6 +116,9 @@ static void alcor_reset(struct alcor_sdmmc_host *host, u8 val) dev_err(host->dev, "%s: timeout\n", __func__); } +/* + * Perform DMA I/O of a single page. + */ static void alcor_data_set_dma(struct alcor_sdmmc_host *host) { struct alcor_pci_priv *priv = host->alcor_pci; @@ -153,12 +155,26 @@ static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host) ctrl |= AU6601_DATA_WRITE; if (data->host_cookie == COOKIE_MAPPED) { + /* + * For DMA transfers, this function is called just once, + * at the start of the operation. The hardware can only + * perform DMA I/O on a single page at a time, so here + * we kick off the transfer with the first page, and expect + * subsequent pages to be transferred upon IRQ events + * indicating that the single-page DMA was completed. + */ alcor_data_set_dma(host); ctrl |= AU6601_DATA_DMA_MODE; host->dma_on = 1; alcor_write32(priv, data->sg_count * 0x1000, AU6601_REG_BLOCK_SIZE); } else { + /* + * For PIO transfers, we break down each operation + * into several sector-sized transfers. When one sector has + * complete, the IRQ handler will call this function again + * to kick off the transfer of the next sector. + */ alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE); } @@ -276,7 +292,7 @@ static void alcor_send_cmd(struct alcor_sdmmc_host *host, break; default: dev_err(host->dev, "%s: cmd->flag (0x%02x) is not valid\n", - mmc_hostname(host->mmc), mmc_resp_type(cmd)); + mmc_hostname(mmc_from_priv(host)), mmc_resp_type(cmd)); break; } @@ -317,7 +333,7 @@ static void alcor_request_complete(struct alcor_sdmmc_host *host, host->data = NULL; host->dma_on = 0; - mmc_request_done(host->mmc, mrq); + mmc_request_done(mmc_from_priv(host), mrq); } static void alcor_finish_data(struct alcor_sdmmc_host *host) @@ -547,7 +563,7 @@ static void alcor_cd_irq(struct alcor_sdmmc_host *host, u32 intmask) alcor_request_complete(host, 1); } - mmc_detect_change(host->mmc, msecs_to_jiffies(1)); + mmc_detect_change(mmc_from_priv(host), msecs_to_jiffies(1)); } static irqreturn_t alcor_irq_thread(int irq, void *d) @@ -771,12 +787,17 @@ static void alcor_pre_req(struct mmc_host *mmc, data->host_cookie = COOKIE_UNMAPPED; /* FIXME: looks like the DMA engine works only with CMD18 */ - if (cmd->opcode != 18) + if (cmd->opcode != MMC_READ_MULTIPLE_BLOCK + && cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK) return; /* * We don't do DMA on "complex" transfers, i.e. with - * non-word-aligned buffers or lengths. Also, we don't bother - * with all the DMA setup overhead for short transfers. + * non-word-aligned buffers or lengths. A future improvement + * could be made to use temporary DMA bounce-buffers when these + * requirements are not met. + * + * Also, we don't bother with all the DMA setup overhead for + * short transfers. */ if (data->blocks * data->blksz < AU6601_MAX_DMA_BLOCK_SIZE) return; @@ -787,6 +808,8 @@ static void alcor_pre_req(struct mmc_host *mmc, for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE) return; + if (sg->offset != 0) + return; } /* This data might be unmapped at this time */ @@ -1024,7 +1047,7 @@ static void alcor_hw_uninit(struct alcor_sdmmc_host *host) static void alcor_init_mmc(struct alcor_sdmmc_host *host) { - struct mmc_host *mmc = host->mmc; + struct mmc_host *mmc = mmc_from_priv(host); mmc->f_min = AU6601_MIN_CLOCK; mmc->f_max = AU6601_MAX_CLOCK; @@ -1036,26 +1059,21 @@ static void alcor_init_mmc(struct alcor_sdmmc_host *host) mmc->ops = &alcor_sdc_ops; /* The hardware does DMA data transfer of 4096 bytes to/from a single - * buffer address. Scatterlists are not supported, but upon DMA - * completion (signalled via IRQ), the original vendor driver does - * then immediately set up another DMA transfer of the next 4096 - * bytes. - * - * This means that we need to handle the I/O in 4096 byte chunks. - * Lacking a way to limit the sglist entries to 4096 bytes, we instead - * impose that only one segment is provided, with maximum size 4096, - * which also happens to be the minimum size. This means that the - * single-entry sglist handled by this driver can be handed directly - * to the hardware, nice and simple. + * buffer address. Scatterlists are not supported at the hardware + * level, however we can work with them at the driver level, + * provided that each segment is exactly 4096 bytes in size. + * Upon DMA completion of a single segment (signalled via IRQ), we + * immediately proceed to transfer the next segment from the + * scatterlist. * - * Unfortunately though, that means we only do 4096 bytes I/O per - * MMC command. A future improvement would be to make the driver - * accept sg lists and entries of any size, and simply iterate - * through them 4096 bytes at a time. + * The overall request is limited to 240 sectors, matching the + * original vendor driver. */ mmc->max_segs = AU6601_MAX_DMA_SEGMENTS; mmc->max_seg_size = AU6601_MAX_DMA_BLOCK_SIZE; - mmc->max_req_size = mmc->max_seg_size; + mmc->max_blk_count = 240; + mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; + dma_set_max_seg_size(host->dev, mmc->max_seg_size); } static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) @@ -1072,7 +1090,6 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) } host = mmc_priv(mmc); - host->mmc = mmc; host->dev = &pdev->dev; host->cur_power_mode = MMC_POWER_UNDEFINED; host->alcor_pci = priv; @@ -1104,13 +1121,14 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev) { struct alcor_sdmmc_host *host = dev_get_drvdata(&pdev->dev); + struct mmc_host *mmc = mmc_from_priv(host); if (cancel_delayed_work_sync(&host->timeout_work)) alcor_request_complete(host, 0); alcor_hw_uninit(host); - mmc_remove_host(host->mmc); - mmc_free_host(host->mmc); + mmc_remove_host(mmc); + mmc_free_host(mmc); return 0; } diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c index a8af682a9182..d59cb0a51964 100644 --- a/drivers/mmc/host/cqhci.c +++ b/drivers/mmc/host/cqhci.c @@ -537,6 +537,8 @@ static void cqhci_prep_dcmd_desc(struct mmc_host *mmc, CQHCI_ACT(0x5) | CQHCI_CMD_INDEX(mrq->cmd->opcode) | CQHCI_CMD_TIMING(timing) | CQHCI_RESP_TYPE(resp_type)); + if (cq_host->ops->update_dcmd_desc) + cq_host->ops->update_dcmd_desc(mmc, mrq, &data); *task_desc |= data; desc = (u8 *)task_desc; pr_debug("%s: cqhci: dcmd: cmd: %d timing: %d resp: %d\n", diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h index 9e68286a07b4..1e8e01d81015 100644 --- a/drivers/mmc/host/cqhci.h +++ b/drivers/mmc/host/cqhci.h @@ -88,6 +88,7 @@ /* send status config 1 */ #define CQHCI_SSC1 0x40 +#define CQHCI_SSC1_CBC_MASK GENMASK(19, 16) /* send status config 2 */ #define CQHCI_SSC2 0x44 @@ -147,6 +148,7 @@ struct cqhci_host_ops; struct mmc_host; +struct mmc_request; struct cqhci_slot; struct cqhci_host { @@ -210,6 +212,8 @@ struct cqhci_host_ops { u32 (*read_l)(struct cqhci_host *host, int reg); void (*enable)(struct mmc_host *mmc); void (*disable)(struct mmc_host *mmc, bool recovery); + void (*update_dcmd_desc)(struct mmc_host *mmc, struct mmc_request *mrq, + u64 *data); }; static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 2eba507790e4..c5a8af4ca76b 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/iopoll.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/ioport.h> @@ -48,6 +49,8 @@ #define CLK_CORE_PHASE_MASK GENMASK(9, 8) #define CLK_TX_PHASE_MASK GENMASK(11, 10) #define CLK_RX_PHASE_MASK GENMASK(13, 12) +#define CLK_PHASE_0 0 +#define CLK_PHASE_180 2 #define CLK_V2_TX_DELAY_MASK GENMASK(19, 16) #define CLK_V2_RX_DELAY_MASK GENMASK(23, 20) #define CLK_V2_ALWAYS_ON BIT(24) @@ -56,10 +59,6 @@ #define CLK_V3_RX_DELAY_MASK GENMASK(27, 22) #define CLK_V3_ALWAYS_ON BIT(28) -#define CLK_DELAY_STEP_PS 200 -#define CLK_PHASE_STEP 30 -#define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP) - #define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask) #define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask) #define CLK_ALWAYS_ON(h) (h->data->always_on) @@ -164,10 +163,10 @@ struct meson_host { void __iomem *regs; struct clk *core_clk; + struct clk *mux_clk; struct clk *mmc_clk; - struct clk *rx_clk; - struct clk *tx_clk; unsigned long req_rate; + bool ddr; struct pinctrl *pinctrl; struct pinctrl_state *pins_default; @@ -207,90 +206,6 @@ struct meson_host { #define CMD_RESP_MASK GENMASK(31, 1) #define CMD_RESP_SRAM BIT(0) -struct meson_mmc_phase { - struct clk_hw hw; - void __iomem *reg; - unsigned long phase_mask; - unsigned long delay_mask; - unsigned int delay_step_ps; -}; - -#define to_meson_mmc_phase(_hw) container_of(_hw, struct meson_mmc_phase, hw) - -static int meson_mmc_clk_get_phase(struct clk_hw *hw) -{ - struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); - unsigned int phase_num = 1 << hweight_long(mmc->phase_mask); - unsigned long period_ps, p, d; - int degrees; - u32 val; - - val = readl(mmc->reg); - p = (val & mmc->phase_mask) >> __ffs(mmc->phase_mask); - degrees = p * 360 / phase_num; - - if (mmc->delay_mask) { - period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, - clk_get_rate(hw->clk)); - d = (val & mmc->delay_mask) >> __ffs(mmc->delay_mask); - degrees += d * mmc->delay_step_ps * 360 / period_ps; - degrees %= 360; - } - - return degrees; -} - -static void meson_mmc_apply_phase_delay(struct meson_mmc_phase *mmc, - unsigned int phase, - unsigned int delay) -{ - u32 val; - - val = readl(mmc->reg); - val &= ~mmc->phase_mask; - val |= phase << __ffs(mmc->phase_mask); - - if (mmc->delay_mask) { - val &= ~mmc->delay_mask; - val |= delay << __ffs(mmc->delay_mask); - } - - writel(val, mmc->reg); -} - -static int meson_mmc_clk_set_phase(struct clk_hw *hw, int degrees) -{ - struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); - unsigned int phase_num = 1 << hweight_long(mmc->phase_mask); - unsigned long period_ps, d = 0, r; - uint64_t p; - - p = degrees % 360; - - if (!mmc->delay_mask) { - p = DIV_ROUND_CLOSEST_ULL(p, 360 / phase_num); - } else { - period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, - clk_get_rate(hw->clk)); - - /* First compute the phase index (p), the remainder (r) is the - * part we'll try to acheive using the delays (d). - */ - r = do_div(p, 360 / phase_num); - d = DIV_ROUND_CLOSEST(r * period_ps, - 360 * mmc->delay_step_ps); - d = min(d, mmc->delay_mask >> __ffs(mmc->delay_mask)); - } - - meson_mmc_apply_phase_delay(mmc, p, d); - return 0; -} - -static const struct clk_ops meson_mmc_clk_phase_ops = { - .get_phase = meson_mmc_clk_get_phase, - .set_phase = meson_mmc_clk_set_phase, -}; - static unsigned int meson_mmc_get_timeout_msecs(struct mmc_data *data) { unsigned int timeout = data->timeout_ns / NSEC_PER_MSEC; @@ -383,16 +298,6 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, mmc_get_dma_dir(data)); } -static bool meson_mmc_timing_is_ddr(struct mmc_ios *ios) -{ - if (ios->timing == MMC_TIMING_MMC_DDR52 || - ios->timing == MMC_TIMING_UHS_DDR50 || - ios->timing == MMC_TIMING_MMC_HS400) - return true; - - return false; -} - /* * Gating the clock on this controller is tricky. It seems the mmc clock * is also used by the controller. It may crash during some operation if the @@ -429,36 +334,41 @@ static void meson_mmc_clk_ungate(struct meson_host *host) writel(cfg, host->regs + SD_EMMC_CFG); } -static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) +static int meson_mmc_clk_set(struct meson_host *host, unsigned long rate, + bool ddr) { struct mmc_host *mmc = host->mmc; - unsigned long rate = ios->clock; int ret; u32 cfg; - /* DDR modes require higher module clock */ - if (meson_mmc_timing_is_ddr(ios)) - rate <<= 1; - /* Same request - bail-out */ - if (host->req_rate == rate) + if (host->ddr == ddr && host->req_rate == rate) return 0; /* stop clock */ meson_mmc_clk_gate(host); < |
