^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for Synopsys DesignWare Cores Mobile Storage Host Controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2018 Synaptics Incorporated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author: Jisheng Zhang <jszhang@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/iopoll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/reset.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/sizes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "sdhci-pltfm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* DWCMSHC specific Mode Select value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define DWCMSHC_CTRL_HS400 0x7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define DWCMSHC_VER_ID 0x500
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define DWCMSHC_VER_TYPE 0x504
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define DWCMSHC_HOST_CTRL3 0x508
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define DWCMSHC_EMMC_CONTROL 0x52c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define DWCMSHC_EMMC_ATCTRL 0x540
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* Rockchip specific Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define DWCMSHC_EMMC_DLL_CTRL 0x800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define DWCMSHC_EMMC_DLL_RXCLK 0x804
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define DWCMSHC_EMMC_DLL_TXCLK 0x808
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define DWCMSHC_EMMC_DLL_STRBIN 0x80c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define DECMSHC_EMMC_DLL_CMDOUT 0x810
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define DWCMSHC_EMMC_DLL_STATUS0 0x840
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define DWCMSHC_EMMC_DLL_START BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define DWCMSHC_EMMC_DLL_START_POINT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define DWCMSHC_EMMC_DLL_INC 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define DLL_TXCLK_TAPNUM_DEFAULT 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define DLL_TXCLK_TAPNUM_90_DEGREES 0x9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define DLL_TXCLK_TAPNUM_FROM_SW BIT(24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define DLL_TXCLK_NO_INVERTER BIT(29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define DLL_STRBIN_TAPNUM_DEFAULT 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define DLL_STRBIN_DELAY_NUM_SEL BIT(26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define DLL_STRBIN_DELAY_NUM_OFFSET 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define DLL_STRBIN_DELAY_NUM_DEFAULT 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define DLL_RXCLK_NO_INVERTER BIT(29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define DWCMSHC_CARD_IS_EMMC BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define DWCMSHC_ENHANCED_STROBE BIT(8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define DLL_CMDOUT_SRC_CLK_NEG BIT(28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define DLL_LOCK_WO_TMOUT(x) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define ROCKCHIP_MAX_CLKS 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define BOUNDARY_OK(addr, len) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct dwcmshc_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct clk *bus_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) u32 cclk_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* Rockchip specified optional clocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct clk_bulk_data rockchip_clks[ROCKCHIP_MAX_CLKS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct reset_control *reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) int txclk_tapnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned int actual_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u32 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u32 acpi_en;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct dwcmshc_driver_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) const struct sdhci_pltfm_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u32 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define RK_PLATFROM BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define RK_DLL_CMD_OUT BIT(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define RK_RXCLK_NO_INVERTER BIT(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * If DMA addr spans 128MB boundary, we split the DMA transfer into two
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * so that each DMA transfer doesn't exceed the boundary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) dma_addr_t addr, int len, unsigned int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) int tmplen, offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (likely(!len || BOUNDARY_OK(addr, len))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) sdhci_adma_write_desc(host, desc, addr, len, cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) offset = addr & (SZ_128M - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) tmplen = SZ_128M - offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) addr += tmplen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) len -= tmplen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) sdhci_adma_write_desc(host, desc, addr, len, cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct mmc_request *mrq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct sdhci_host *host = mmc_priv(mmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * No matter V4 is enabled or not, ARGUMENT2 register is 32-bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * block count register which doesn't support stuff bits of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * CMD23 argument on dwcmsch host controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (mrq->sbc && (mrq->sbc->arg & SDHCI_DWCMSHC_ARG2_STUFF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) host->flags &= ~SDHCI_AUTO_CMD23;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) host->flags |= SDHCI_AUTO_CMD23;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) dwcmshc_check_auto_cmd23(mmc, mrq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) sdhci_request(mmc, mrq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) unsigned int timing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) u16 ctrl_2, ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* Select Bus Speed Mode for host */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if ((timing == MMC_TIMING_MMC_HS200) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) (timing == MMC_TIMING_UHS_SDR104))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) else if (timing == MMC_TIMING_UHS_SDR12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) else if ((timing == MMC_TIMING_UHS_SDR25) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) (timing == MMC_TIMING_MMC_HS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) else if (timing == MMC_TIMING_UHS_SDR50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) else if ((timing == MMC_TIMING_UHS_DDR50) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) (timing == MMC_TIMING_MMC_DDR52))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) else if (timing == MMC_TIMING_MMC_HS400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* set CARD_IS_EMMC bit to enable Data Strobe for HS400 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) ctrl = sdhci_readw(host, DWCMSHC_EMMC_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) ctrl |= DWCMSHC_CARD_IS_EMMC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) sdhci_writew(host, ctrl, DWCMSHC_EMMC_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ctrl_2 |= DWCMSHC_CTRL_HS400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct mmc_ios *ios)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) u32 vendor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct sdhci_host *host = mmc_priv(mmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) vendor = sdhci_readl(host, DWCMSHC_EMMC_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (ios->enhanced_strobe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) vendor |= DWCMSHC_ENHANCED_STROBE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) vendor &= ~DWCMSHC_ENHANCED_STROBE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) sdhci_writel(host, vendor, DWCMSHC_EMMC_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) u32 txclk_tapnum, extra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) host->mmc->actual_clock = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (clock == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* Disable interface clock at initial state. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) sdhci_set_clock(host, clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) /* Rockchip platform only support 375KHz for identify mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (clock <= 400000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) clock = 375000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (priv->acpi_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) union acpi_object params[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct acpi_object_list param_objects;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) params[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) params[0].integer.value = clock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) param_objects.count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) param_objects.pointer = params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) acpi_evaluate_object(ACPI_HANDLE(mmc_dev(host->mmc)), "SCLK", ¶m_objects, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) err = clk_set_rate(pltfm_host->clk, clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) sdhci_set_clock(host, clock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /* Disable cmd conflict check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) extra = sdhci_readl(host, DWCMSHC_HOST_CTRL3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) extra &= ~BIT(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (clock <= 52000000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) /* Disable DLL and reset both of sample and drive clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * Before switching to hs400es mode, the driver will enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * enhanced strobe first. PHY needs to configure the parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * of enhanced strobe first.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) extra = DWCMSHC_EMMC_DLL_DLYENA |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) DLL_STRBIN_DELAY_NUM_SEL |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* Reset DLL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) sdhci_writel(host, BIT(1), DWCMSHC_EMMC_DLL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * We shouldn't set DLL_RXCLK_NO_INVERTER for identify mode but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * we must set it in higher speed mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) extra = DWCMSHC_EMMC_DLL_DLYENA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (priv->flags & RK_RXCLK_NO_INVERTER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) extra |= DLL_RXCLK_NO_INVERTER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* Init DLL settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 0x2 << DWCMSHC_EMMC_DLL_INC |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) DWCMSHC_EMMC_DLL_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) err = readl_poll_timeout(host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) extra, DLL_LOCK_WO_TMOUT(extra), 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 500 * USEC_PER_MSEC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) extra = 0x1 << 16 | /* tune clock stop en */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 0x2 << 17 | /* pre-change delay */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 0x3 << 19; /* post-change delay */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) sdhci_writel(host, extra, DWCMSHC_EMMC_ATCTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) txclk_tapnum = priv->txclk_tapnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if ((priv->flags & RK_DLL_CMD_OUT) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) extra = DLL_CMDOUT_SRC_CLK_NEG |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) DLL_CMDOUT_EN_SRC_CLK_NEG |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) DWCMSHC_EMMC_DLL_DLYENA |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) DLL_CMDOUT_TAPNUM_90_DEGREES |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) DLL_CMDOUT_TAPNUM_FROM_SW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) extra = DWCMSHC_EMMC_DLL_DLYENA |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) DLL_TXCLK_TAPNUM_FROM_SW |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) DLL_RXCLK_NO_INVERTER |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) txclk_tapnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) extra = DWCMSHC_EMMC_DLL_DLYENA |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) DLL_STRBIN_TAPNUM_DEFAULT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) DLL_STRBIN_TAPNUM_FROM_SW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static void rockchip_sdhci_reset(struct sdhci_host *host, u8 mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct sdhci_pltfm_host *pltfm_host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) struct dwcmshc_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (mask & SDHCI_RESET_ALL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) priv = sdhci_pltfm_priv(pltfm_host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (!IS_ERR_OR_NULL(priv->reset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) reset_control_assert(priv->reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) udelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) reset_control_deassert(priv->reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) sdhci_reset(host, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) static const struct sdhci_ops sdhci_dwcmshc_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) .set_clock = sdhci_set_clock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) .set_bus_width = sdhci_set_bus_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .set_uhs_signaling = dwcmshc_set_uhs_signaling,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) .get_max_clock = sdhci_pltfm_clk_get_max_clock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .reset = sdhci_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) .adma_write_desc = dwcmshc_adma_write_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static const struct sdhci_ops sdhci_dwcmshc_rk_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) .set_clock = dwcmshc_rk_set_clock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .set_bus_width = sdhci_set_bus_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .set_uhs_signaling = dwcmshc_set_uhs_signaling,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) .get_max_clock = sdhci_pltfm_clk_get_max_clock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) .reset = rockchip_sdhci_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) .adma_write_desc = dwcmshc_adma_write_desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) .ops = &sdhci_dwcmshc_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) static const struct sdhci_pltfm_data sdhci_dwcmshc_rk_pdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) .ops = &sdhci_dwcmshc_rk_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) static const struct dwcmshc_driver_data dwcmshc_drvdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) .pdata = &sdhci_dwcmshc_pdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static const struct dwcmshc_driver_data rk3568_drvdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) .pdata = &sdhci_dwcmshc_rk_pdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) .flags = RK_PLATFROM | RK_RXCLK_NO_INVERTER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) static const struct dwcmshc_driver_data rk3588_drvdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) .pdata = &sdhci_dwcmshc_rk_pdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) .flags = RK_PLATFROM | RK_DLL_CMD_OUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) static int rockchip_pltf_init(struct sdhci_host *host, struct dwcmshc_priv *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) priv->rockchip_clks[0].id = "axi";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) priv->rockchip_clks[1].id = "block";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) priv->rockchip_clks[2].id = "timer";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), ROCKCHIP_MAX_CLKS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) priv->rockchip_clks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) err = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (of_property_read_u32(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) &priv->txclk_tapnum))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /* Disable cmd conflict check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) sdhci_writel(host, 0x0, DWCMSHC_HOST_CTRL3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) /* Reset previous settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * Don't support highspeed bus mode with low clk speed as we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * cannot use DLL for this condition.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (host->mmc->f_max <= 52000000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) .compatible = "snps,dwcmshc-sdhci",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) .data = &dwcmshc_drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) .compatible = "rockchip,dwcmshc-sdhci",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) .data = &rk3568_drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) .compatible = "rockchip,rk3588-dwcmshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .data = &rk3588_drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) static int dwcmshc_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) struct sdhci_pltfm_host *pltfm_host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) struct sdhci_host *host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) struct dwcmshc_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) const struct dwcmshc_driver_data *drv_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) u32 extra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) drv_data = device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) if (!drv_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) dev_err(&pdev->dev, "Error: No device match data found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) host = sdhci_pltfm_init(pdev, drv_data->pdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) sizeof(struct dwcmshc_priv));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (IS_ERR(host))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return PTR_ERR(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * extra adma table cnt for cross 128M boundary handling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (extra > SDHCI_MAX_SEGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) extra = SDHCI_MAX_SEGS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) host->adma_table_cnt += extra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) priv = sdhci_pltfm_priv(pltfm_host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) priv->acpi_en = has_acpi_companion(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (!priv->acpi_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) priv->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (IS_ERR(pltfm_host->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) err = PTR_ERR(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) dev_err(&pdev->dev, "failed to get core clk: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) goto free_pltfm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) err = clk_prepare_enable(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) goto free_pltfm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) priv->bus_clk = devm_clk_get(&pdev->dev, "bus");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (!IS_ERR(priv->bus_clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) clk_prepare_enable(priv->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) err = mmc_of_parse(host->mmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) goto err_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) sdhci_get_of_property(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) host->mmc_host_ops.request = dwcmshc_request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) err = sdhci_add_host(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) goto err_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) priv->flags = drv_data->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (drv_data->flags & RK_PLATFROM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) err = rockchip_pltf_init(host, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) goto err_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if (!priv->acpi_en) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) pm_runtime_get_noresume(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) pm_runtime_set_active(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) pm_runtime_enable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) pm_runtime_use_autosuspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) pm_runtime_put_autosuspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) err_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) clk_disable_unprepare(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) clk_disable_unprepare(priv->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) free_pltfm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) sdhci_pltfm_free(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) static int dwcmshc_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) struct sdhci_host *host = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) sdhci_remove_host(host, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) clk_disable_unprepare(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) clk_disable_unprepare(priv->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) sdhci_pltfm_free(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) static int dwcmshc_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct sdhci_host *host = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) ret = sdhci_suspend_host(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) clk_disable_unprepare(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (!IS_ERR(priv->bus_clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) clk_disable_unprepare(priv->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) static int dwcmshc_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) struct sdhci_host *host = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) ret = clk_prepare_enable(pltfm_host->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (!IS_ERR(priv->bus_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) ret = clk_prepare_enable(priv->bus_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) ret = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) return sdhci_resume_host(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) static int dwcmshc_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) struct sdhci_host *host = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) data = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) data &= ~SDHCI_CLOCK_CARD_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) sdhci_writew(host, data, SDHCI_CLOCK_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) static int dwcmshc_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) struct sdhci_host *host = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) u16 data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) data = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) data |= SDHCI_CLOCK_CARD_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) sdhci_writew(host, data, SDHCI_CLOCK_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) static const struct dev_pm_ops dwcmshc_pmops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend, dwcmshc_runtime_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) static struct platform_driver sdhci_dwcmshc_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) .name = "sdhci-dwcmshc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) .probe_type = PROBE_PREFER_ASYNCHRONOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) .of_match_table = sdhci_dwcmshc_dt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) .pm = &dwcmshc_pmops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) .probe = dwcmshc_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) .remove = dwcmshc_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) module_platform_driver(sdhci_dwcmshc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) MODULE_DESCRIPTION("SDHCI platform driver for Synopsys DWC MSHC");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) MODULE_LICENSE("GPL v2");