1a6e7e407SFabio Estevam // SPDX-License-Identifier: GPL-2.0 295f25efeSWolfram Sang /* 395f25efeSWolfram Sang * Freescale eSDHC i.MX controller driver for the platform bus. 495f25efeSWolfram Sang * 595f25efeSWolfram Sang * derived from the OF-version. 695f25efeSWolfram Sang * 795f25efeSWolfram Sang * Copyright (c) 2010 Pengutronix e.K. 8035ff831SWolfram Sang * Author: Wolfram Sang <kernel@pengutronix.de> 995f25efeSWolfram Sang */ 1095f25efeSWolfram Sang 11a8e809ecSMasahiro Yamada #include <linux/bitfield.h> 1295f25efeSWolfram Sang #include <linux/io.h> 13f581e909SHaibo Chen #include <linux/iopoll.h> 1495f25efeSWolfram Sang #include <linux/delay.h> 1595f25efeSWolfram Sang #include <linux/err.h> 1695f25efeSWolfram Sang #include <linux/clk.h> 1766506f76SShawn Guo #include <linux/module.h> 18e149860dSRichard Zhu #include <linux/slab.h> 191c4989b0SBOUGH CHEN #include <linux/pm_qos.h> 2095f25efeSWolfram Sang #include <linux/mmc/host.h> 2158ac8177SRichard Zhu #include <linux/mmc/mmc.h> 2258ac8177SRichard Zhu #include <linux/mmc/sdio.h> 23fbe5fdd1SShawn Guo #include <linux/mmc/slot-gpio.h> 24abfafc2dSShawn Guo #include <linux/of.h> 25abfafc2dSShawn Guo #include <linux/of_device.h> 26e62d8b8fSDong Aisheng #include <linux/pinctrl/consumer.h> 2789d7e5c1SDong Aisheng #include <linux/pm_runtime.h> 28fb1dec44SBrian Norris #include "sdhci-cqhci.h" 2995f25efeSWolfram Sang #include "sdhci-pltfm.h" 3095f25efeSWolfram Sang #include "sdhci-esdhc.h" 31bb6e3581SBOUGH CHEN #include "cqhci.h" 3295f25efeSWolfram Sang 33a215186dSHaibo Chen #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f 3460bf6396SShawn Guo #define ESDHC_CTRL_D3CD 0x08 35fd44954eSHaibo Chen #define ESDHC_BURST_LEN_EN_INCR (1 << 27) 3658ac8177SRichard Zhu /* VENDOR SPEC register */ 3760bf6396SShawn Guo #define ESDHC_VENDOR_SPEC 0xc0 3860bf6396SShawn Guo #define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1) 390322191eSDong Aisheng #define ESDHC_VENDOR_SPEC_VSELECT (1 << 1) 40fed2f6e2SDong Aisheng #define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8) 413722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_AND_STATUS_REG 0xc2 423722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_REG 0xc3 433722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_MASK 0xf 443722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_CMD_STATE 1 453722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_DATA_STATE 2 463722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_TRANS_STATE 3 473722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_DMA_STATE 4 483722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_ADMA_STATE 5 493722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_FIFO_STATE 6 503722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_ASYNC_FIFO_STATE 7 5160bf6396SShawn Guo #define ESDHC_WTMK_LVL 0x44 52cc17e129SDong Aisheng #define ESDHC_WTMK_DEFAULT_VAL 0x10401040 533fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_RD_WML_MASK 0x000000FF 543fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_RD_WML_SHIFT 0 553fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_WR_WML_MASK 0x00FF0000 563fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_WR_WML_SHIFT 16 573fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_WML_VAL_DEF 64 583fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_WML_VAL_MAX 128 5960bf6396SShawn Guo #define ESDHC_MIX_CTRL 0x48 60de5bdbffSDong Aisheng #define ESDHC_MIX_CTRL_DDREN (1 << 3) 612a15f981SShawn Guo #define ESDHC_MIX_CTRL_AC23EN (1 << 7) 620322191eSDong Aisheng #define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22) 630322191eSDong Aisheng #define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23) 640b330e38SDong Aisheng #define ESDHC_MIX_CTRL_AUTO_TUNE_EN (1 << 24) 650322191eSDong Aisheng #define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25) 6628b07674SHaibo Chen #define ESDHC_MIX_CTRL_HS400_EN (1 << 26) 67029e2476SBOUGH CHEN #define ESDHC_MIX_CTRL_HS400_ES_EN (1 << 27) 682a15f981SShawn Guo /* Bits 3 and 6 are not SDHCI standard definitions */ 692a15f981SShawn Guo #define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7 70d131a71cSDong Aisheng /* Tuning bits */ 71d131a71cSDong Aisheng #define ESDHC_MIX_CTRL_TUNING_MASK 0x03c00000 7258ac8177SRichard Zhu 73602519b2SDong Aisheng /* dll control register */ 74602519b2SDong Aisheng #define ESDHC_DLL_CTRL 0x60 75602519b2SDong Aisheng #define ESDHC_DLL_OVERRIDE_VAL_SHIFT 9 76602519b2SDong Aisheng #define ESDHC_DLL_OVERRIDE_EN_SHIFT 8 77602519b2SDong Aisheng 780322191eSDong Aisheng /* tune control register */ 790322191eSDong Aisheng #define ESDHC_TUNE_CTRL_STATUS 0x68 800322191eSDong Aisheng #define ESDHC_TUNE_CTRL_STEP 1 810322191eSDong Aisheng #define ESDHC_TUNE_CTRL_MIN 0 820322191eSDong Aisheng #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) 830322191eSDong Aisheng 8428b07674SHaibo Chen /* strobe dll register */ 8528b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL 0x70 8628b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0) 8728b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1) 885bd2acdcSHaibo Chen #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT 0x7 8928b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3 902eaf5a53SBOUGH CHEN #define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT (4 << 20) 9128b07674SHaibo Chen 9228b07674SHaibo Chen #define ESDHC_STROBE_DLL_STATUS 0x74 9328b07674SHaibo Chen #define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1) 9428b07674SHaibo Chen #define ESDHC_STROBE_DLL_STS_SLV_LOCK 0x1 9528b07674SHaibo Chen 96bcdb5301SBOUGH CHEN #define ESDHC_VEND_SPEC2 0xc8 97bcdb5301SBOUGH CHEN #define ESDHC_VEND_SPEC2_EN_BUSY_IRQ (1 << 8) 9845334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN (1 << 4) 9945334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN (0 << 4) 10045334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN (2 << 4) 10145334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN (1 << 6) 10245334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK (7 << 4) 103bcdb5301SBOUGH CHEN 1046e9fd28eSDong Aisheng #define ESDHC_TUNING_CTRL 0xcc 1056e9fd28eSDong Aisheng #define ESDHC_STD_TUNING_EN (1 << 24) 1066e9fd28eSDong Aisheng /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ 107d87fc966SDong Aisheng #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 1081194be8cSHaibo Chen #define ESDHC_TUNING_START_TAP_MASK 0x7f 10916e40e5bSHaibo Chen #define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE (1 << 7) 110260ecb3cSHaibo Chen #define ESDHC_TUNING_STEP_MASK 0x00070000 111d407e30bSHaibo Chen #define ESDHC_TUNING_STEP_SHIFT 16 1126e9fd28eSDong Aisheng 113ad93220dSDong Aisheng /* pinctrl state */ 114ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" 115ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz" 116ad93220dSDong Aisheng 11758ac8177SRichard Zhu /* 118af51079eSSascha Hauer * Our interpretation of the SDHCI_HOST_CONTROL register 119af51079eSSascha Hauer */ 120af51079eSSascha Hauer #define ESDHC_CTRL_4BITBUS (0x1 << 1) 121af51079eSSascha Hauer #define ESDHC_CTRL_8BITBUS (0x2 << 1) 122af51079eSSascha Hauer #define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) 12345334ee1SHaibo Chen #define USDHC_GET_BUSWIDTH(c) (c & ESDHC_CTRL_BUSWIDTH_MASK) 124af51079eSSascha Hauer 125af51079eSSascha Hauer /* 126d04f8d5bSBenoît Thébaudeau * There is an INT DMA ERR mismatch between eSDHC and STD SDHC SPEC: 12797e4ba6aSRichard Zhu * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, 12897e4ba6aSRichard Zhu * but bit28 is used as the INT DMA ERR in fsl eSDHC design. 12997e4ba6aSRichard Zhu * Define this macro DMA error INT for fsl eSDHC 13097e4ba6aSRichard Zhu */ 13160bf6396SShawn Guo #define ESDHC_INT_VENDOR_SPEC_DMA_ERR (1 << 28) 13297e4ba6aSRichard Zhu 133bb6e3581SBOUGH CHEN /* the address offset of CQHCI */ 134bb6e3581SBOUGH CHEN #define ESDHC_CQHCI_ADDR_OFFSET 0x100 135bb6e3581SBOUGH CHEN 13697e4ba6aSRichard Zhu /* 13758ac8177SRichard Zhu * The CMDTYPE of the CMD register (offset 0xE) should be set to 13858ac8177SRichard Zhu * "11" when the STOP CMD12 is issued on imx53 to abort one 13958ac8177SRichard Zhu * open ended multi-blk IO. Otherwise the TC INT wouldn't 14058ac8177SRichard Zhu * be generated. 14158ac8177SRichard Zhu * In exact block transfer, the controller doesn't complete the 14258ac8177SRichard Zhu * operations automatically as required at the end of the 14358ac8177SRichard Zhu * transfer and remains on hold if the abort command is not sent. 14458ac8177SRichard Zhu * As a result, the TC flag is not asserted and SW received timeout 145d04f8d5bSBenoît Thébaudeau * exception. Bit1 of Vendor Spec register is used to fix it. 14658ac8177SRichard Zhu */ 14731fbb301SShawn Guo #define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1) 14831fbb301SShawn Guo /* 1499d61c009SShawn Guo * The flag tells that the ESDHC controller is an USDHC block that is 1509d61c009SShawn Guo * integrated on the i.MX6 series. 1519d61c009SShawn Guo */ 1529d61c009SShawn Guo #define ESDHC_FLAG_USDHC BIT(3) 1536e9fd28eSDong Aisheng /* The IP supports manual tuning process */ 1546e9fd28eSDong Aisheng #define ESDHC_FLAG_MAN_TUNING BIT(4) 1556e9fd28eSDong Aisheng /* The IP supports standard tuning process */ 1566e9fd28eSDong Aisheng #define ESDHC_FLAG_STD_TUNING BIT(5) 1576e9fd28eSDong Aisheng /* The IP has SDHCI_CAPABILITIES_1 register */ 1586e9fd28eSDong Aisheng #define ESDHC_FLAG_HAVE_CAP1 BIT(6) 15918094430SDong Aisheng /* 160d04f8d5bSBenoît Thébaudeau * The IP has erratum ERR004536 16118094430SDong Aisheng * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow, 16218094430SDong Aisheng * when reading data from the card 163667123f6SBenoît Thébaudeau * This flag is also set for i.MX25 and i.MX35 in order to get 164667123f6SBenoît Thébaudeau * SDHCI_QUIRK_BROKEN_ADMA, but for different reasons (ADMA capability bits). 16518094430SDong Aisheng */ 16618094430SDong Aisheng #define ESDHC_FLAG_ERR004536 BIT(7) 1674245afffSDong Aisheng /* The IP supports HS200 mode */ 1684245afffSDong Aisheng #define ESDHC_FLAG_HS200 BIT(8) 16928b07674SHaibo Chen /* The IP supports HS400 mode */ 17028b07674SHaibo Chen #define ESDHC_FLAG_HS400 BIT(9) 171af6a50d4SBOUGH CHEN /* 172af6a50d4SBOUGH CHEN * The IP has errata ERR010450 173af6a50d4SBOUGH CHEN * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't 174af6a50d4SBOUGH CHEN * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz. 175af6a50d4SBOUGH CHEN */ 176af6a50d4SBOUGH CHEN #define ESDHC_FLAG_ERR010450 BIT(10) 177029e2476SBOUGH CHEN /* The IP supports HS400ES mode */ 178029e2476SBOUGH CHEN #define ESDHC_FLAG_HS400_ES BIT(11) 179bb6e3581SBOUGH CHEN /* The IP has Host Controller Interface for Command Queuing */ 180bb6e3581SBOUGH CHEN #define ESDHC_FLAG_CQHCI BIT(12) 1811c4989b0SBOUGH CHEN /* need request pmqos during low power */ 1821c4989b0SBOUGH CHEN #define ESDHC_FLAG_PMQOS BIT(13) 183a26a4f1bSHaibo Chen /* The IP state got lost in low power mode */ 184a26a4f1bSHaibo Chen #define ESDHC_FLAG_STATE_LOST_IN_LPMODE BIT(14) 1855c11f1ffSHaibo Chen /* The IP lost clock rate in PM_RUNTIME */ 1865c11f1ffSHaibo Chen #define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME BIT(15) 18774898cbcSHaibo Chen /* 18874898cbcSHaibo Chen * The IP do not support the ACMD23 feature completely when use ADMA mode. 18974898cbcSHaibo Chen * In ADMA mode, it only use the 16 bit block count of the register 0x4 19074898cbcSHaibo Chen * (BLOCK_ATT) as the CMD23's argument for ACMD23 mode, which means it will 19174898cbcSHaibo Chen * ignore the upper 16 bit of the CMD23's argument. This will block the reliable 19274898cbcSHaibo Chen * write operation in RPMB, because RPMB reliable write need to set the bit31 19374898cbcSHaibo Chen * of the CMD23's argument. 19474898cbcSHaibo Chen * imx6qpdl/imx6sx/imx6sl/imx7d has this limitation only for ADMA mode, SDMA 19574898cbcSHaibo Chen * do not has this limitation. so when these SoC use ADMA mode, it need to 19674898cbcSHaibo Chen * disable the ACMD23 feature. 19774898cbcSHaibo Chen */ 19874898cbcSHaibo Chen #define ESDHC_FLAG_BROKEN_AUTO_CMD23 BIT(16) 199e149860dSRichard Zhu 2005c4f0062SChester Lin /* ERR004536 is not applicable for the IP */ 2015c4f0062SChester Lin #define ESDHC_FLAG_SKIP_ERR004536 BIT(17) 2025c4f0062SChester Lin 2034a11cc64SFabio Estevam enum wp_types { 2044a11cc64SFabio Estevam ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ 2054a11cc64SFabio Estevam ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ 2064a11cc64SFabio Estevam ESDHC_WP_GPIO, /* external gpio pin for WP */ 2074a11cc64SFabio Estevam }; 2084a11cc64SFabio Estevam 2094a11cc64SFabio Estevam enum cd_types { 2104a11cc64SFabio Estevam ESDHC_CD_NONE, /* no CD, neither controller nor gpio */ 2114a11cc64SFabio Estevam ESDHC_CD_CONTROLLER, /* mmc controller internal CD */ 2124a11cc64SFabio Estevam ESDHC_CD_GPIO, /* external gpio pin for CD */ 2134a11cc64SFabio Estevam ESDHC_CD_PERMANENT, /* no CD, card permanently wired to host */ 2144a11cc64SFabio Estevam }; 2154a11cc64SFabio Estevam 2164a11cc64SFabio Estevam /* 2174a11cc64SFabio Estevam * struct esdhc_platform_data - platform data for esdhc on i.MX 2184a11cc64SFabio Estevam * 2194a11cc64SFabio Estevam * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35. 2204a11cc64SFabio Estevam * 2214a11cc64SFabio Estevam * @wp_type: type of write_protect method (see wp_types enum above) 2224a11cc64SFabio Estevam * @cd_type: type of card_detect method (see cd_types enum above) 2234a11cc64SFabio Estevam */ 2244a11cc64SFabio Estevam 2254a11cc64SFabio Estevam struct esdhc_platform_data { 2264a11cc64SFabio Estevam enum wp_types wp_type; 2274a11cc64SFabio Estevam enum cd_types cd_type; 2284a11cc64SFabio Estevam int max_bus_width; 2294a11cc64SFabio Estevam unsigned int delay_line; 2304a11cc64SFabio Estevam unsigned int tuning_step; /* The delay cell steps in tuning procedure */ 2314a11cc64SFabio Estevam unsigned int tuning_start_tap; /* The start delay cell point in tuning procedure */ 2324a11cc64SFabio Estevam unsigned int strobe_dll_delay_target; /* The delay cell for strobe pad (read clock) */ 2334a11cc64SFabio Estevam }; 2344a11cc64SFabio Estevam 235f47c4bbfSShawn Guo struct esdhc_soc_data { 236f47c4bbfSShawn Guo u32 flags; 237f47c4bbfSShawn Guo }; 238f47c4bbfSShawn Guo 2394f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx25_data = { 240667123f6SBenoît Thébaudeau .flags = ESDHC_FLAG_ERR004536, 241f47c4bbfSShawn Guo }; 242f47c4bbfSShawn Guo 2434f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx35_data = { 244667123f6SBenoît Thébaudeau .flags = ESDHC_FLAG_ERR004536, 245f47c4bbfSShawn Guo }; 246f47c4bbfSShawn Guo 2474f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx51_data = { 248f47c4bbfSShawn Guo .flags = 0, 249f47c4bbfSShawn Guo }; 250f47c4bbfSShawn Guo 2514f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx53_data = { 252f47c4bbfSShawn Guo .flags = ESDHC_FLAG_MULTIBLK_NO_INT, 253f47c4bbfSShawn Guo }; 254f47c4bbfSShawn Guo 2554f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6q_data = { 25674898cbcSHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING 25774898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 2586e9fd28eSDong Aisheng }; 2596e9fd28eSDong Aisheng 2604f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sl_data = { 2616e9fd28eSDong Aisheng .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 2624245afffSDong Aisheng | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 26374898cbcSHaibo Chen | ESDHC_FLAG_HS200 26474898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 26574898cbcSHaibo Chen }; 26674898cbcSHaibo Chen 26774898cbcSHaibo Chen static const struct esdhc_soc_data usdhc_imx6sll_data = { 26874898cbcSHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 26974898cbcSHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 27086b59671SHaibo Chen | ESDHC_FLAG_HS400 27174898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 27257ed3314SShawn Guo }; 27357ed3314SShawn Guo 2744f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sx_data = { 275913d4951SDong Aisheng .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 276a26a4f1bSHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 27774898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 27874898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 279913d4951SDong Aisheng }; 280913d4951SDong Aisheng 281af6a50d4SBOUGH CHEN static const struct esdhc_soc_data usdhc_imx6ull_data = { 282af6a50d4SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 283af6a50d4SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 284a26a4f1bSHaibo Chen | ESDHC_FLAG_ERR010450 285a26a4f1bSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 286af6a50d4SBOUGH CHEN }; 287af6a50d4SBOUGH CHEN 2884f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx7d_data = { 28928b07674SHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 29028b07674SHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 291a26a4f1bSHaibo Chen | ESDHC_FLAG_HS400 29274898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 29374898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 29428b07674SHaibo Chen }; 29528b07674SHaibo Chen 2965c4f0062SChester Lin static struct esdhc_soc_data usdhc_s32g2_data = { 2975c4f0062SChester Lin .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING 2985c4f0062SChester Lin | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 2995c4f0062SChester Lin | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 3005c4f0062SChester Lin | ESDHC_FLAG_SKIP_ERR004536, 3015c4f0062SChester Lin }; 3025c4f0062SChester Lin 3031c4989b0SBOUGH CHEN static struct esdhc_soc_data usdhc_imx7ulp_data = { 3041c4989b0SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 3051c4989b0SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 306a26a4f1bSHaibo Chen | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 307a26a4f1bSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 3081c4989b0SBOUGH CHEN }; 3092f4788f3SJesse Taube static struct esdhc_soc_data usdhc_imxrt1050_data = { 310d7a1830eSGiulio Benetti .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 311d7a1830eSGiulio Benetti | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, 3122f4788f3SJesse Taube }; 3131c4989b0SBOUGH CHEN 314029e2476SBOUGH CHEN static struct esdhc_soc_data usdhc_imx8qxp_data = { 315029e2476SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 316029e2476SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 317bb6e3581SBOUGH CHEN | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 3185c11f1ffSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 3195c11f1ffSHaibo Chen | ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME, 320029e2476SBOUGH CHEN }; 321029e2476SBOUGH CHEN 322cde5e8e9SHaibo Chen static struct esdhc_soc_data usdhc_imx8mm_data = { 323cde5e8e9SHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 324cde5e8e9SHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 325cde5e8e9SHaibo Chen | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 326cde5e8e9SHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 327e149860dSRichard Zhu }; 328e149860dSRichard Zhu 329e149860dSRichard Zhu struct pltfm_imx_data { 330e149860dSRichard Zhu u32 scratchpad; 331e62d8b8fSDong Aisheng struct pinctrl *pinctrl; 332ad93220dSDong Aisheng struct pinctrl_state *pins_100mhz; 333ad93220dSDong Aisheng struct pinctrl_state *pins_200mhz; 334f47c4bbfSShawn Guo const struct esdhc_soc_data *socdata; 335842afc02SShawn Guo struct esdhc_platform_data boarddata; 33652dac615SSascha Hauer struct clk *clk_ipg; 33752dac615SSascha Hauer struct clk *clk_ahb; 33852dac615SSascha Hauer struct clk *clk_per; 3393602785bSMichael Trimarchi unsigned int actual_clock; 340361b8482SLucas Stach enum { 341361b8482SLucas Stach NO_CMD_PENDING, /* no multiblock command pending */ 342361b8482SLucas Stach MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ 343361b8482SLucas Stach WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ 344361b8482SLucas Stach } multiblock_status; 345de5bdbffSDong Aisheng u32 is_ddr; 3461c4989b0SBOUGH CHEN struct pm_qos_request pm_qos_req; 347e149860dSRichard Zhu }; 348e149860dSRichard Zhu 349abfafc2dSShawn Guo static const struct of_device_id imx_esdhc_dt_ids[] = { 350f47c4bbfSShawn Guo { .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, }, 351f47c4bbfSShawn Guo { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, 352f47c4bbfSShawn Guo { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, 353f47c4bbfSShawn Guo { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, 354913d4951SDong Aisheng { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, }, 3556e9fd28eSDong Aisheng { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, 35674898cbcSHaibo Chen { .compatible = "fsl,imx6sll-usdhc", .data = &usdhc_imx6sll_data, }, 357f47c4bbfSShawn Guo { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, 358af6a50d4SBOUGH CHEN { .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, }, 35928b07674SHaibo Chen { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, 3601c4989b0SBOUGH CHEN { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, 361029e2476SBOUGH CHEN { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, 362cde5e8e9SHaibo Chen { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, 3632f4788f3SJesse Taube { .compatible = "fsl,imxrt1050-usdhc", .data = &usdhc_imxrt1050_data, }, 3645c4f0062SChester Lin { .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, }, 365abfafc2dSShawn Guo { /* sentinel */ } 366abfafc2dSShawn Guo }; 367abfafc2dSShawn Guo MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); 368abfafc2dSShawn Guo 36957ed3314SShawn Guo static inline int is_imx25_esdhc(struct pltfm_imx_data *data) 37057ed3314SShawn Guo { 371f47c4bbfSShawn Guo return data->socdata == &esdhc_imx25_data; 37257ed3314SShawn Guo } 37357ed3314SShawn Guo 37457ed3314SShawn Guo static inline int is_imx53_esdhc(struct pltfm_imx_data *data) 37557ed3314SShawn Guo { 376f47c4bbfSShawn Guo return data->socdata == &esdhc_imx53_data; 37757ed3314SShawn Guo } 37857ed3314SShawn Guo 3799d61c009SShawn Guo static inline int esdhc_is_usdhc(struct pltfm_imx_data *data) 3809d61c009SShawn Guo { 381f47c4bbfSShawn Guo return !!(data->socdata->flags & ESDHC_FLAG_USDHC); 3829d61c009SShawn Guo } 3839d61c009SShawn Guo 38495f25efeSWolfram Sang static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) 38595f25efeSWolfram Sang { 38695f25efeSWolfram Sang void __iomem *base = host->ioaddr + (reg & ~0x3); 38795f25efeSWolfram Sang u32 shift = (reg & 0x3) * 8; 38895f25efeSWolfram Sang 38995f25efeSWolfram Sang writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); 39095f25efeSWolfram Sang } 39195f25efeSWolfram Sang 3923722c74cSHaibo Chen #define DRIVER_NAME "sdhci-esdhc-imx" 3933722c74cSHaibo Chen #define ESDHC_IMX_DUMP(f, x...) \ 3943722c74cSHaibo Chen pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) 3953722c74cSHaibo Chen static void esdhc_dump_debug_regs(struct sdhci_host *host) 3963722c74cSHaibo Chen { 3973722c74cSHaibo Chen int i; 3983722c74cSHaibo Chen char *debug_status[7] = { 3993722c74cSHaibo Chen "cmd debug status", 4003722c74cSHaibo Chen "data debug status", 4013722c74cSHaibo Chen "trans debug status", 4023722c74cSHaibo Chen "dma debug status", 4033722c74cSHaibo Chen "adma debug status", 4043722c74cSHaibo Chen "fifo debug status", 4053722c74cSHaibo Chen "async fifo debug status" 4063722c74cSHaibo Chen }; 4073722c74cSHaibo Chen 4083722c74cSHaibo Chen ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n"); 4093722c74cSHaibo Chen for (i = 0; i < 7; i++) { 4103722c74cSHaibo Chen esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 4113722c74cSHaibo Chen ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG); 4123722c74cSHaibo Chen ESDHC_IMX_DUMP("%s: 0x%04x\n", debug_status[i], 4133722c74cSHaibo Chen readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG)); 4143722c74cSHaibo Chen } 4153722c74cSHaibo Chen 4163722c74cSHaibo Chen esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG); 4173722c74cSHaibo Chen 4183722c74cSHaibo Chen } 4193722c74cSHaibo Chen 420f581e909SHaibo Chen static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host) 421f581e909SHaibo Chen { 422f581e909SHaibo Chen u32 present_state; 423f581e909SHaibo Chen int ret; 424f581e909SHaibo Chen 425f581e909SHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state, 426f581e909SHaibo Chen (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100); 427f581e909SHaibo Chen if (ret == -ETIMEDOUT) 428f581e909SHaibo Chen dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__); 429f581e909SHaibo Chen } 430f581e909SHaibo Chen 43145334ee1SHaibo Chen /* Enable the auto tuning circuit to check the CMD line and BUS line */ 43245334ee1SHaibo Chen static inline void usdhc_auto_tuning_mode_sel(struct sdhci_host *host) 43345334ee1SHaibo Chen { 43445334ee1SHaibo Chen u32 buswidth, auto_tune_buswidth; 43545334ee1SHaibo Chen 43645334ee1SHaibo Chen buswidth = USDHC_GET_BUSWIDTH(readl(host->ioaddr + SDHCI_HOST_CONTROL)); 43745334ee1SHaibo Chen 43845334ee1SHaibo Chen switch (buswidth) { 43945334ee1SHaibo Chen case ESDHC_CTRL_8BITBUS: 44045334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN; 44145334ee1SHaibo Chen break; 44245334ee1SHaibo Chen case ESDHC_CTRL_4BITBUS: 44345334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN; 44445334ee1SHaibo Chen break; 44545334ee1SHaibo Chen default: /* 1BITBUS */ 44645334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN; 44745334ee1SHaibo Chen break; 44845334ee1SHaibo Chen } 44945334ee1SHaibo Chen 45045334ee1SHaibo Chen esdhc_clrset_le(host, ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK, 45145334ee1SHaibo Chen auto_tune_buswidth | ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN, 45245334ee1SHaibo Chen ESDHC_VEND_SPEC2); 45345334ee1SHaibo Chen } 45445334ee1SHaibo Chen 4557e29c306SWolfram Sang static u32 esdhc_readl_le(struct sdhci_host *host, int reg) 4567e29c306SWolfram Sang { 457361b8482SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 458070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 459913413c3SShawn Guo u32 val = readl(host->ioaddr + reg); 460913413c3SShawn Guo 4610322191eSDong Aisheng if (unlikely(reg == SDHCI_PRESENT_STATE)) { 4620322191eSDong Aisheng u32 fsl_prss = val; 4630322191eSDong Aisheng /* save the least 20 bits */ 4640322191eSDong Aisheng val = fsl_prss & 0x000FFFFF; 4650322191eSDong Aisheng /* move dat[0-3] bits */ 4660322191eSDong Aisheng val |= (fsl_prss & 0x0F000000) >> 4; 4670322191eSDong Aisheng /* move cmd line bit */ 4680322191eSDong Aisheng val |= (fsl_prss & 0x00800000) << 1; 4690322191eSDong Aisheng } 4700322191eSDong Aisheng 47197e4ba6aSRichard Zhu if (unlikely(reg == SDHCI_CAPABILITIES)) { 4726b4fb671SDong Aisheng /* ignore bit[0-15] as it stores cap_1 register val for mx6sl */ 4736b4fb671SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) 4746b4fb671SDong Aisheng val &= 0xffff0000; 4756b4fb671SDong Aisheng 47697e4ba6aSRichard Zhu /* In FSL esdhc IC module, only bit20 is used to indicate the 47797e4ba6aSRichard Zhu * ADMA2 capability of esdhc, but this bit is messed up on 47897e4ba6aSRichard Zhu * some SOCs (e.g. on MX25, MX35 this bit is set, but they 47997e4ba6aSRichard Zhu * don't actually support ADMA2). So set the BROKEN_ADMA 480d04f8d5bSBenoît Thébaudeau * quirk on MX25/35 platforms. 48197e4ba6aSRichard Zhu */ 48297e4ba6aSRichard Zhu 48397e4ba6aSRichard Zhu if (val & SDHCI_CAN_DO_ADMA1) { 48497e4ba6aSRichard Zhu val &= ~SDHCI_CAN_DO_ADMA1; 48597e4ba6aSRichard Zhu val |= SDHCI_CAN_DO_ADMA2; 48697e4ba6aSRichard Zhu } 48797e4ba6aSRichard Zhu } 48897e4ba6aSRichard Zhu 4896e9fd28eSDong Aisheng if (unlikely(reg == SDHCI_CAPABILITIES_1)) { 4906e9fd28eSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 4916e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) 4926e9fd28eSDong Aisheng val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF; 4936e9fd28eSDong Aisheng else 4946e9fd28eSDong Aisheng /* imx6q/dl does not have cap_1 register, fake one */ 4950322191eSDong Aisheng val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 496888824bbSDong Aisheng | SDHCI_SUPPORT_SDR50 497da0295ffSDong Aisheng | SDHCI_USE_SDR50_TUNING 498a8e809ecSMasahiro Yamada | FIELD_PREP(SDHCI_RETUNING_MODE_MASK, 499a8e809ecSMasahiro Yamada SDHCI_TUNING_MODE_3); 50028b07674SHaibo Chen 50192748beaSStefan Agner /* 50292748beaSStefan Agner * Do not advertise faster UHS modes if there are no 50392748beaSStefan Agner * pinctrl states for 100MHz/200MHz. 50492748beaSStefan Agner */ 50525e8b9ebSShawn Guo if (IS_ERR_OR_NULL(imx_data->pins_100mhz)) 50625e8b9ebSShawn Guo val &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); 50725e8b9ebSShawn Guo if (IS_ERR_OR_NULL(imx_data->pins_200mhz)) 50825e8b9ebSShawn Guo val &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_HS400); 5096e9fd28eSDong Aisheng } 5106e9fd28eSDong Aisheng } 5110322191eSDong Aisheng 5129d61c009SShawn Guo if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { 5130322191eSDong Aisheng val = 0; 514804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF); 515804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF); 516804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF); 5170322191eSDong Aisheng } 5180322191eSDong Aisheng 51997e4ba6aSRichard Zhu if (unlikely(reg == SDHCI_INT_STATUS)) { 52060bf6396SShawn Guo if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) { 52160bf6396SShawn Guo val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; 52297e4ba6aSRichard Zhu val |= SDHCI_INT_ADMA_ERROR; 52397e4ba6aSRichard Zhu } 524361b8482SLucas Stach 525361b8482SLucas Stach /* 526361b8482SLucas Stach * mask off the interrupt we get in response to the manually 527361b8482SLucas Stach * sent CMD12 528361b8482SLucas Stach */ 529361b8482SLucas Stach if ((imx_data->multiblock_status == WAIT_FOR_INT) && 530361b8482SLucas Stach ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) { 531361b8482SLucas Stach val &= ~SDHCI_INT_RESPONSE; 532361b8482SLucas Stach writel(SDHCI_INT_RESPONSE, host->ioaddr + 533361b8482SLucas Stach SDHCI_INT_STATUS); 534361b8482SLucas Stach imx_data->multiblock_status = NO_CMD_PENDING; 535361b8482SLucas Stach } 53697e4ba6aSRichard Zhu } 53797e4ba6aSRichard Zhu 5387e29c306SWolfram Sang return val; 5397e29c306SWolfram Sang } 5407e29c306SWolfram Sang 5417e29c306SWolfram Sang static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) 5427e29c306SWolfram Sang { 543e149860dSRichard Zhu struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 544070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 5450d58864bSTony Lin u32 data; 546e149860dSRichard Zhu 54777da3da0SAaron Brice if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE || 54877da3da0SAaron Brice reg == SDHCI_INT_STATUS)) { 549b7321042SDong Aisheng if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) { 5500d58864bSTony Lin /* 5510d58864bSTony Lin * Clear and then set D3CD bit to avoid missing the 552d04f8d5bSBenoît Thébaudeau * card interrupt. This is an eSDHC controller problem 5530d58864bSTony Lin * so we need to apply the following workaround: clear 5540d58864bSTony Lin * and set D3CD bit will make eSDHC re-sample the card 5550d58864bSTony Lin * interrupt. In case a card interrupt was lost, 5560d58864bSTony Lin * re-sample it by the following steps. 5570d58864bSTony Lin */ 5580d58864bSTony Lin data = readl(host->ioaddr + SDHCI_HOST_CONTROL); 55960bf6396SShawn Guo data &= ~ESDHC_CTRL_D3CD; 5600d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 56160bf6396SShawn Guo data |= ESDHC_CTRL_D3CD; 5620d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 5630d58864bSTony Lin } 564915be485SDong Aisheng 565915be485SDong Aisheng if (val & SDHCI_INT_ADMA_ERROR) { 566915be485SDong Aisheng val &= ~SDHCI_INT_ADMA_ERROR; 567915be485SDong Aisheng val |= ESDHC_INT_VENDOR_SPEC_DMA_ERR; 568915be485SDong Aisheng } 5690d58864bSTony Lin } 5700d58864bSTony Lin 571f47c4bbfSShawn Guo if (unlikely((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 57258ac8177SRichard Zhu && (reg == SDHCI_INT_STATUS) 57358ac8177SRichard Zhu && (val & SDHCI_INT_DATA_END))) { 57458ac8177SRichard Zhu u32 v; 57560bf6396SShawn Guo v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 57660bf6396SShawn Guo v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK; 57760bf6396SShawn Guo writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); 578361b8482SLucas Stach 579361b8482SLucas Stach if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS) 580361b8482SLucas Stach { 581361b8482SLucas Stach /* send a manual CMD12 with RESPTYP=none */ 582361b8482SLucas Stach data = MMC_STOP_TRANSMISSION << 24 | 583361b8482SLucas Stach SDHCI_CMD_ABORTCMD << 16; 584361b8482SLucas Stach writel(data, host->ioaddr + SDHCI_TRANSFER_MODE); 585361b8482SLucas Stach imx_data->multiblock_status = WAIT_FOR_INT; 586361b8482SLucas Stach } 58758ac8177SRichard Zhu } 58858ac8177SRichard Zhu 5897e29c306SWolfram Sang writel(val, host->ioaddr + reg); 5907e29c306SWolfram Sang } 5917e29c306SWolfram Sang 59295f25efeSWolfram Sang static u16 esdhc_readw_le(struct sdhci_host *host, int reg) 59395f25efeSWolfram Sang { 594ef4d0888SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 595070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 5960322191eSDong Aisheng u16 ret = 0; 5970322191eSDong Aisheng u32 val; 598ef4d0888SShawn Guo 59995a2482aSShawn Guo if (unlikely(reg == SDHCI_HOST_VERSION)) { 600ef4d0888SShawn Guo reg ^= 2; 6019d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 60295a2482aSShawn Guo /* 603ef4d0888SShawn Guo * The usdhc register returns a wrong host version. 604ef4d0888SShawn Guo * Correct it here. 60595a2482aSShawn Guo */ 606ef4d0888SShawn Guo return SDHCI_SPEC_300; 607ef4d0888SShawn Guo } 60895a2482aSShawn Guo } 60995f25efeSWolfram Sang 6100322191eSDong Aisheng if (unlikely(reg == SDHCI_HOST_CONTROL2)) { 6110322191eSDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6120322191eSDong Aisheng if (val & ESDHC_VENDOR_SPEC_VSELECT) 6130322191eSDong Aisheng ret |= SDHCI_CTRL_VDD_180; 6140322191eSDong Aisheng 6159d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 6166e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) 6170322191eSDong Aisheng val = readl(host->ioaddr + ESDHC_MIX_CTRL); 6186e9fd28eSDong Aisheng else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) 6196e9fd28eSDong Aisheng /* the std tuning bits is in ACMD12_ERR for imx6sl */ 620869f8a69SAdrian Hunter val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6216e9fd28eSDong Aisheng } 6226e9fd28eSDong Aisheng 6230322191eSDong Aisheng if (val & ESDHC_MIX_CTRL_EXE_TUNE) 6240322191eSDong Aisheng ret |= SDHCI_CTRL_EXEC_TUNING; 6250322191eSDong Aisheng if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) 6260322191eSDong Aisheng ret |= SDHCI_CTRL_TUNED_CLK; 6270322191eSDong Aisheng 6280322191eSDong Aisheng ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; 6290322191eSDong Aisheng 6300322191eSDong Aisheng return ret; 6310322191eSDong Aisheng } 6320322191eSDong Aisheng 6337dd109efSDong Aisheng if (unlikely(reg == SDHCI_TRANSFER_MODE)) { 6347dd109efSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 6357dd109efSDong Aisheng u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 6367dd109efSDong Aisheng ret = m & ESDHC_MIX_CTRL_SDHCI_MASK; 6377dd109efSDong Aisheng /* Swap AC23 bit */ 6387dd109efSDong Aisheng if (m & ESDHC_MIX_CTRL_AC23EN) { 6397dd109efSDong Aisheng ret &= ~ESDHC_MIX_CTRL_AC23EN; 6407dd109efSDong Aisheng ret |= SDHCI_TRNS_AUTO_CMD23; 6417dd109efSDong Aisheng } 6427dd109efSDong Aisheng } else { 6437dd109efSDong Aisheng ret = readw(host->ioaddr + SDHCI_TRANSFER_MODE); 6447dd109efSDong Aisheng } 6457dd109efSDong Aisheng 6467dd109efSDong Aisheng return ret; 6477dd109efSDong Aisheng } 6487dd109efSDong Aisheng 64995f25efeSWolfram Sang return readw(host->ioaddr + reg); 65095f25efeSWolfram Sang } 65195f25efeSWolfram Sang 65295f25efeSWolfram Sang static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) 65395f25efeSWolfram Sang { 65495f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 655070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 6560322191eSDong Aisheng u32 new_val = 0; 65795f25efeSWolfram Sang 65895f25efeSWolfram Sang switch (reg) { 6590322191eSDong Aisheng case SDHCI_CLOCK_CONTROL: 6600322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6610322191eSDong Aisheng if (val & SDHCI_CLOCK_CARD_EN) 6620322191eSDong Aisheng new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 6630322191eSDong Aisheng else 6640322191eSDong Aisheng new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 6650322191eSDong Aisheng writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); 666f581e909SHaibo Chen if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON)) 667f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 6680322191eSDong Aisheng return; 6690322191eSDong Aisheng case SDHCI_HOST_CONTROL2: 6700322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6710322191eSDong Aisheng if (val & SDHCI_CTRL_VDD_180) 6720322191eSDong Aisheng new_val |= ESDHC_VENDOR_SPEC_VSELECT; 6730322191eSDong Aisheng else 6740322191eSDong Aisheng new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; 6750322191eSDong Aisheng writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); 676a0dbbdc2SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 677869f8a69SAdrian Hunter u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6786e9fd28eSDong Aisheng u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 6798b2bb0adSDong Aisheng if (val & SDHCI_CTRL_TUNED_CLK) { 6808b2bb0adSDong Aisheng v |= ESDHC_MIX_CTRL_SMPCLK_SEL; 6816e9fd28eSDong Aisheng } else { 6828b2bb0adSDong Aisheng v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 6836e9fd28eSDong Aisheng m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; 6840b330e38SDong Aisheng m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN; 6856e9fd28eSDong Aisheng } 6866e9fd28eSDong Aisheng 6878b2bb0adSDong Aisheng if (val & SDHCI_CTRL_EXEC_TUNING) { 6888b2bb0adSDong Aisheng v |= ESDHC_MIX_CTRL_EXE_TUNE; 6898b2bb0adSDong Aisheng m |= ESDHC_MIX_CTRL_FBCLK_SEL; 6900b330e38SDong Aisheng m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; 69145334ee1SHaibo Chen usdhc_auto_tuning_mode_sel(host); 6928b2bb0adSDong Aisheng } else { 6938b2bb0adSDong Aisheng v &= ~ESDHC_MIX_CTRL_EXE_TUNE; 6948b2bb0adSDong Aisheng } 6956e9fd28eSDong Aisheng 696869f8a69SAdrian Hunter writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6976e9fd28eSDong Aisheng writel(m, host->ioaddr + ESDHC_MIX_CTRL); 6986e9fd28eSDong Aisheng } 6990322191eSDong Aisheng return; 70095f25efeSWolfram Sang case SDHCI_TRANSFER_MODE: 701f47c4bbfSShawn Guo if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 70258ac8177SRichard Zhu && (host->cmd->opcode == SD_IO_RW_EXTENDED) 70358ac8177SRichard Zhu && (host->cmd->data->blocks > 1) 70458ac8177SRichard Zhu && (host->cmd->data->flags & MMC_DATA_READ)) { 70558ac8177SRichard Zhu u32 v; 70660bf6396SShawn Guo v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 70760bf6396SShawn Guo v |= ESDHC_VENDOR_SPEC_SDIO_QUIRK; 70860bf6396SShawn Guo writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); 70958ac8177SRichard Zhu } 71069f54698SShawn Guo 7119d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 7123fbd4322SAndrew Gabbasov u32 wml; 71369f54698SShawn Guo u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 7142a15f981SShawn Guo /* Swap AC23 bit */ 7152a15f981SShawn Guo if (val & SDHCI_TRNS_AUTO_CMD23) { 7162a15f981SShawn Guo val &= ~SDHCI_TRNS_AUTO_CMD23; 7172a15f981SShawn Guo val |= ESDHC_MIX_CTRL_AC23EN; 7182a15f981SShawn Guo } 7192a15f981SShawn Guo m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK); 72069f54698SShawn Guo writel(m, host->ioaddr + ESDHC_MIX_CTRL); 7213fbd4322SAndrew Gabbasov 7223fbd4322SAndrew Gabbasov /* Set watermark levels for PIO access to maximum value 7233fbd4322SAndrew Gabbasov * (128 words) to accommodate full 512 bytes buffer. 7243fbd4322SAndrew Gabbasov * For DMA access restore the levels to default value. 7253fbd4322SAndrew Gabbasov */ 7263fbd4322SAndrew Gabbasov m = readl(host->ioaddr + ESDHC_WTMK_LVL); 727e534b82fSHaibo Chen if (val & SDHCI_TRNS_DMA) { 7283fbd4322SAndrew Gabbasov wml = ESDHC_WTMK_LVL_WML_VAL_DEF; 729e534b82fSHaibo Chen } else { 730e534b82fSHaibo Chen u8 ctrl; 7313fbd4322SAndrew Gabbasov wml = ESDHC_WTMK_LVL_WML_VAL_MAX; 732e534b82fSHaibo Chen 733e534b82fSHaibo Chen /* 734e534b82fSHaibo Chen * Since already disable DMA mode, so also need 735e534b82fSHaibo Chen * to clear the DMASEL. Otherwise, for standard 736e534b82fSHaibo Chen * tuning, when send tuning command, usdhc will 737e534b82fSHaibo Chen * still prefetch the ADMA script from wrong 738e534b82fSHaibo Chen * DMA address, then we will see IOMMU report 739e534b82fSHaibo Chen * some error which show lack of TLB mapping. 740e534b82fSHaibo Chen */ 741e534b82fSHaibo Chen ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 742e534b82fSHaibo Chen ctrl &= ~SDHCI_CTRL_DMA_MASK; 743e534b82fSHaibo Chen sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 744e534b82fSHaibo Chen } 7453fbd4322SAndrew Gabbasov m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK | 7463fbd4322SAndrew Gabbasov ESDHC_WTMK_LVL_WR_WML_MASK); 7473fbd4322SAndrew Gabbasov m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) | 7483fbd4322SAndrew Gabbasov (wml << ESDHC_WTMK_LVL_WR_WML_SHIFT); 7493fbd4322SAndrew Gabbasov writel(m, host->ioaddr + ESDHC_WTMK_LVL); 75069f54698SShawn Guo } else { 75169f54698SShawn Guo /* 75269f54698SShawn Guo * Postpone this write, we must do it together with a 75369f54698SShawn Guo * command write that is down below. 75469f54698SShawn Guo */ 755e149860dSRichard Zhu imx_data->scratchpad = val; 75669f54698SShawn Guo } 75795f25efeSWolfram Sang return; 75895f25efeSWolfram Sang case SDHCI_COMMAND: 759361b8482SLucas Stach if (host->cmd->opcode == MMC_STOP_TRANSMISSION) 76058ac8177SRichard Zhu val |= SDHCI_CMD_ABORTCMD; 76195a2482aSShawn Guo 762361b8482SLucas Stach if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) && 763f47c4bbfSShawn Guo (imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) 764361b8482SLucas Stach imx_data->multiblock_status = MULTIBLK_IN_PROCESS; 765361b8482SLucas Stach 7669d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) 76795a2482aSShawn Guo writel(val << 16, 76895a2482aSShawn Guo host->ioaddr + SDHCI_TRANSFER_MODE); 76969f54698SShawn Guo else 770e149860dSRichard Zhu writel(val << 16 | imx_data->scratchpad, 77195f25efeSWolfram Sang host->ioaddr + SDHCI_TRANSFER_MODE); 77295f25efeSWolfram Sang return; 77395f25efeSWolfram Sang case SDHCI_BLOCK_SIZE: 77495f25efeSWolfram Sang val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 77595f25efeSWolfram Sang break; 77695f25efeSWolfram Sang } 77795f25efeSWolfram Sang esdhc_clrset_le(host, 0xffff, val, reg); 77895f25efeSWolfram Sang } 77995f25efeSWolfram Sang 78077da3da0SAaron Brice static u8 esdhc_readb_le(struct sdhci_host *host, int reg) 78177da3da0SAaron Brice { 78277da3da0SAaron Brice u8 ret; 78377da3da0SAaron Brice u32 val; 78477da3da0SAaron Brice 78577da3da0SAaron Brice switch (reg) { 78677da3da0SAaron Brice case SDHCI_HOST_CONTROL: 78777da3da0SAaron Brice val = readl(host->ioaddr + reg); 78877da3da0SAaron Brice 78977da3da0SAaron Brice ret = val & SDHCI_CTRL_LED; 79077da3da0SAaron Brice ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK; 79177da3da0SAaron Brice ret |= (val & ESDHC_CTRL_4BITBUS); 79277da3da0SAaron Brice ret |= (val & ESDHC_CTRL_8BITBUS) << 3; 79377da3da0SAaron Brice return ret; 79477da3da0SAaron Brice } 79577da3da0SAaron Brice 79677da3da0SAaron Brice return readb(host->ioaddr + reg); 79777da3da0SAaron Brice } 79877da3da0SAaron Brice 79995f25efeSWolfram Sang static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) 80095f25efeSWolfram Sang { 8019a0985b7SWilson Callan struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 802070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 80381a0a8bcSBenoît Thébaudeau u32 new_val = 0; 804af51079eSSascha Hauer u32 mask; 80595f25efeSWolfram Sang 80695f25efeSWolfram Sang switch (reg) { 80795f25efeSWolfram Sang case SDHCI_POWER_CONTROL: 80895f25efeSWolfram Sang /* 80995f25efeSWolfram Sang * FSL put some DMA bits here 81095f25efeSWolfram Sang * If your board has a regulator, code should be here 81195f25efeSWolfram Sang */ 81295f25efeSWolfram Sang return; 81395f25efeSWolfram Sang case SDHCI_HOST_CONTROL: 8146b40d182SShawn Guo /* FSL messed up here, so we need to manually compose it. */ 815af51079eSSascha Hauer new_val = val & SDHCI_CTRL_LED; 8167122bbb0SMasanari Iida /* ensure the endianness */ 81795f25efeSWolfram Sang new_val |= ESDHC_HOST_CONTROL_LE; 8189a0985b7SWilson Callan /* bits 8&9 are reserved on mx25 */ 8199a0985b7SWilson Callan if (!is_imx25_esdhc(imx_data)) { 82095f25efeSWolfram Sang /* DMA mode bits are shifted */ 82195f25efeSWolfram Sang new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 8229a0985b7SWilson Callan } 82395f25efeSWolfram Sang 824af51079eSSascha Hauer /* 825af51079eSSascha Hauer * Do not touch buswidth bits here. This is done in 826af51079eSSascha Hauer * esdhc_pltfm_bus_width. 827f6825748SMartin Fuzzey * Do not touch the D3CD bit either which is used for the 828d04f8d5bSBenoît Thébaudeau * SDIO interrupt erratum workaround. 829af51079eSSascha Hauer */ 830f6825748SMartin Fuzzey mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD); 831af51079eSSascha Hauer 832af51079eSSascha Hauer esdhc_clrset_le(host, mask, new_val, reg); 83395f25efeSWolfram Sang return; 83481a0a8bcSBenoît Thébaudeau case SDHCI_SOFTWARE_RESET: 83581a0a8bcSBenoît Thébaudeau if (val & SDHCI_RESET_DATA) 83681a0a8bcSBenoît Thébaudeau new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL); 83781a0a8bcSBenoît Thébaudeau break; 83895f25efeSWolfram Sang } 83995f25efeSWolfram Sang esdhc_clrset_le(host, 0xff, val, reg); 840913413c3SShawn Guo 84181a0a8bcSBenoît Thébaudeau if (reg == SDHCI_SOFTWARE_RESET) { 84281a0a8bcSBenoît Thébaudeau if (val & SDHCI_RESET_ALL) { 843913413c3SShawn Guo /* 84481a0a8bcSBenoît Thébaudeau * The esdhc has a design violation to SDHC spec which 84581a0a8bcSBenoît Thébaudeau * tells that software reset should not affect card 84681a0a8bcSBenoît Thébaudeau * detection circuit. But esdhc clears its SYSCTL 84781a0a8bcSBenoît Thébaudeau * register bits [0..2] during the software reset. This 84881a0a8bcSBenoît Thébaudeau * will stop those clocks that card detection circuit 84981a0a8bcSBenoît Thébaudeau * relies on. To work around it, we turn the clocks on 85081a0a8bcSBenoît Thébaudeau * back to keep card detection circuit functional. 851913413c3SShawn Guo */ 852913413c3SShawn Guo esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); 85358c8c4fbSShawn Guo /* 85458c8c4fbSShawn Guo * The reset on usdhc fails to clear MIX_CTRL register. 85558c8c4fbSShawn Guo * Do it manually here. 85658c8c4fbSShawn Guo */ 857de5bdbffSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 85881a0a8bcSBenoît Thébaudeau /* 85981a0a8bcSBenoît Thébaudeau * the tuning bits should be kept during reset 86081a0a8bcSBenoît Thébaudeau */ 861d131a71cSDong Aisheng new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); 862d131a71cSDong Aisheng writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK, 863d131a71cSDong Aisheng host->ioaddr + ESDHC_MIX_CTRL); 864de5bdbffSDong Aisheng imx_data->is_ddr = 0; 865de5bdbffSDong Aisheng } 86681a0a8bcSBenoît Thébaudeau } else if (val & SDHCI_RESET_DATA) { 86781a0a8bcSBenoît Thébaudeau /* 86881a0a8bcSBenoît Thébaudeau * The eSDHC DAT line software reset clears at least the 86981a0a8bcSBenoît Thébaudeau * data transfer width on i.MX25, so make sure that the 87081a0a8bcSBenoît Thébaudeau * Host Control register is unaffected. 87181a0a8bcSBenoît Thébaudeau */ 87281a0a8bcSBenoît Thébaudeau esdhc_clrset_le(host, 0xff, new_val, 87381a0a8bcSBenoît Thébaudeau SDHCI_HOST_CONTROL); 87481a0a8bcSBenoît Thébaudeau } 87558c8c4fbSShawn Guo } 87695f25efeSWolfram Sang } 87795f25efeSWolfram Sang 8780ddf03c9SLucas Stach static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) 8790ddf03c9SLucas Stach { 8800ddf03c9SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 8810ddf03c9SLucas Stach 882a974862fSDong Aisheng return pltfm_host->clock; 8830ddf03c9SLucas Stach } 8840ddf03c9SLucas Stach 88595f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) 88695f25efeSWolfram Sang { 88795f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 88895f25efeSWolfram Sang 889a974862fSDong Aisheng return pltfm_host->clock / 256 / 16; 89095f25efeSWolfram Sang } 89195f25efeSWolfram Sang 8928ba9580aSLucas Stach static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, 8938ba9580aSLucas Stach unsigned int clock) 8948ba9580aSLucas Stach { 8958ba9580aSLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 896070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 897a974862fSDong Aisheng unsigned int host_clock = pltfm_host->clock; 8985143c953SBenoît Thébaudeau int ddr_pre_div = imx_data->is_ddr ? 2 : 1; 8995143c953SBenoît Thébaudeau int pre_div = 1; 900d31fc00aSDong Aisheng int div = 1; 901f581e909SHaibo Chen int ret; 902fed2f6e2SDong Aisheng u32 temp, val; 9038ba9580aSLucas Stach 9049d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 905fed2f6e2SDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 906fed2f6e2SDong Aisheng writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 907fed2f6e2SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 908f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 909fed2f6e2SDong Aisheng } 91073e736f8SStefan Agner 91173e736f8SStefan Agner if (clock == 0) { 91273e736f8SStefan Agner host->mmc->actual_clock = 0; 913373073efSRussell King return; 914fed2f6e2SDong Aisheng } 915d31fc00aSDong Aisheng 916499ed50fSBenoît Thébaudeau /* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */ 917499ed50fSBenoît Thébaudeau if (is_imx53_esdhc(imx_data)) { 918499ed50fSBenoît Thébaudeau /* 919499ed50fSBenoît Thébaudeau * According to the i.MX53 reference manual, if DLLCTRL[10] can 920499ed50fSBenoît Thébaudeau * be set, then the controller is eSDHCv3, else it is eSDHCv2. 921499ed50fSBenoît Thébaudeau */ 922499ed50fSBenoît Thébaudeau val = readl(host->ioaddr + ESDHC_DLL_CTRL); 923499ed50fSBenoît Thébaudeau writel(val | BIT(10), host->ioaddr + ESDHC_DLL_CTRL); 924499ed50fSBenoît Thébaudeau temp = readl(host->ioaddr + ESDHC_DLL_CTRL); 925499ed50fSBenoît Thébaudeau writel(val, host->ioaddr + ESDHC_DLL_CTRL); 926499ed50fSBenoît Thébaudeau if (temp & BIT(10)) 927499ed50fSBenoît Thébaudeau pre_div = 2; 928499ed50fSBenoît Thébaudeau } 929499ed50fSBenoît Thébaudeau 930d31fc00aSDong Aisheng temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 931d31fc00aSDong Aisheng temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 932d31fc00aSDong Aisheng | ESDHC_CLOCK_MASK); 933d31fc00aSDong Aisheng sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 934d31fc00aSDong Aisheng 935af6a50d4SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) { 936af6a50d4SBOUGH CHEN unsigned int max_clock; 937af6a50d4SBOUGH CHEN 938af6a50d4SBOUGH CHEN max_clock = imx_data->is_ddr ? 45000000 : 150000000; 939af6a50d4SBOUGH CHEN 940af6a50d4SBOUGH CHEN clock = min(clock, max_clock); 941af6a50d4SBOUGH CHEN } 942af6a50d4SBOUGH CHEN 9435143c953SBenoît Thébaudeau while (host_clock / (16 * pre_div * ddr_pre_div) > clock && 9445143c953SBenoît Thébaudeau pre_div < 256) 945d31fc00aSDong Aisheng pre_div *= 2; 946d31fc00aSDong Aisheng 9475143c953SBenoît Thébaudeau while (host_clock / (div * pre_div * ddr_pre_div) > clock && div < 16) 948d31fc00aSDong Aisheng div++; 949d31fc00aSDong Aisheng 9505143c953SBenoît Thébaudeau host->mmc->actual_clock = host_clock / (div * pre_div * ddr_pre_div); 951d31fc00aSDong Aisheng dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", 952e76b8559SDong Aisheng clock, host->mmc->actual_clock); 953d31fc00aSDong Aisheng 954d31fc00aSDong Aisheng pre_div >>= 1; 955d31fc00aSDong Aisheng div--; 956d31fc00aSDong Aisheng 957d31fc00aSDong Aisheng temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 958d31fc00aSDong Aisheng temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 959d31fc00aSDong Aisheng | (div << ESDHC_DIVIDER_SHIFT) 960d31fc00aSDong Aisheng | (pre_div << ESDHC_PREDIV_SHIFT)); 961d31fc00aSDong Aisheng sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 962fed2f6e2SDong Aisheng 963f581e909SHaibo Chen /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */ 964f581e909SHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp, 965f581e909SHaibo Chen (temp & ESDHC_CLOCK_STABLE), 2, 100); 966f581e909SHaibo Chen if (ret == -ETIMEDOUT) 967f581e909SHaibo Chen dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n"); 968f581e909SHaibo Chen 9699d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 970fed2f6e2SDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 971fed2f6e2SDong Aisheng writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 972fed2f6e2SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 973fed2f6e2SDong Aisheng } 974fed2f6e2SDong Aisheng 9758ba9580aSLucas Stach } 9768ba9580aSLucas Stach 977913413c3SShawn Guo static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) 978913413c3SShawn Guo { 979842afc02SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 980070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 981842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 982913413c3SShawn Guo 983913413c3SShawn Guo switch (boarddata->wp_type) { 984913413c3SShawn Guo case ESDHC_WP_GPIO: 985fbe5fdd1SShawn Guo return mmc_gpio_get_ro(host->mmc); 986913413c3SShawn Guo case ESDHC_WP_CONTROLLER: 987913413c3SShawn Guo return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 988913413c3SShawn Guo SDHCI_WRITE_PROTECT); 989913413c3SShawn Guo case ESDHC_WP_NONE: 990913413c3SShawn Guo break; 991913413c3SShawn Guo } 992913413c3SShawn Guo 993913413c3SShawn Guo return -ENOSYS; 994913413c3SShawn Guo } 995913413c3SShawn Guo 9962317f56cSRussell King static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) 997af51079eSSascha Hauer { 998af51079eSSascha Hauer u32 ctrl; 999af51079eSSascha Hauer 1000af51079eSSascha Hauer switch (width) { 1001af51079eSSascha Hauer case MMC_BUS_WIDTH_8: 1002af51079eSSascha Hauer ctrl = ESDHC_CTRL_8BITBUS; 1003af51079eSSascha Hauer break; 1004af51079eSSascha Hauer case MMC_BUS_WIDTH_4: 1005af51079eSSascha Hauer ctrl = ESDHC_CTRL_4BITBUS; 1006af51079eSSascha Hauer break; 1007af51079eSSascha Hauer default: 1008af51079eSSascha Hauer ctrl = 0; 1009af51079eSSascha Hauer break; 1010af51079eSSascha Hauer } 1011af51079eSSascha Hauer 1012af51079eSSascha Hauer esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl, 1013af51079eSSascha Hauer SDHCI_HOST_CONTROL); 1014af51079eSSascha Hauer } 1015af51079eSSascha Hauer 1016*4fb27869SHaibo Chen static void esdhc_reset_tuning(struct sdhci_host *host) 1017*4fb27869SHaibo Chen { 1018*4fb27869SHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1019*4fb27869SHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1020*4fb27869SHaibo Chen u32 ctrl; 1021*4fb27869SHaibo Chen int ret; 1022*4fb27869SHaibo Chen 1023*4fb27869SHaibo Chen /* Reset the tuning circuit */ 1024*4fb27869SHaibo Chen if (esdhc_is_usdhc(imx_data)) { 1025*4fb27869SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 1026*4fb27869SHaibo Chen ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL); 1027*4fb27869SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 1028*4fb27869SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL; 1029*4fb27869SHaibo Chen writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); 1030*4fb27869SHaibo Chen writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 1031*4fb27869SHaibo Chen } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 1032*4fb27869SHaibo Chen ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1033*4fb27869SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 1034*4fb27869SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; 1035*4fb27869SHaibo Chen writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1036*4fb27869SHaibo Chen /* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */ 1037*4fb27869SHaibo Chen ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS, 1038*4fb27869SHaibo Chen ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50); 1039*4fb27869SHaibo Chen if (ret == -ETIMEDOUT) 1040*4fb27869SHaibo Chen dev_warn(mmc_dev(host->mmc), 1041*4fb27869SHaibo Chen "Warning! clear execute tuning bit failed\n"); 1042*4fb27869SHaibo Chen /* 1043*4fb27869SHaibo Chen * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the 1044*4fb27869SHaibo Chen * usdhc IP internal logic flag execute_tuning_with_clr_buf, which 1045*4fb27869SHaibo Chen * will finally make sure the normal data transfer logic correct. 1046*4fb27869SHaibo Chen */ 1047*4fb27869SHaibo Chen ctrl = readl(host->ioaddr + SDHCI_INT_STATUS); 1048*4fb27869SHaibo Chen ctrl |= SDHCI_INT_DATA_AVAIL; 1049*4fb27869SHaibo Chen writel(ctrl, host->ioaddr + SDHCI_INT_STATUS); 1050*4fb27869SHaibo Chen } 1051*4fb27869SHaibo Chen } 1052*4fb27869SHaibo Chen } 1053*4fb27869SHaibo Chen 1054de3e1dd0SBOUGH CHEN static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) 1055de3e1dd0SBOUGH CHEN { 1056de3e1dd0SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 1057de3e1dd0SBOUGH CHEN 1058de3e1dd0SBOUGH CHEN /* 1059de3e1dd0SBOUGH CHEN * i.MX uSDHC internally already uses a fixed optimized timing for 1060de3e1dd0SBOUGH CHEN * DDR50, normally does not require tuning for DDR50 mode. 1061de3e1dd0SBOUGH CHEN */ 1062de3e1dd0SBOUGH CHEN if (host->timing == MMC_TIMING_UHS_DDR50) 1063de3e1dd0SBOUGH CHEN return 0; 1064de3e1dd0SBOUGH CHEN 1065*4fb27869SHaibo Chen /* 1066*4fb27869SHaibo Chen * Reset tuning circuit logic. If not, the previous tuning result 1067*4fb27869SHaibo Chen * will impact current tuning, make current tuning can't set the 1068*4fb27869SHaibo Chen * correct delay cell. 1069*4fb27869SHaibo Chen */ 1070*4fb27869SHaibo Chen esdhc_reset_tuning(host); 1071de3e1dd0SBOUGH CHEN return sdhci_execute_tuning(mmc, opcode); 1072de3e1dd0SBOUGH CHEN } 1073de3e1dd0SBOUGH CHEN 10740322191eSDong Aisheng static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) 10750322191eSDong Aisheng { 10760322191eSDong Aisheng u32 reg; 10770ac4f496SHaibo Chen u8 sw_rst; 10780ac4f496SHaibo Chen int ret; 10790322191eSDong Aisheng 10800322191eSDong Aisheng /* FIXME: delay a bit for card to be ready for next tuning due to errors */ 10810322191eSDong Aisheng mdelay(1); 10820322191eSDong Aisheng 10830ac4f496SHaibo Chen /* IC suggest to reset USDHC before every tuning command */ 10840ac4f496SHaibo Chen esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET); 10850ac4f496SHaibo Chen ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst, 10860ac4f496SHaibo Chen !(sw_rst & SDHCI_RESET_ALL), 10, 100); 10870ac4f496SHaibo Chen if (ret == -ETIMEDOUT) 10880ac4f496SHaibo Chen dev_warn(mmc_dev(host->mmc), 10890ac4f496SHaibo Chen "warning! RESET_ALL never complete before sending tuning command\n"); 10900ac4f496SHaibo Chen 10910322191eSDong Aisheng reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 10920322191eSDong Aisheng reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | 10930322191eSDong Aisheng ESDHC_MIX_CTRL_FBCLK_SEL; 10940322191eSDong Aisheng writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 10950322191eSDong Aisheng writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 10960322191eSDong Aisheng dev_dbg(mmc_dev(host->mmc), 1097d04f8d5bSBenoît Thébaudeau "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", 10980322191eSDong Aisheng val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); 10990322191eSDong Aisheng } 11000322191eSDong Aisheng 11010322191eSDong Aisheng static void esdhc_post_tuning(struct sdhci_host *host) 11020322191eSDong Aisheng { 11030322191eSDong Aisheng u32 reg; 11040322191eSDong Aisheng 110545334ee1SHaibo Chen usdhc_auto_tuning_mode_sel(host); 110645334ee1SHaibo Chen 11070322191eSDong Aisheng reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 11080322191eSDong Aisheng reg &= ~ESDHC_MIX_CTRL_EXE_TUNE; 1109da0295ffSDong Aisheng reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; 11100322191eSDong Aisheng writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 11110322191eSDong Aisheng } 11120322191eSDong Aisheng 11130322191eSDong Aisheng static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) 11140322191eSDong Aisheng { 11150322191eSDong Aisheng int min, max, avg, ret; 11160322191eSDong Aisheng 11170322191eSDong Aisheng /* find the mininum delay first which can pass tuning */ 11180322191eSDong Aisheng min = ESDHC_TUNE_CTRL_MIN; 11190322191eSDong Aisheng while (min < ESDHC_TUNE_CTRL_MAX) { 11200322191eSDong Aisheng esdhc_prepare_tuning(host, min); 11219979dbe5SChaotian Jing if (!mmc_send_tuning(host->mmc, opcode, NULL)) 11220322191eSDong Aisheng break; 11230322191eSDong Aisheng min += ESDHC_TUNE_CTRL_STEP; 11240322191eSDong Aisheng } 11250322191eSDong Aisheng 11260322191eSDong Aisheng /* find the maxinum delay which can not pass tuning */ 11270322191eSDong Aisheng max = min + ESDHC_TUNE_CTRL_STEP; 11280322191eSDong Aisheng while (max < ESDHC_TUNE_CTRL_MAX) { 11290322191eSDong Aisheng esdhc_prepare_tuning(host, max); 11309979dbe5SChaotian Jing if (mmc_send_tuning(host->mmc, opcode, NULL)) { 11310322191eSDong Aisheng max -= ESDHC_TUNE_CTRL_STEP; 11320322191eSDong Aisheng break; 11330322191eSDong Aisheng } 11340322191eSDong Aisheng max += ESDHC_TUNE_CTRL_STEP; 11350322191eSDong Aisheng } 11360322191eSDong Aisheng 11370322191eSDong Aisheng /* use average delay to get the best timing */ 11380322191eSDong Aisheng avg = (min + max) / 2; 11390322191eSDong Aisheng esdhc_prepare_tuning(host, avg); 11409979dbe5SChaotian Jing ret = mmc_send_tuning(host->mmc, opcode, NULL); 11410322191eSDong Aisheng esdhc_post_tuning(host); 11420322191eSDong Aisheng 1143d04f8d5bSBenoît Thébaudeau dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n", 11440322191eSDong Aisheng ret ? "failed" : "passed", avg, ret); 11450322191eSDong Aisheng 11460322191eSDong Aisheng return ret; 11470322191eSDong Aisheng } 11480322191eSDong Aisheng 1149029e2476SBOUGH CHEN static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) 1150029e2476SBOUGH CHEN { 1151029e2476SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 1152029e2476SBOUGH CHEN u32 m; 1153029e2476SBOUGH CHEN 1154029e2476SBOUGH CHEN m = readl(host->ioaddr + ESDHC_MIX_CTRL); 1155029e2476SBOUGH CHEN if (ios->enhanced_strobe) 1156029e2476SBOUGH CHEN m |= ESDHC_MIX_CTRL_HS400_ES_EN; 1157029e2476SBOUGH CHEN else 1158029e2476SBOUGH CHEN m &= ~ESDHC_MIX_CTRL_HS400_ES_EN; 1159029e2476SBOUGH CHEN writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1160029e2476SBOUGH CHEN } 1161029e2476SBOUGH CHEN 1162ad93220dSDong Aisheng static int esdhc_change_pinstate(struct sdhci_host *host, 1163ad93220dSDong Aisheng unsigned int uhs) 1164ad93220dSDong Aisheng { 1165ad93220dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1166070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1167ad93220dSDong Aisheng struct pinctrl_state *pinctrl; 1168ad93220dSDong Aisheng 1169ad93220dSDong Aisheng dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs); 1170ad93220dSDong Aisheng 1171ad93220dSDong Aisheng if (IS_ERR(imx_data->pinctrl) || 1172ad93220dSDong Aisheng IS_ERR(imx_data->pins_100mhz) || 1173ad93220dSDong Aisheng IS_ERR(imx_data->pins_200mhz)) 1174ad93220dSDong Aisheng return -EINVAL; 1175ad93220dSDong Aisheng 1176ad93220dSDong Aisheng switch (uhs) { 1177ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR50: 11789f327845SHaibo Chen case MMC_TIMING_UHS_DDR50: 1179ad93220dSDong Aisheng pinctrl = imx_data->pins_100mhz; 1180ad93220dSDong Aisheng break; 1181ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR104: 1182429a5b45SDong Aisheng case MMC_TIMING_MMC_HS200: 118328b07674SHaibo Chen case MMC_TIMING_MMC_HS400: 1184ad93220dSDong Aisheng pinctrl = imx_data->pins_200mhz; 1185ad93220dSDong Aisheng break; 1186ad93220dSDong Aisheng default: 1187ad93220dSDong Aisheng /* back to default state for other legacy timing */ 11882480b720SUlf Hansson return pinctrl_select_default_state(mmc_dev(host->mmc)); 1189ad93220dSDong Aisheng } 1190ad93220dSDong Aisheng 1191ad93220dSDong Aisheng return pinctrl_select_state(imx_data->pinctrl, pinctrl); 1192ad93220dSDong Aisheng } 1193ad93220dSDong Aisheng 119428b07674SHaibo Chen /* 1195d04f8d5bSBenoît Thébaudeau * For HS400 eMMC, there is a data_strobe line. This signal is generated 119628b07674SHaibo Chen * by the device and used for data output and CRC status response output 119728b07674SHaibo Chen * in HS400 mode. The frequency of this signal follows the frequency of 1198d04f8d5bSBenoît Thébaudeau * CLK generated by host. The host receives the data which is aligned to the 119928b07674SHaibo Chen * edge of data_strobe line. Due to the time delay between CLK line and 120028b07674SHaibo Chen * data_strobe line, if the delay time is larger than one clock cycle, 1201d04f8d5bSBenoît Thébaudeau * then CLK and data_strobe line will be misaligned, read error shows up. 120228b07674SHaibo Chen */ 120328b07674SHaibo Chen static void esdhc_set_strobe_dll(struct sdhci_host *host) 120428b07674SHaibo Chen { 12055bd2acdcSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 12065bd2acdcSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 12075bd2acdcSHaibo Chen u32 strobe_delay; 120828b07674SHaibo Chen u32 v; 1209373e800bSHaibo Chen int ret; 121028b07674SHaibo Chen 12117ac6da26SDong Aisheng /* disable clock before enabling strobe dll */ 12127ac6da26SDong Aisheng writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & 12137ac6da26SDong Aisheng ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 12147ac6da26SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 1215f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 12167ac6da26SDong Aisheng 121728b07674SHaibo Chen /* force a reset on strobe dll */ 121828b07674SHaibo Chen writel(ESDHC_STROBE_DLL_CTRL_RESET, 121928b07674SHaibo Chen host->ioaddr + ESDHC_STROBE_DLL_CTRL); 12202eaf5a53SBOUGH CHEN /* clear the reset bit on strobe dll before any setting */ 12212eaf5a53SBOUGH CHEN writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL); 12222eaf5a53SBOUGH CHEN 122328b07674SHaibo Chen /* 122428b07674SHaibo Chen * enable strobe dll ctrl and adjust the delay target 122528b07674SHaibo Chen * for the uSDHC loopback read clock 122628b07674SHaibo Chen */ 12275bd2acdcSHaibo Chen if (imx_data->boarddata.strobe_dll_delay_target) 12285bd2acdcSHaibo Chen strobe_delay = imx_data->boarddata.strobe_dll_delay_target; 12295bd2acdcSHaibo Chen else 12305bd2acdcSHaibo Chen strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT; 123128b07674SHaibo Chen v = ESDHC_STROBE_DLL_CTRL_ENABLE | 12322eaf5a53SBOUGH CHEN ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT | 12335bd2acdcSHaibo Chen (strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); 123428b07674SHaibo Chen writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); 1235373e800bSHaibo Chen 1236373e800bSHaibo Chen /* wait max 50us to get the REF/SLV lock */ 1237373e800bSHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_STROBE_DLL_STATUS, v, 1238373e800bSHaibo Chen ((v & ESDHC_STROBE_DLL_STS_REF_LOCK) && (v & ESDHC_STROBE_DLL_STS_SLV_LOCK)), 1, 50); 1239373e800bSHaibo Chen if (ret == -ETIMEDOUT) 124028b07674SHaibo Chen dev_warn(mmc_dev(host->mmc), 1241373e800bSHaibo Chen "warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v); 124228b07674SHaibo Chen } 124328b07674SHaibo Chen 1244850a29b8SRussell King static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) 1245ad93220dSDong Aisheng { 124628b07674SHaibo Chen u32 m; 1247ad93220dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1248070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1249602519b2SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1250ad93220dSDong Aisheng 125128b07674SHaibo Chen /* disable ddr mode and disable HS400 mode */ 125228b07674SHaibo Chen m = readl(host->ioaddr + ESDHC_MIX_CTRL); 125328b07674SHaibo Chen m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN); 125428b07674SHaibo Chen imx_data->is_ddr = 0; 125528b07674SHaibo Chen 1256850a29b8SRussell King switch (timing) { 1257ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR12: 1258ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR25: 1259ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR50: 1260ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR104: 1261de0a0decSBOUGH CHEN case MMC_TIMING_MMC_HS: 1262429a5b45SDong Aisheng case MMC_TIMING_MMC_HS200: 126328b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1264ad93220dSDong Aisheng break; 1265ad93220dSDong Aisheng case MMC_TIMING_UHS_DDR50: 126669f5bf38SAisheng Dong case MMC_TIMING_MMC_DDR52: 126728b07674SHaibo Chen m |= ESDHC_MIX_CTRL_DDREN; 126828b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1269de5bdbffSDong Aisheng imx_data->is_ddr = 1; 1270602519b2SDong Aisheng if (boarddata->delay_line) { 1271602519b2SDong Aisheng u32 v; 1272602519b2SDong Aisheng v = boarddata->delay_line << 1273602519b2SDong Aisheng ESDHC_DLL_OVERRIDE_VAL_SHIFT | 1274602519b2SDong Aisheng (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT); 1275602519b2SDong Aisheng if (is_imx53_esdhc(imx_data)) 1276602519b2SDong Aisheng v <<= 1; 1277602519b2SDong Aisheng writel(v, host->ioaddr + ESDHC_DLL_CTRL); 1278602519b2SDong Aisheng } 1279ad93220dSDong Aisheng break; 128028b07674SHaibo Chen case MMC_TIMING_MMC_HS400: 128128b07674SHaibo Chen m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN; 128228b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 128328b07674SHaibo Chen imx_data->is_ddr = 1; 12847ac6da26SDong Aisheng /* update clock after enable DDR for strobe DLL lock */ 12857ac6da26SDong Aisheng host->ops->set_clock(host, host->clock); 128628b07674SHaibo Chen esdhc_set_strobe_dll(host); 128728b07674SHaibo Chen break; 1288d9370424SHaibo Chen case MMC_TIMING_LEGACY: 1289d9370424SHaibo Chen default: 1290d9370424SHaibo Chen esdhc_reset_tuning(host); 1291d9370424SHaibo Chen break; 1292ad93220dSDong Aisheng } 1293ad93220dSDong Aisheng 1294850a29b8SRussell King esdhc_change_pinstate(host, timing); 1295ad93220dSDong Aisheng } 1296ad93220dSDong Aisheng 12970718e59aSRussell King static void esdhc_reset(struct sdhci_host *host, u8 mask) 12980718e59aSRussell King { 1299fb1dec44SBrian Norris sdhci_and_cqhci_reset(host, mask); 13000718e59aSRussell King 13010718e59aSRussell King sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); 13020718e59aSRussell King sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); 13030718e59aSRussell King } 13040718e59aSRussell King 130510fd0ad9SAisheng Dong static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) 130610fd0ad9SAisheng Dong { 130710fd0ad9SAisheng Dong struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1308070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 130910fd0ad9SAisheng Dong 1310d04f8d5bSBenoît Thébaudeau /* Doc Erratum: the uSDHC actual maximum timeout count is 1 << 29 */ 13112fb0b02bSHaibo Chen return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27; 131210fd0ad9SAisheng Dong } 131310fd0ad9SAisheng Dong 1314e33eb8e2SAisheng Dong static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) 1315e33eb8e2SAisheng Dong { 1316e33eb8e2SAisheng Dong struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1317070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1318e33eb8e2SAisheng Dong 1319e33eb8e2SAisheng Dong /* use maximum timeout counter */ 1320a215186dSHaibo Chen esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK, 1321a215186dSHaibo Chen esdhc_is_usdhc(imx_data) ? 0xF : 0xE, 1322e33eb8e2SAisheng Dong SDHCI_TIMEOUT_CONTROL); 1323e33eb8e2SAisheng Dong } 1324e33eb8e2SAisheng Dong 1325bb6e3581SBOUGH CHEN static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) 1326bb6e3581SBOUGH CHEN { 1327bb6e3581SBOUGH CHEN int cmd_error = 0; 1328bb6e3581SBOUGH CHEN int data_error = 0; 1329bb6e3581SBOUGH CHEN 1330bb6e3581SBOUGH CHEN if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 1331bb6e3581SBOUGH CHEN return intmask; 1332bb6e3581SBOUGH CHEN 1333bb6e3581SBOUGH CHEN cqhci_irq(host->mmc, intmask, cmd_error, data_error); 1334bb6e3581SBOUGH CHEN 1335bb6e3581SBOUGH CHEN return 0; 1336bb6e3581SBOUGH CHEN } 1337bb6e3581SBOUGH CHEN 13386e9fd28eSDong Aisheng static struct sdhci_ops sdhci_esdhc_ops = { 1339e149860dSRichard Zhu .read_l = esdhc_readl_le, 13400c6d49ceSWolfram Sang .read_w = esdhc_readw_le, 134177da3da0SAaron Brice .read_b = esdhc_readb_le, 1342e149860dSRichard Zhu .write_l = esdhc_writel_le, 13430c6d49ceSWolfram Sang .write_w = esdhc_writew_le, 13440c6d49ceSWolfram Sang .write_b = esdhc_writeb_le, 13458ba9580aSLucas Stach .set_clock = esdhc_pltfm_set_clock, 13460ddf03c9SLucas Stach .get_max_clock = esdhc_pltfm_get_max_clock, 13470c6d49ceSWolfram Sang .get_min_clock = esdhc_pltfm_get_min_clock, 134810fd0ad9SAisheng Dong .get_max_timeout_count = esdhc_get_max_timeout_count, 1349913413c3SShawn Guo .get_ro = esdhc_pltfm_get_ro, 1350e33eb8e2SAisheng Dong .set_timeout = esdhc_set_timeout, 13512317f56cSRussell King .set_bus_width = esdhc_pltfm_set_bus_width, 1352ad93220dSDong Aisheng .set_uhs_signaling = esdhc_set_uhs_signaling, 13530718e59aSRussell King .reset = esdhc_reset, 1354bb6e3581SBOUGH CHEN .irq = esdhc_cqhci_irq, 13553722c74cSHaibo Chen .dump_vendor_regs = esdhc_dump_debug_regs, 13560c6d49ceSWolfram Sang }; 13570c6d49ceSWolfram Sang 13581db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 135997e4ba6aSRichard Zhu .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT 136097e4ba6aSRichard Zhu | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC 136197e4ba6aSRichard Zhu | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC 136285d6509dSShawn Guo | SDHCI_QUIRK_BROKEN_CARD_DETECTION, 136385d6509dSShawn Guo .ops = &sdhci_esdhc_ops, 136485d6509dSShawn Guo }; 136585d6509dSShawn Guo 1366f3f5cf3dSDong Aisheng static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) 1367f3f5cf3dSDong Aisheng { 1368f3f5cf3dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1369f3f5cf3dSDong Aisheng struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1370982cf37dSHaibo Chen struct cqhci_host *cq_host = host->mmc->cqe_private; 13712b16cf32SDong Aisheng int tmp; 1372f3f5cf3dSDong Aisheng 1373f3f5cf3dSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 1374f3f5cf3dSDong Aisheng /* 1375f3f5cf3dSDong Aisheng * The imx6q ROM code will change the default watermark 1376f3f5cf3dSDong Aisheng * level setting to something insane. Change it back here. 1377f3f5cf3dSDong Aisheng */ 1378f3f5cf3dSDong Aisheng writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL); 1379f3f5cf3dSDong Aisheng 1380f3f5cf3dSDong Aisheng /* 1381f3f5cf3dSDong Aisheng * ROM code will change the bit burst_length_enable setting 1382d04f8d5bSBenoît Thébaudeau * to zero if this usdhc is chosen to boot system. Change 1383f3f5cf3dSDong Aisheng * it back here, otherwise it will impact the performance a 1384f3f5cf3dSDong Aisheng * lot. This bit is used to enable/disable the burst length 1385d04f8d5bSBenoît Thébaudeau * for the external AHB2AXI bridge. It's useful especially 1386f3f5cf3dSDong Aisheng * for INCR transfer because without burst length indicator, 1387f3f5cf3dSDong Aisheng * the AHB2AXI bridge does not know the burst length in 1388f3f5cf3dSDong Aisheng * advance. And without burst length indicator, AHB INCR 1389f3f5cf3dSDong Aisheng * transfer can only be converted to singles on the AXI side. 1390f3f5cf3dSDong Aisheng */ 1391f3f5cf3dSDong Aisheng writel(readl(host->ioaddr + SDHCI_HOST_CONTROL) 1392f3f5cf3dSDong Aisheng | ESDHC_BURST_LEN_EN_INCR, 1393f3f5cf3dSDong Aisheng host->ioaddr + SDHCI_HOST_CONTROL); 1394e30be063SBOUGH CHEN 1395f3f5cf3dSDong Aisheng /* 1396d04f8d5bSBenoît Thébaudeau * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL 1397f3f5cf3dSDong Aisheng * TO1.1, it's harmless for MX6SL 1398f3f5cf3dSDong Aisheng */ 13995c4f0062SChester Lin if (!(imx_data->socdata->flags & ESDHC_FLAG_SKIP_ERR004536)) { 1400e30be063SBOUGH CHEN writel(readl(host->ioaddr + 0x6c) & ~BIT(7), 1401f3f5cf3dSDong Aisheng host->ioaddr + 0x6c); 14025c4f0062SChester Lin } 1403f3f5cf3dSDong Aisheng 1404f3f5cf3dSDong Aisheng /* disable DLL_CTRL delay line settings */ 1405f3f5cf3dSDong Aisheng writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); 14062b16cf32SDong Aisheng 1407bcdb5301SBOUGH CHEN /* 1408bcdb5301SBOUGH CHEN * For the case of command with busy, if set the bit 1409bcdb5301SBOUGH CHEN * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a 1410bcdb5301SBOUGH CHEN * transfer complete interrupt when busy is deasserted. 1411bcdb5301SBOUGH CHEN * When CQHCI use DCMD to send a CMD need R1b respons, 1412bcdb5301SBOUGH CHEN * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ, 1413bcdb5301SBOUGH CHEN * otherwise DCMD will always meet timeout waiting for 1414bcdb5301SBOUGH CHEN * hardware interrupt issue. 1415bcdb5301SBOUGH CHEN */ 1416bcdb5301SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { 1417bcdb5301SBOUGH CHEN tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2); 1418bcdb5301SBOUGH CHEN tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ; 1419bcdb5301SBOUGH CHEN writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2); 1420bcdb5301SBOUGH CHEN 1421bcdb5301SBOUGH CHEN host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; 1422bcdb5301SBOUGH CHEN } 1423bcdb5301SBOUGH CHEN 14242b16cf32SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 14252b16cf32SDong Aisheng tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); 14262b16cf32SDong Aisheng tmp |= ESDHC_STD_TUNING_EN | 14272b16cf32SDong Aisheng ESDHC_TUNING_START_TAP_DEFAULT; 14282b16cf32SDong Aisheng if (imx_data->boarddata.tuning_start_tap) { 14292b16cf32SDong Aisheng tmp &= ~ESDHC_TUNING_START_TAP_MASK; 14302b16cf32SDong Aisheng tmp |= imx_data->boarddata.tuning_start_tap; 14312b16cf32SDong Aisheng } 14322b16cf32SDong Aisheng 14332b16cf32SDong Aisheng if (imx_data->boarddata.tuning_step) { 14342b16cf32SDong Aisheng tmp &= ~ESDHC_TUNING_STEP_MASK; 14352b16cf32SDong Aisheng tmp |= imx_data->boarddata.tuning_step 14362b16cf32SDong Aisheng << ESDHC_TUNING_STEP_SHIFT; 14372b16cf32SDong Aisheng } 143816e40e5bSHaibo Chen 143916e40e5bSHaibo Chen /* Disable the CMD CRC check for tuning, if not, need to 144016e40e5bSHaibo Chen * add some delay after every tuning command, because 144116e40e5bSHaibo Chen * hardware standard tuning logic will directly go to next 144216e40e5bSHaibo Chen * step once it detect the CMD CRC error, will not wait for 144316e40e5bSHaibo Chen * the card side to finally send out the tuning data, trigger 144416e40e5bSHaibo Chen * the buffer read ready interrupt immediately. If usdhc send 144516e40e5bSHaibo Chen * the next tuning command some eMMC card will stuck, can't 144616e40e5bSHaibo Chen * response, block the tuning procedure or the first command 144716e40e5bSHaibo Chen * after the whole tuning procedure always can't get any response. 144816e40e5bSHaibo Chen */ 144916e40e5bSHaibo Chen tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; 14502b16cf32SDong Aisheng writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); 1451a98c557eSBOUGH CHEN } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 1452a98c557eSBOUGH CHEN /* 1453a98c557eSBOUGH CHEN * ESDHC_STD_TUNING_EN may be configed in bootloader 1454a98c557eSBOUGH CHEN * or ROM code, so clear this bit here to make sure 1455a98c557eSBOUGH CHEN * the manual tuning can work. 1456a98c557eSBOUGH CHEN */ 1457a98c557eSBOUGH CHEN tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); 1458a98c557eSBOUGH CHEN tmp &= ~ESDHC_STD_TUNING_EN; 1459a98c557eSBOUGH CHEN writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); 14602b16cf32SDong Aisheng } 1461982cf37dSHaibo Chen 1462982cf37dSHaibo Chen /* 1463982cf37dSHaibo Chen * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card 14641ad0dcb9Swangjianli * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let 1465982cf37dSHaibo Chen * the 1st linux configure power/clock for the 2nd Linux. 1466982cf37dSHaibo Chen * 1467982cf37dSHaibo Chen * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux 1468982cf37dSHaibo Chen * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump. 1469982cf37dSHaibo Chen * After we clear the pending interrupt and halt CQCTL, issue gone. 1470982cf37dSHaibo Chen */ 1471982cf37dSHaibo Chen if (cq_host) { 1472982cf37dSHaibo Chen tmp = cqhci_readl(cq_host, CQHCI_IS); 1473982cf37dSHaibo Chen cqhci_writel(cq_host, tmp, CQHCI_IS); 1474982cf37dSHaibo Chen cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL); 1475982cf37dSHaibo Chen } 1476f3f5cf3dSDong Aisheng } 1477f3f5cf3dSDong Aisheng } 1478f3f5cf3dSDong Aisheng 1479bb6e3581SBOUGH CHEN static void esdhc_cqe_enable(struct mmc_host *mmc) 1480bb6e3581SBOUGH CHEN { 1481bb6e3581SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 148285236d2bSBOUGH CHEN struct cqhci_host *cq_host = mmc->cqe_private; 1483bb6e3581SBOUGH CHEN u32 reg; 1484bb6e3581SBOUGH CHEN u16 mode; 1485bb6e3581SBOUGH CHEN int count = 10; 1486bb6e3581SBOUGH CHEN 1487bb6e3581SBOUGH CHEN /* 1488bb6e3581SBOUGH CHEN * CQE gets stuck if it sees Buffer Read Enable bit set, which can be 1489bb6e3581SBOUGH CHEN * the case after tuning, so ensure the buffer is drained. 1490bb6e3581SBOUGH CHEN */ 1491bb6e3581SBOUGH CHEN reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 1492bb6e3581SBOUGH CHEN while (reg & SDHCI_DATA_AVAILABLE) { 1493bb6e3581SBOUGH CHEN sdhci_readl(host, SDHCI_BUFFER); 1494bb6e3581SBOUGH CHEN reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 1495bb6e3581SBOUGH CHEN if (count-- == 0) { 1496bb6e3581SBOUGH CHEN dev_warn(mmc_dev(host->mmc), 1497bb6e3581SBOUGH CHEN "CQE may get stuck because the Buffer Read Enable bit is set\n"); 1498bb6e3581SBOUGH CHEN break; 1499bb6e3581SBOUGH CHEN } 1500bb6e3581SBOUGH CHEN mdelay(1); 1501bb6e3581SBOUGH CHEN } 1502bb6e3581SBOUGH CHEN 1503bb6e3581SBOUGH CHEN /* 1504bb6e3581SBOUGH CHEN * Runtime resume will reset the entire host controller, which 1505bb6e3581SBOUGH CHEN * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL. 1506bb6e3581SBOUGH CHEN * Here set DMAEN and BCEN when enable CMDQ. 1507bb6e3581SBOUGH CHEN */ 1508bb6e3581SBOUGH CHEN mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); 1509bb6e3581SBOUGH CHEN if (host->flags & SDHCI_REQ_USE_DMA) 1510bb6e3581SBOUGH CHEN mode |= SDHCI_TRNS_DMA; 1511bb6e3581SBOUGH CHEN if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) 1512bb6e3581SBOUGH CHEN mode |= SDHCI_TRNS_BLK_CNT_EN; 1513bb6e3581SBOUGH CHEN sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); 1514bb6e3581SBOUGH CHEN 151585236d2bSBOUGH CHEN /* 151685236d2bSBOUGH CHEN * Though Runtime resume reset the entire host controller, 151785236d2bSBOUGH CHEN * but do not impact the CQHCI side, need to clear the 151885236d2bSBOUGH CHEN * HALT bit, avoid CQHCI stuck in the first request when 151985236d2bSBOUGH CHEN * system resume back. 152085236d2bSBOUGH CHEN */ 152185236d2bSBOUGH CHEN cqhci_writel(cq_host, 0, CQHCI_CTL); 1522a3cab1d2SSebastian Falbesoner if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) 152385236d2bSBOUGH CHEN dev_err(mmc_dev(host->mmc), 152485236d2bSBOUGH CHEN "failed to exit halt state when enable CQE\n"); 152585236d2bSBOUGH CHEN 152685236d2bSBOUGH CHEN 1527bb6e3581SBOUGH CHEN sdhci_cqe_enable(mmc); 1528bb6e3581SBOUGH CHEN } 1529bb6e3581SBOUGH CHEN 1530bb6e3581SBOUGH CHEN static void esdhc_sdhci_dumpregs(struct mmc_host *mmc) 1531bb6e3581SBOUGH CHEN { 1532bb6e3581SBOUGH CHEN sdhci_dumpregs(mmc_priv(mmc)); 1533bb6e3581SBOUGH CHEN } 1534bb6e3581SBOUGH CHEN 1535bb6e3581SBOUGH CHEN static const struct cqhci_host_ops esdhc_cqhci_ops = { 1536bb6e3581SBOUGH CHEN .enable = esdhc_cqe_enable, 1537bb6e3581SBOUGH CHEN .disable = sdhci_cqe_disable, 1538bb6e3581SBOUGH CHEN .dumpregs = esdhc_sdhci_dumpregs, 1539bb6e3581SBOUGH CHEN }; 1540bb6e3581SBOUGH CHEN 1541c3be1efdSBill Pemberton static int 1542abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 154307bf2b54SSascha Hauer struct sdhci_host *host, 154491fa4252SDong Aisheng struct pltfm_imx_data *imx_data) 1545abfafc2dSShawn Guo { 1546abfafc2dSShawn Guo struct device_node *np = pdev->dev.of_node; 154791fa4252SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 15484800e87aSDong Aisheng int ret; 1549abfafc2dSShawn Guo 1550abfafc2dSShawn Guo if (of_get_property(np, "fsl,wp-controller", NULL)) 1551abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_CONTROLLER; 1552abfafc2dSShawn Guo 155374ff81e1SLinus Walleij /* 155474ff81e1SLinus Walleij * If we have this property, then activate WP check. 155574ff81e1SLinus Walleij * Retrieveing and requesting the actual WP GPIO will happen 155674ff81e1SLinus Walleij * in the call to mmc_of_parse(). 155774ff81e1SLinus Walleij */ 155874ff81e1SLinus Walleij if (of_property_read_bool(np, "wp-gpios")) 1559abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_GPIO; 1560abfafc2dSShawn Guo 1561d407e30bSHaibo Chen of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step); 1562d87fc966SDong Aisheng of_property_read_u32(np, "fsl,tuning-start-tap", 1563d87fc966SDong Aisheng &boarddata->tuning_start_tap); 1564d407e30bSHaibo Chen 15655bd2acdcSHaibo Chen of_property_read_u32(np, "fsl,strobe-dll-delay-target", 15665bd2acdcSHaibo Chen &boarddata->strobe_dll_delay_target); 1567ad93220dSDong Aisheng if (of_find_property(np, "no-1-8-v", NULL)) 156886f495c5SStefan Agner host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; 1569ad93220dSDong Aisheng 1570602519b2SDong Aisheng if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line)) 1571602519b2SDong Aisheng boarddata->delay_line = 0; 1572602519b2SDong Aisheng 15736dab809bSAndy Shevchenko mmc_of_parse_voltage(host->mmc, &host->ocr_mask); 157407bf2b54SSascha Hauer 1575f410ee0aSPeng Fan if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pinctrl)) { 157691fa4252SDong Aisheng imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl, 157791fa4252SDong Aisheng ESDHC_PINCTRL_STATE_100MHZ); 157891fa4252SDong Aisheng imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl, 157991fa4252SDong Aisheng ESDHC_PINCTRL_STATE_200MHZ); 158091fa4252SDong Aisheng } 158191fa4252SDong Aisheng 158215064119SFabio Estevam /* call to generic mmc_of_parse to support additional capabilities */ 15834800e87aSDong Aisheng ret = mmc_of_parse(host->mmc); 15844800e87aSDong Aisheng if (ret) 15854800e87aSDong Aisheng return ret; 15864800e87aSDong Aisheng 1587287980e4SArnd Bergmann if (mmc_gpio_get_cd(host->mmc) >= 0) 15884800e87aSDong Aisheng host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 15894800e87aSDong Aisheng 15904800e87aSDong Aisheng return 0; 1591abfafc2dSShawn Guo } 1592abfafc2dSShawn Guo 1593c3be1efdSBill Pemberton static int sdhci_esdhc_imx_probe(struct platform_device *pdev) 159495f25efeSWolfram Sang { 159585d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 159685d6509dSShawn Guo struct sdhci_host *host; 1597bb6e3581SBOUGH CHEN struct cqhci_host *cq_host; 15980c6d49ceSWolfram Sang int err; 1599e149860dSRichard Zhu struct pltfm_imx_data *imx_data; 160095f25efeSWolfram Sang 1601070e6d3fSJisheng Zhang host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 1602070e6d3fSJisheng Zhang sizeof(*imx_data)); 160385d6509dSShawn Guo if (IS_ERR(host)) 160485d6509dSShawn Guo return PTR_ERR(host); 160585d6509dSShawn Guo 160685d6509dSShawn Guo pltfm_host = sdhci_priv(host); 160785d6509dSShawn Guo 1608070e6d3fSJisheng Zhang imx_data = sdhci_pltfm_priv(pltfm_host); 160957ed3314SShawn Guo 161091b3d2e5SFabio Estevam imx_data->socdata = device_get_match_data(&pdev->dev); 161185d6509dSShawn Guo 16121c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1613d1b98305SRafael J. Wysocki cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 16141c4989b0SBOUGH CHEN 161552dac615SSascha Hauer imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 161652dac615SSascha Hauer if (IS_ERR(imx_data->clk_ipg)) { 161752dac615SSascha Hauer err = PTR_ERR(imx_data->clk_ipg); 1618e3af31c6SShawn Guo goto free_sdhci; 161995f25efeSWolfram Sang } 162052dac615SSascha Hauer 162152dac615SSascha Hauer imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); 162252dac615SSascha Hauer if (IS_ERR(imx_data->clk_ahb)) { 162352dac615SSascha Hauer err = PTR_ERR(imx_data->clk_ahb); 1624e3af31c6SShawn Guo goto free_sdhci; 162552dac615SSascha Hauer } 162652dac615SSascha Hauer 162752dac615SSascha Hauer imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); 162852dac615SSascha Hauer if (IS_ERR(imx_data->clk_per)) { 162952dac615SSascha Hauer err = PTR_ERR(imx_data->clk_per); 1630e3af31c6SShawn Guo goto free_sdhci; 163152dac615SSascha Hauer } 163252dac615SSascha Hauer 163352dac615SSascha Hauer pltfm_host->clk = imx_data->clk_per; 1634a974862fSDong Aisheng pltfm_host->clock = clk_get_rate(pltfm_host->clk); 163517b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_per); 163617b1eb7fSFabio Estevam if (err) 163717b1eb7fSFabio Estevam goto free_sdhci; 163817b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ipg); 163917b1eb7fSFabio Estevam if (err) 164017b1eb7fSFabio Estevam goto disable_per_clk; 164117b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ahb); 164217b1eb7fSFabio Estevam if (err) 164317b1eb7fSFabio Estevam goto disable_ipg_clk; 164495f25efeSWolfram Sang 1645ad93220dSDong Aisheng imx_data->pinctrl = devm_pinctrl_get(&pdev->dev); 16469e70ff99SHaibo Chen if (IS_ERR(imx_data->pinctrl)) 1647b62eee9fSHaibo Chen dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n"); 1648e62d8b8fSDong Aisheng 164969ed60e0SDong Aisheng if (esdhc_is_usdhc(imx_data)) { 165069ed60e0SDong Aisheng host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; 165109c8192bSStefan Agner host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR; 1652f6140462SHaibo Chen 1653f6140462SHaibo Chen /* GPIO CD can be set as a wakeup source */ 1654f6140462SHaibo Chen host->mmc->caps |= MMC_CAP_CD_WAKE; 1655f6140462SHaibo Chen 16564245afffSDong Aisheng if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) 16574245afffSDong Aisheng host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; 1658a75dcbf4SDong Aisheng 1659a75dcbf4SDong Aisheng /* clear tuning bits in case ROM has set it already */ 1660a75dcbf4SDong Aisheng writel(0x0, host->ioaddr + ESDHC_MIX_CTRL); 1661869f8a69SAdrian Hunter writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1662a75dcbf4SDong Aisheng writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 1663de3e1dd0SBOUGH CHEN 1664de3e1dd0SBOUGH CHEN /* 1665de3e1dd0SBOUGH CHEN * Link usdhc specific mmc_host_ops execute_tuning function, 1666de3e1dd0SBOUGH CHEN * to replace the standard one in sdhci_ops. 1667de3e1dd0SBOUGH CHEN */ 1668de3e1dd0SBOUGH CHEN host->mmc_host_ops.execute_tuning = usdhc_execute_tuning; 166969ed60e0SDong Aisheng } 1670f750ba9bSShawn Guo 16711ed5c3b2SSascha Hauer err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); 16721ed5c3b2SSascha Hauer if (err) 16731ed5c3b2SSascha Hauer goto disable_ahb_clk; 16741ed5c3b2SSascha Hauer 16756e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) 16766e9fd28eSDong Aisheng sdhci_esdhc_ops.platform_execute_tuning = 16776e9fd28eSDong Aisheng esdhc_executing_tuning; 16788b2bb0adSDong Aisheng 167918094430SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) 168018094430SDong Aisheng host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; 168118094430SDong Aisheng 1682f002f45aSHaibo Chen if (host->mmc->caps & MMC_CAP_8_BIT_DATA && 16831ed5c3b2SSascha Hauer imx_data->socdata->flags & ESDHC_FLAG_HS400) 16842991ad76SLucas Stach host->mmc->caps2 |= MMC_CAP2_HS400; 168528b07674SHaibo Chen 168674898cbcSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23) 168774898cbcSHaibo Chen host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN; 168874898cbcSHaibo Chen 1689f002f45aSHaibo Chen if (host->mmc->caps & MMC_CAP_8_BIT_DATA && 16901ed5c3b2SSascha Hauer imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) { 1691029e2476SBOUGH CHEN host->mmc->caps2 |= MMC_CAP2_HS400_ES; 1692029e2476SBOUGH CHEN host->mmc_host_ops.hs400_enhanced_strobe = 1693029e2476SBOUGH CHEN esdhc_hs400_enhanced_strobe; 1694029e2476SBOUGH CHEN } 1695029e2476SBOUGH CHEN 1696bb6e3581SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { 1697bcdb5301SBOUGH CHEN host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 1698bb6e3581SBOUGH CHEN cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL); 16999a633f3bSWei Yongjun if (!cq_host) { 17009a633f3bSWei Yongjun err = -ENOMEM; 1701bb6e3581SBOUGH CHEN goto disable_ahb_clk; 1702bb6e3581SBOUGH CHEN } 1703bb6e3581SBOUGH CHEN 1704bb6e3581SBOUGH CHEN cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET; 1705bb6e3581SBOUGH CHEN cq_host->ops = &esdhc_cqhci_ops; 1706bb6e3581SBOUGH CHEN 1707bb6e3581SBOUGH CHEN err = cqhci_init(cq_host, host->mmc, false); 1708bb6e3581SBOUGH CHEN if (err) 1709bb6e3581SBOUGH CHEN goto disable_ahb_clk; 1710bb6e3581SBOUGH CHEN } 1711bb6e3581SBOUGH CHEN 1712f3f5cf3dSDong Aisheng sdhci_esdhc_imx_hwinit(host); 1713f3f5cf3dSDong Aisheng 171485d6509dSShawn Guo err = sdhci_add_host(host); 171585d6509dSShawn Guo if (err) 171617b1eb7fSFabio Estevam goto disable_ahb_clk; 171785d6509dSShawn Guo 1718f62f7bccSHaibo Chen /* 1719f62f7bccSHaibo Chen * Setup the wakeup capability here, let user to decide 1720f62f7bccSHaibo Chen * whether need to enable this wakeup through sysfs interface. 1721f62f7bccSHaibo Chen */ 1722f62f7bccSHaibo Chen if ((host->mmc->pm_caps & MMC_PM_KEEP_POWER) && 1723f62f7bccSHaibo Chen (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ)) 1724f62f7bccSHaibo Chen device_set_wakeup_capable(&pdev->dev, true); 1725f62f7bccSHaibo Chen 172689d7e5c1SDong Aisheng pm_runtime_set_active(&pdev->dev); 172789d7e5c1SDong Aisheng pm_runtime_set_autosuspend_delay(&pdev->dev, 50); 172889d7e5c1SDong Aisheng pm_runtime_use_autosuspend(&pdev->dev); 172989d7e5c1SDong Aisheng pm_suspend_ignore_children(&pdev->dev, 1); 173077903c01SUlf Hansson pm_runtime_enable(&pdev->dev); 173189d7e5c1SDong Aisheng 17327e29c306SWolfram Sang return 0; 17337e29c306SWolfram Sang 173417b1eb7fSFabio Estevam disable_ahb_clk: 173552dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ahb); 173617b1eb7fSFabio Estevam disable_ipg_clk: 173717b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_ipg); 173817b1eb7fSFabio Estevam disable_per_clk: 173917b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_per); 1740e3af31c6SShawn Guo free_sdhci: 17411c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1742d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 174385d6509dSShawn Guo sdhci_pltfm_free(pdev); 174485d6509dSShawn Guo return err; 174595f25efeSWolfram Sang } 174695f25efeSWolfram Sang 17476e0ee714SBill Pemberton static int sdhci_esdhc_imx_remove(struct platform_device *pdev) 174895f25efeSWolfram Sang { 174985d6509dSShawn Guo struct sdhci_host *host = platform_get_drvdata(pdev); 175095f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1751070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1752a56f4413SFrank Li int dead; 175385d6509dSShawn Guo 17540b414368SUlf Hansson pm_runtime_get_sync(&pdev->dev); 1755a56f4413SFrank Li dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 17560b414368SUlf Hansson pm_runtime_disable(&pdev->dev); 17570b414368SUlf Hansson pm_runtime_put_noidle(&pdev->dev); 17580b414368SUlf Hansson 175985d6509dSShawn Guo sdhci_remove_host(host, dead); 17600c6d49ceSWolfram Sang 176152dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_per); 176252dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ipg); 176352dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ahb); 176452dac615SSascha Hauer 17651c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1766d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 17671c4989b0SBOUGH CHEN 176885d6509dSShawn Guo sdhci_pltfm_free(pdev); 176985d6509dSShawn Guo 177085d6509dSShawn Guo return 0; 177195f25efeSWolfram Sang } 177295f25efeSWolfram Sang 17732788ed42SUlf Hansson #ifdef CONFIG_PM_SLEEP 177404143fbaSDong Aisheng static int sdhci_esdhc_suspend(struct device *dev) 177504143fbaSDong Aisheng { 17763e3274abSUlf Hansson struct sdhci_host *host = dev_get_drvdata(dev); 1777a26a4f1bSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1778a26a4f1bSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1779bb6e3581SBOUGH CHEN int ret; 1780bb6e3581SBOUGH CHEN 1781bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) { 1782bb6e3581SBOUGH CHEN ret = cqhci_suspend(host->mmc); 1783bb6e3581SBOUGH CHEN if (ret) 1784bb6e3581SBOUGH CHEN return ret; 1785bb6e3581SBOUGH CHEN } 17863e3274abSUlf Hansson 1787a26a4f1bSHaibo Chen if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) && 1788a26a4f1bSHaibo Chen (host->tuning_mode != SDHCI_TUNING_MODE_1)) { 1789a26a4f1bSHaibo Chen mmc_retune_timer_stop(host->mmc); 1790a26a4f1bSHaibo Chen mmc_retune_needed(host->mmc); 1791a26a4f1bSHaibo Chen } 1792a26a4f1bSHaibo Chen 1793d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 1794d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 1795d38dcad4SAdrian Hunter 1796af8fade4SHaibo Chen ret = sdhci_suspend_host(host); 1797f6140462SHaibo Chen if (ret) 1798f6140462SHaibo Chen return ret; 1799f6140462SHaibo Chen 1800f6140462SHaibo Chen ret = pinctrl_pm_select_sleep_state(dev); 1801f6140462SHaibo Chen if (ret) 1802f6140462SHaibo Chen return ret; 1803f6140462SHaibo Chen 1804f6140462SHaibo Chen ret = mmc_gpio_set_cd_wake(host->mmc, true); 1805af8fade4SHaibo Chen 1806af8fade4SHaibo Chen return ret; 180704143fbaSDong Aisheng } 180804143fbaSDong Aisheng 180904143fbaSDong Aisheng static int sdhci_esdhc_resume(struct device *dev) 181004143fbaSDong Aisheng { 1811cc17e129SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 1812bb6e3581SBOUGH CHEN int ret; 1813cc17e129SDong Aisheng 1814af8fade4SHaibo Chen ret = pinctrl_pm_select_default_state(dev); 1815af8fade4SHaibo Chen if (ret) 1816af8fade4SHaibo Chen return ret; 1817af8fade4SHaibo Chen 181819dbfdd3SDong Aisheng /* re-initialize hw state in case it's lost in low power mode */ 181919dbfdd3SDong Aisheng sdhci_esdhc_imx_hwinit(host); 1820cc17e129SDong Aisheng 1821bb6e3581SBOUGH CHEN ret = sdhci_resume_host(host); 1822bb6e3581SBOUGH CHEN if (ret) 1823bb6e3581SBOUGH CHEN return ret; 1824bb6e3581SBOUGH CHEN 1825bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) 1826bb6e3581SBOUGH CHEN ret = cqhci_resume(host->mmc); 1827bb6e3581SBOUGH CHEN 1828f6140462SHaibo Chen if (!ret) 1829f6140462SHaibo Chen ret = mmc_gpio_set_cd_wake(host->mmc, false); 1830f6140462SHaibo Chen 1831bb6e3581SBOUGH CHEN return ret; 183204143fbaSDong Aisheng } 18332788ed42SUlf Hansson #endif 183404143fbaSDong Aisheng 18352788ed42SUlf Hansson #ifdef CONFIG_PM 183689d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_suspend(struct device *dev) 183789d7e5c1SDong Aisheng { 183889d7e5c1SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 183989d7e5c1SDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1840070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 184189d7e5c1SDong Aisheng int ret; 184289d7e5c1SDong Aisheng 1843bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) { 1844bb6e3581SBOUGH CHEN ret = cqhci_suspend(host->mmc); 1845bb6e3581SBOUGH CHEN if (ret) 1846bb6e3581SBOUGH CHEN return ret; 1847bb6e3581SBOUGH CHEN } 1848bb6e3581SBOUGH CHEN 184989d7e5c1SDong Aisheng ret = sdhci_runtime_suspend_host(host); 1850371d39faSMichael Trimarchi if (ret) 1851371d39faSMichael Trimarchi return ret; 185289d7e5c1SDong Aisheng 1853d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 1854d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 1855d38dcad4SAdrian Hunter 18563602785bSMichael Trimarchi imx_data->actual_clock = host->mmc->actual_clock; 18573602785bSMichael Trimarchi esdhc_pltfm_set_clock(host, 0); 185889d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_per); 185989d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_ipg); 186089d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_ahb); 186189d7e5c1SDong Aisheng 18621c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1863d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 18641c4989b0SBOUGH CHEN 186589d7e5c1SDong Aisheng return ret; 186689d7e5c1SDong Aisheng } 186789d7e5c1SDong Aisheng 186889d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_resume(struct device *dev) 186989d7e5c1SDong Aisheng { 187089d7e5c1SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 187189d7e5c1SDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1872070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 187317b1eb7fSFabio Estevam int err; 187489d7e5c1SDong Aisheng 18751c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1876d1b98305SRafael J. Wysocki cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 18771c4989b0SBOUGH CHEN 18785c11f1ffSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME) 18795c11f1ffSHaibo Chen clk_set_rate(imx_data->clk_per, pltfm_host->clock); 18805c11f1ffSHaibo Chen 1881a0ad3087SMichael Trimarchi err = clk_prepare_enable(imx_data->clk_ahb); 1882a0ad3087SMichael Trimarchi if (err) 18831c4989b0SBOUGH CHEN goto remove_pm_qos_request; 1884a0ad3087SMichael Trimarchi 188517b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_per); 188617b1eb7fSFabio Estevam if (err) 1887a0ad3087SMichael Trimarchi goto disable_ahb_clk; 1888af5d2b7bSUlf Hansson 188917b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ipg); 189017b1eb7fSFabio Estevam if (err) 189117b1eb7fSFabio Estevam goto disable_per_clk; 1892af5d2b7bSUlf Hansson 18933602785bSMichael Trimarchi esdhc_pltfm_set_clock(host, imx_data->actual_clock); 1894a0ad3087SMichael Trimarchi 1895c6303c5dSBaolin Wang err = sdhci_runtime_resume_host(host, 0); 189617b1eb7fSFabio Estevam if (err) 1897a0ad3087SMichael Trimarchi goto disable_ipg_clk; 189889d7e5c1SDong Aisheng 1899bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) 1900bb6e3581SBOUGH CHEN err = cqhci_resume(host->mmc); 1901bb6e3581SBOUGH CHEN 1902bb6e3581SBOUGH CHEN return err; 190317b1eb7fSFabio Estevam 190417b1eb7fSFabio Estevam disable_ipg_clk: 190517b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_ipg); 190617b1eb7fSFabio Estevam disable_per_clk: 190717b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_per); 1908a0ad3087SMichael Trimarchi disable_ahb_clk: 1909a0ad3087SMichael Trimarchi clk_disable_unprepare(imx_data->clk_ahb); 19101c4989b0SBOUGH CHEN remove_pm_qos_request: 19111c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1912d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 191317b1eb7fSFabio Estevam return err; 191489d7e5c1SDong Aisheng } 191589d7e5c1SDong Aisheng #endif 191689d7e5c1SDong Aisheng 191789d7e5c1SDong Aisheng static const struct dev_pm_ops sdhci_esdhc_pmops = { 191804143fbaSDong Aisheng SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume) 191989d7e5c1SDong Aisheng SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend, 192089d7e5c1SDong Aisheng sdhci_esdhc_runtime_resume, NULL) 192189d7e5c1SDong Aisheng }; 192289d7e5c1SDong Aisheng 192385d6509dSShawn Guo static struct platform_driver sdhci_esdhc_imx_driver = { 192485d6509dSShawn Guo .driver = { 192585d6509dSShawn Guo .name = "sdhci-esdhc-imx", 192621b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 1927abfafc2dSShawn Guo .of_match_table = imx_esdhc_dt_ids, 192889d7e5c1SDong Aisheng .pm = &sdhci_esdhc_pmops, 192985d6509dSShawn Guo }, 193085d6509dSShawn Guo .probe = sdhci_esdhc_imx_probe, 19310433c143SBill Pemberton .remove = sdhci_esdhc_imx_remove, 193295f25efeSWolfram Sang }; 193385d6509dSShawn Guo 1934d1f81a64SAxel Lin module_platform_driver(sdhci_esdhc_imx_driver); 193585d6509dSShawn Guo 193685d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); 1937035ff831SWolfram Sang MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>"); 193885d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 1939