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> 25c62da8a8SRob Herring #include <linux/platform_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) 1101e336aa0SHaibo Chen #define ESDHC_TUNING_STEP_DEFAULT 0x1 111260ecb3cSHaibo Chen #define ESDHC_TUNING_STEP_MASK 0x00070000 112d407e30bSHaibo Chen #define ESDHC_TUNING_STEP_SHIFT 16 1136e9fd28eSDong Aisheng 114ad93220dSDong Aisheng /* pinctrl state */ 115ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" 116ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz" 117ad93220dSDong Aisheng 11858ac8177SRichard Zhu /* 119af51079eSSascha Hauer * Our interpretation of the SDHCI_HOST_CONTROL register 120af51079eSSascha Hauer */ 121af51079eSSascha Hauer #define ESDHC_CTRL_4BITBUS (0x1 << 1) 122af51079eSSascha Hauer #define ESDHC_CTRL_8BITBUS (0x2 << 1) 123af51079eSSascha Hauer #define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) 12445334ee1SHaibo Chen #define USDHC_GET_BUSWIDTH(c) (c & ESDHC_CTRL_BUSWIDTH_MASK) 125af51079eSSascha Hauer 126af51079eSSascha Hauer /* 127d04f8d5bSBenoît Thébaudeau * There is an INT DMA ERR mismatch between eSDHC and STD SDHC SPEC: 12897e4ba6aSRichard Zhu * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, 12997e4ba6aSRichard Zhu * but bit28 is used as the INT DMA ERR in fsl eSDHC design. 13097e4ba6aSRichard Zhu * Define this macro DMA error INT for fsl eSDHC 13197e4ba6aSRichard Zhu */ 13260bf6396SShawn Guo #define ESDHC_INT_VENDOR_SPEC_DMA_ERR (1 << 28) 13397e4ba6aSRichard Zhu 134bb6e3581SBOUGH CHEN /* the address offset of CQHCI */ 135bb6e3581SBOUGH CHEN #define ESDHC_CQHCI_ADDR_OFFSET 0x100 136bb6e3581SBOUGH CHEN 13797e4ba6aSRichard Zhu /* 13858ac8177SRichard Zhu * The CMDTYPE of the CMD register (offset 0xE) should be set to 13958ac8177SRichard Zhu * "11" when the STOP CMD12 is issued on imx53 to abort one 14058ac8177SRichard Zhu * open ended multi-blk IO. Otherwise the TC INT wouldn't 14158ac8177SRichard Zhu * be generated. 14258ac8177SRichard Zhu * In exact block transfer, the controller doesn't complete the 14358ac8177SRichard Zhu * operations automatically as required at the end of the 14458ac8177SRichard Zhu * transfer and remains on hold if the abort command is not sent. 14558ac8177SRichard Zhu * As a result, the TC flag is not asserted and SW received timeout 146d04f8d5bSBenoît Thébaudeau * exception. Bit1 of Vendor Spec register is used to fix it. 14758ac8177SRichard Zhu */ 14831fbb301SShawn Guo #define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1) 14931fbb301SShawn Guo /* 1509d61c009SShawn Guo * The flag tells that the ESDHC controller is an USDHC block that is 1519d61c009SShawn Guo * integrated on the i.MX6 series. 1529d61c009SShawn Guo */ 1539d61c009SShawn Guo #define ESDHC_FLAG_USDHC BIT(3) 1546e9fd28eSDong Aisheng /* The IP supports manual tuning process */ 1556e9fd28eSDong Aisheng #define ESDHC_FLAG_MAN_TUNING BIT(4) 1566e9fd28eSDong Aisheng /* The IP supports standard tuning process */ 1576e9fd28eSDong Aisheng #define ESDHC_FLAG_STD_TUNING BIT(5) 1586e9fd28eSDong Aisheng /* The IP has SDHCI_CAPABILITIES_1 register */ 1596e9fd28eSDong Aisheng #define ESDHC_FLAG_HAVE_CAP1 BIT(6) 16018094430SDong Aisheng /* 161d04f8d5bSBenoît Thébaudeau * The IP has erratum ERR004536 16218094430SDong Aisheng * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow, 16318094430SDong Aisheng * when reading data from the card 164667123f6SBenoît Thébaudeau * This flag is also set for i.MX25 and i.MX35 in order to get 165667123f6SBenoît Thébaudeau * SDHCI_QUIRK_BROKEN_ADMA, but for different reasons (ADMA capability bits). 16618094430SDong Aisheng */ 16718094430SDong Aisheng #define ESDHC_FLAG_ERR004536 BIT(7) 1684245afffSDong Aisheng /* The IP supports HS200 mode */ 1694245afffSDong Aisheng #define ESDHC_FLAG_HS200 BIT(8) 17028b07674SHaibo Chen /* The IP supports HS400 mode */ 17128b07674SHaibo Chen #define ESDHC_FLAG_HS400 BIT(9) 172af6a50d4SBOUGH CHEN /* 173af6a50d4SBOUGH CHEN * The IP has errata ERR010450 174af6a50d4SBOUGH CHEN * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't 175af6a50d4SBOUGH CHEN * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz. 176af6a50d4SBOUGH CHEN */ 177af6a50d4SBOUGH CHEN #define ESDHC_FLAG_ERR010450 BIT(10) 178029e2476SBOUGH CHEN /* The IP supports HS400ES mode */ 179029e2476SBOUGH CHEN #define ESDHC_FLAG_HS400_ES BIT(11) 180bb6e3581SBOUGH CHEN /* The IP has Host Controller Interface for Command Queuing */ 181bb6e3581SBOUGH CHEN #define ESDHC_FLAG_CQHCI BIT(12) 1821c4989b0SBOUGH CHEN /* need request pmqos during low power */ 1831c4989b0SBOUGH CHEN #define ESDHC_FLAG_PMQOS BIT(13) 184a26a4f1bSHaibo Chen /* The IP state got lost in low power mode */ 185a26a4f1bSHaibo Chen #define ESDHC_FLAG_STATE_LOST_IN_LPMODE BIT(14) 1865c11f1ffSHaibo Chen /* The IP lost clock rate in PM_RUNTIME */ 1875c11f1ffSHaibo Chen #define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME BIT(15) 18874898cbcSHaibo Chen /* 18974898cbcSHaibo Chen * The IP do not support the ACMD23 feature completely when use ADMA mode. 19074898cbcSHaibo Chen * In ADMA mode, it only use the 16 bit block count of the register 0x4 19174898cbcSHaibo Chen * (BLOCK_ATT) as the CMD23's argument for ACMD23 mode, which means it will 19274898cbcSHaibo Chen * ignore the upper 16 bit of the CMD23's argument. This will block the reliable 19374898cbcSHaibo Chen * write operation in RPMB, because RPMB reliable write need to set the bit31 19474898cbcSHaibo Chen * of the CMD23's argument. 19574898cbcSHaibo Chen * imx6qpdl/imx6sx/imx6sl/imx7d has this limitation only for ADMA mode, SDMA 19674898cbcSHaibo Chen * do not has this limitation. so when these SoC use ADMA mode, it need to 19774898cbcSHaibo Chen * disable the ACMD23 feature. 19874898cbcSHaibo Chen */ 19974898cbcSHaibo Chen #define ESDHC_FLAG_BROKEN_AUTO_CMD23 BIT(16) 200e149860dSRichard Zhu 2015c4f0062SChester Lin /* ERR004536 is not applicable for the IP */ 2025c4f0062SChester Lin #define ESDHC_FLAG_SKIP_ERR004536 BIT(17) 2035c4f0062SChester Lin 2044a11cc64SFabio Estevam enum wp_types { 2054a11cc64SFabio Estevam ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ 2064a11cc64SFabio Estevam ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ 2074a11cc64SFabio Estevam ESDHC_WP_GPIO, /* external gpio pin for WP */ 2084a11cc64SFabio Estevam }; 2094a11cc64SFabio Estevam 2104a11cc64SFabio Estevam enum cd_types { 2114a11cc64SFabio Estevam ESDHC_CD_NONE, /* no CD, neither controller nor gpio */ 2124a11cc64SFabio Estevam ESDHC_CD_CONTROLLER, /* mmc controller internal CD */ 2134a11cc64SFabio Estevam ESDHC_CD_GPIO, /* external gpio pin for CD */ 2144a11cc64SFabio Estevam ESDHC_CD_PERMANENT, /* no CD, card permanently wired to host */ 2154a11cc64SFabio Estevam }; 2164a11cc64SFabio Estevam 2174a11cc64SFabio Estevam /* 2184a11cc64SFabio Estevam * struct esdhc_platform_data - platform data for esdhc on i.MX 2194a11cc64SFabio Estevam * 2204a11cc64SFabio Estevam * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35. 2214a11cc64SFabio Estevam * 2224a11cc64SFabio Estevam * @wp_type: type of write_protect method (see wp_types enum above) 2234a11cc64SFabio Estevam * @cd_type: type of card_detect method (see cd_types enum above) 2244a11cc64SFabio Estevam */ 2254a11cc64SFabio Estevam 2264a11cc64SFabio Estevam struct esdhc_platform_data { 2274a11cc64SFabio Estevam enum wp_types wp_type; 2284a11cc64SFabio Estevam enum cd_types cd_type; 2294a11cc64SFabio Estevam int max_bus_width; 2304a11cc64SFabio Estevam unsigned int delay_line; 2314a11cc64SFabio Estevam unsigned int tuning_step; /* The delay cell steps in tuning procedure */ 2324a11cc64SFabio Estevam unsigned int tuning_start_tap; /* The start delay cell point in tuning procedure */ 2334a11cc64SFabio Estevam unsigned int strobe_dll_delay_target; /* The delay cell for strobe pad (read clock) */ 2344a11cc64SFabio Estevam }; 2354a11cc64SFabio Estevam 236f47c4bbfSShawn Guo struct esdhc_soc_data { 237f47c4bbfSShawn Guo u32 flags; 238f47c4bbfSShawn Guo }; 239f47c4bbfSShawn Guo 2404f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx25_data = { 241667123f6SBenoît Thébaudeau .flags = ESDHC_FLAG_ERR004536, 242f47c4bbfSShawn Guo }; 243f47c4bbfSShawn Guo 2444f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx35_data = { 245667123f6SBenoît Thébaudeau .flags = ESDHC_FLAG_ERR004536, 246f47c4bbfSShawn Guo }; 247f47c4bbfSShawn Guo 2484f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx51_data = { 249f47c4bbfSShawn Guo .flags = 0, 250f47c4bbfSShawn Guo }; 251f47c4bbfSShawn Guo 2524f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx53_data = { 253f47c4bbfSShawn Guo .flags = ESDHC_FLAG_MULTIBLK_NO_INT, 254f47c4bbfSShawn Guo }; 255f47c4bbfSShawn Guo 2564f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6q_data = { 25774898cbcSHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING 25874898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 2596e9fd28eSDong Aisheng }; 2606e9fd28eSDong Aisheng 2614f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sl_data = { 2626e9fd28eSDong Aisheng .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 2634245afffSDong Aisheng | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 26474898cbcSHaibo Chen | ESDHC_FLAG_HS200 26574898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 26674898cbcSHaibo Chen }; 26774898cbcSHaibo Chen 26874898cbcSHaibo Chen static const struct esdhc_soc_data usdhc_imx6sll_data = { 26974898cbcSHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 27074898cbcSHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 27186b59671SHaibo Chen | ESDHC_FLAG_HS400 27274898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 27357ed3314SShawn Guo }; 27457ed3314SShawn Guo 2754f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sx_data = { 276913d4951SDong Aisheng .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 277a26a4f1bSHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 27874898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 27974898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 280913d4951SDong Aisheng }; 281913d4951SDong Aisheng 282af6a50d4SBOUGH CHEN static const struct esdhc_soc_data usdhc_imx6ull_data = { 283af6a50d4SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 284af6a50d4SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 285a26a4f1bSHaibo Chen | ESDHC_FLAG_ERR010450 286a26a4f1bSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 287af6a50d4SBOUGH CHEN }; 288af6a50d4SBOUGH CHEN 2894f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx7d_data = { 29028b07674SHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 29128b07674SHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 292a26a4f1bSHaibo Chen | ESDHC_FLAG_HS400 29374898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 29474898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 29528b07674SHaibo Chen }; 29628b07674SHaibo Chen 2975c4f0062SChester Lin static struct esdhc_soc_data usdhc_s32g2_data = { 2985c4f0062SChester Lin .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING 2995c4f0062SChester Lin | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 3005c4f0062SChester Lin | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 3015c4f0062SChester Lin | ESDHC_FLAG_SKIP_ERR004536, 3025c4f0062SChester Lin }; 3035c4f0062SChester Lin 3041c4989b0SBOUGH CHEN static struct esdhc_soc_data usdhc_imx7ulp_data = { 3051c4989b0SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 3061c4989b0SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 307a26a4f1bSHaibo Chen | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 308a26a4f1bSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 3091c4989b0SBOUGH CHEN }; 3102f4788f3SJesse Taube static struct esdhc_soc_data usdhc_imxrt1050_data = { 311d7a1830eSGiulio Benetti .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 312d7a1830eSGiulio Benetti | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, 3132f4788f3SJesse Taube }; 3141c4989b0SBOUGH CHEN 315029e2476SBOUGH CHEN static struct esdhc_soc_data usdhc_imx8qxp_data = { 316029e2476SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 317029e2476SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 318bb6e3581SBOUGH CHEN | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 3195c11f1ffSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 3205c11f1ffSHaibo Chen | ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME, 321029e2476SBOUGH CHEN }; 322029e2476SBOUGH CHEN 323cde5e8e9SHaibo Chen static struct esdhc_soc_data usdhc_imx8mm_data = { 324cde5e8e9SHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 325cde5e8e9SHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 326cde5e8e9SHaibo Chen | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 327cde5e8e9SHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 328e149860dSRichard Zhu }; 329e149860dSRichard Zhu 330e149860dSRichard Zhu struct pltfm_imx_data { 331e149860dSRichard Zhu u32 scratchpad; 332e62d8b8fSDong Aisheng struct pinctrl *pinctrl; 333ad93220dSDong Aisheng struct pinctrl_state *pins_100mhz; 334ad93220dSDong Aisheng struct pinctrl_state *pins_200mhz; 335f47c4bbfSShawn Guo const struct esdhc_soc_data *socdata; 336842afc02SShawn Guo struct esdhc_platform_data boarddata; 33752dac615SSascha Hauer struct clk *clk_ipg; 33852dac615SSascha Hauer struct clk *clk_ahb; 33952dac615SSascha Hauer struct clk *clk_per; 3403602785bSMichael Trimarchi unsigned int actual_clock; 34152e4c32bSHaibo Chen 34252e4c32bSHaibo Chen /* 34352e4c32bSHaibo Chen * USDHC has one limition, require the SDIO device a different 34452e4c32bSHaibo Chen * register setting. Driver has to recognize card type during 34552e4c32bSHaibo Chen * the card init, but at this stage, mmc_host->card is not 34652e4c32bSHaibo Chen * available. So involve this field to save the card type 34752e4c32bSHaibo Chen * during card init through usdhc_init_card(). 34852e4c32bSHaibo Chen */ 34952e4c32bSHaibo Chen unsigned int init_card_type; 35052e4c32bSHaibo Chen 351361b8482SLucas Stach enum { 352361b8482SLucas Stach NO_CMD_PENDING, /* no multiblock command pending */ 353361b8482SLucas Stach MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ 354361b8482SLucas Stach WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ 355361b8482SLucas Stach } multiblock_status; 356de5bdbffSDong Aisheng u32 is_ddr; 3571c4989b0SBOUGH CHEN struct pm_qos_request pm_qos_req; 358e149860dSRichard Zhu }; 359e149860dSRichard Zhu 360abfafc2dSShawn Guo static const struct of_device_id imx_esdhc_dt_ids[] = { 361f47c4bbfSShawn Guo { .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, }, 362f47c4bbfSShawn Guo { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, 363f47c4bbfSShawn Guo { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, 364f47c4bbfSShawn Guo { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, 365913d4951SDong Aisheng { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, }, 3666e9fd28eSDong Aisheng { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, 36774898cbcSHaibo Chen { .compatible = "fsl,imx6sll-usdhc", .data = &usdhc_imx6sll_data, }, 368f47c4bbfSShawn Guo { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, 369af6a50d4SBOUGH CHEN { .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, }, 37028b07674SHaibo Chen { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, 3711c4989b0SBOUGH CHEN { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, 372029e2476SBOUGH CHEN { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, 373cde5e8e9SHaibo Chen { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, 3742f4788f3SJesse Taube { .compatible = "fsl,imxrt1050-usdhc", .data = &usdhc_imxrt1050_data, }, 3755c4f0062SChester Lin { .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, }, 376abfafc2dSShawn Guo { /* sentinel */ } 377abfafc2dSShawn Guo }; 378abfafc2dSShawn Guo MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); 379abfafc2dSShawn Guo 38057ed3314SShawn Guo static inline int is_imx25_esdhc(struct pltfm_imx_data *data) 38157ed3314SShawn Guo { 382f47c4bbfSShawn Guo return data->socdata == &esdhc_imx25_data; 38357ed3314SShawn Guo } 38457ed3314SShawn Guo 38557ed3314SShawn Guo static inline int is_imx53_esdhc(struct pltfm_imx_data *data) 38657ed3314SShawn Guo { 387f47c4bbfSShawn Guo return data->socdata == &esdhc_imx53_data; 38857ed3314SShawn Guo } 38957ed3314SShawn Guo 3909d61c009SShawn Guo static inline int esdhc_is_usdhc(struct pltfm_imx_data *data) 3919d61c009SShawn Guo { 392f47c4bbfSShawn Guo return !!(data->socdata->flags & ESDHC_FLAG_USDHC); 3939d61c009SShawn Guo } 3949d61c009SShawn Guo 39595f25efeSWolfram Sang static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) 39695f25efeSWolfram Sang { 39795f25efeSWolfram Sang void __iomem *base = host->ioaddr + (reg & ~0x3); 39895f25efeSWolfram Sang u32 shift = (reg & 0x3) * 8; 39995f25efeSWolfram Sang 40095f25efeSWolfram Sang writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); 40195f25efeSWolfram Sang } 40295f25efeSWolfram Sang 4033722c74cSHaibo Chen #define DRIVER_NAME "sdhci-esdhc-imx" 4043722c74cSHaibo Chen #define ESDHC_IMX_DUMP(f, x...) \ 4053722c74cSHaibo Chen pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) 4063722c74cSHaibo Chen static void esdhc_dump_debug_regs(struct sdhci_host *host) 4073722c74cSHaibo Chen { 4083722c74cSHaibo Chen int i; 4093722c74cSHaibo Chen char *debug_status[7] = { 4103722c74cSHaibo Chen "cmd debug status", 4113722c74cSHaibo Chen "data debug status", 4123722c74cSHaibo Chen "trans debug status", 4133722c74cSHaibo Chen "dma debug status", 4143722c74cSHaibo Chen "adma debug status", 4153722c74cSHaibo Chen "fifo debug status", 4163722c74cSHaibo Chen "async fifo debug status" 4173722c74cSHaibo Chen }; 4183722c74cSHaibo Chen 4193722c74cSHaibo Chen ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n"); 4203722c74cSHaibo Chen for (i = 0; i < 7; i++) { 4213722c74cSHaibo Chen esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 4223722c74cSHaibo Chen ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG); 4233722c74cSHaibo Chen ESDHC_IMX_DUMP("%s: 0x%04x\n", debug_status[i], 4243722c74cSHaibo Chen readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG)); 4253722c74cSHaibo Chen } 4263722c74cSHaibo Chen 4273722c74cSHaibo Chen esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG); 4283722c74cSHaibo Chen 4293722c74cSHaibo Chen } 4303722c74cSHaibo Chen 431f581e909SHaibo Chen static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host) 432f581e909SHaibo Chen { 433f581e909SHaibo Chen u32 present_state; 434f581e909SHaibo Chen int ret; 435f581e909SHaibo Chen 436f581e909SHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state, 437f581e909SHaibo Chen (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100); 438f581e909SHaibo Chen if (ret == -ETIMEDOUT) 439f581e909SHaibo Chen dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__); 440f581e909SHaibo Chen } 441f581e909SHaibo Chen 44245334ee1SHaibo Chen /* Enable the auto tuning circuit to check the CMD line and BUS line */ 443c8c49a5aSHaibo Chen static inline void usdhc_auto_tuning_mode_sel_and_en(struct sdhci_host *host) 44445334ee1SHaibo Chen { 44552e4c32bSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 44652e4c32bSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 44745334ee1SHaibo Chen u32 buswidth, auto_tune_buswidth; 448c8c49a5aSHaibo Chen u32 reg; 44945334ee1SHaibo Chen 45045334ee1SHaibo Chen buswidth = USDHC_GET_BUSWIDTH(readl(host->ioaddr + SDHCI_HOST_CONTROL)); 45145334ee1SHaibo Chen 45245334ee1SHaibo Chen switch (buswidth) { 45345334ee1SHaibo Chen case ESDHC_CTRL_8BITBUS: 45445334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN; 45545334ee1SHaibo Chen break; 45645334ee1SHaibo Chen case ESDHC_CTRL_4BITBUS: 45745334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN; 45845334ee1SHaibo Chen break; 45945334ee1SHaibo Chen default: /* 1BITBUS */ 46045334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN; 46145334ee1SHaibo Chen break; 46245334ee1SHaibo Chen } 46345334ee1SHaibo Chen 46452e4c32bSHaibo Chen /* 46552e4c32bSHaibo Chen * For USDHC, auto tuning circuit can not handle the async sdio 46652e4c32bSHaibo Chen * device interrupt correctly. When sdio device use 4 data lines, 46752e4c32bSHaibo Chen * async sdio interrupt will use the shared DAT[1], if enable auto 46852e4c32bSHaibo Chen * tuning circuit check these 4 data lines, include the DAT[1], 46952e4c32bSHaibo Chen * this circuit will detect this interrupt, take this as a data on 47052e4c32bSHaibo Chen * DAT[1], and adjust the delay cell wrongly. 47152e4c32bSHaibo Chen * This is the hardware design limitation, to avoid this, for sdio 47252e4c32bSHaibo Chen * device, config the auto tuning circuit only check DAT[0] and CMD 47352e4c32bSHaibo Chen * line. 47452e4c32bSHaibo Chen */ 47552e4c32bSHaibo Chen if (imx_data->init_card_type == MMC_TYPE_SDIO) 47652e4c32bSHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN; 47752e4c32bSHaibo Chen 47845334ee1SHaibo Chen esdhc_clrset_le(host, ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK, 47945334ee1SHaibo Chen auto_tune_buswidth | ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN, 48045334ee1SHaibo Chen ESDHC_VEND_SPEC2); 481c8c49a5aSHaibo Chen 482c8c49a5aSHaibo Chen reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 483c8c49a5aSHaibo Chen reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; 484c8c49a5aSHaibo Chen writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 48545334ee1SHaibo Chen } 48645334ee1SHaibo Chen 4877e29c306SWolfram Sang static u32 esdhc_readl_le(struct sdhci_host *host, int reg) 4887e29c306SWolfram Sang { 489361b8482SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 490070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 491913413c3SShawn Guo u32 val = readl(host->ioaddr + reg); 492913413c3SShawn Guo 4930322191eSDong Aisheng if (unlikely(reg == SDHCI_PRESENT_STATE)) { 4940322191eSDong Aisheng u32 fsl_prss = val; 4950322191eSDong Aisheng /* save the least 20 bits */ 4960322191eSDong Aisheng val = fsl_prss & 0x000FFFFF; 4970322191eSDong Aisheng /* move dat[0-3] bits */ 4980322191eSDong Aisheng val |= (fsl_prss & 0x0F000000) >> 4; 4990322191eSDong Aisheng /* move cmd line bit */ 5000322191eSDong Aisheng val |= (fsl_prss & 0x00800000) << 1; 5010322191eSDong Aisheng } 5020322191eSDong Aisheng 50397e4ba6aSRichard Zhu if (unlikely(reg == SDHCI_CAPABILITIES)) { 5046b4fb671SDong Aisheng /* ignore bit[0-15] as it stores cap_1 register val for mx6sl */ 5056b4fb671SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) 5066b4fb671SDong Aisheng val &= 0xffff0000; 5076b4fb671SDong Aisheng 50897e4ba6aSRichard Zhu /* In FSL esdhc IC module, only bit20 is used to indicate the 50997e4ba6aSRichard Zhu * ADMA2 capability of esdhc, but this bit is messed up on 51097e4ba6aSRichard Zhu * some SOCs (e.g. on MX25, MX35 this bit is set, but they 51197e4ba6aSRichard Zhu * don't actually support ADMA2). So set the BROKEN_ADMA 512d04f8d5bSBenoît Thébaudeau * quirk on MX25/35 platforms. 51397e4ba6aSRichard Zhu */ 51497e4ba6aSRichard Zhu 51597e4ba6aSRichard Zhu if (val & SDHCI_CAN_DO_ADMA1) { 51697e4ba6aSRichard Zhu val &= ~SDHCI_CAN_DO_ADMA1; 51797e4ba6aSRichard Zhu val |= SDHCI_CAN_DO_ADMA2; 51897e4ba6aSRichard Zhu } 51997e4ba6aSRichard Zhu } 52097e4ba6aSRichard Zhu 5216e9fd28eSDong Aisheng if (unlikely(reg == SDHCI_CAPABILITIES_1)) { 5226e9fd28eSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 5236e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) 5246e9fd28eSDong Aisheng val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF; 5256e9fd28eSDong Aisheng else 5266e9fd28eSDong Aisheng /* imx6q/dl does not have cap_1 register, fake one */ 5270322191eSDong Aisheng val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 528888824bbSDong Aisheng | SDHCI_SUPPORT_SDR50 529da0295ffSDong Aisheng | SDHCI_USE_SDR50_TUNING 530a8e809ecSMasahiro Yamada | FIELD_PREP(SDHCI_RETUNING_MODE_MASK, 531a8e809ecSMasahiro Yamada SDHCI_TUNING_MODE_3); 53228b07674SHaibo Chen 53392748beaSStefan Agner /* 53492748beaSStefan Agner * Do not advertise faster UHS modes if there are no 53592748beaSStefan Agner * pinctrl states for 100MHz/200MHz. 53692748beaSStefan Agner */ 53725e8b9ebSShawn Guo if (IS_ERR_OR_NULL(imx_data->pins_100mhz)) 53825e8b9ebSShawn Guo val &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); 53925e8b9ebSShawn Guo if (IS_ERR_OR_NULL(imx_data->pins_200mhz)) 54025e8b9ebSShawn Guo val &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_HS400); 5416e9fd28eSDong Aisheng } 5426e9fd28eSDong Aisheng } 5430322191eSDong Aisheng 5449d61c009SShawn Guo if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { 5450322191eSDong Aisheng val = 0; 546804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF); 547804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF); 548804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF); 5490322191eSDong Aisheng } 5500322191eSDong Aisheng 55197e4ba6aSRichard Zhu if (unlikely(reg == SDHCI_INT_STATUS)) { 55260bf6396SShawn Guo if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) { 55360bf6396SShawn Guo val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; 55497e4ba6aSRichard Zhu val |= SDHCI_INT_ADMA_ERROR; 55597e4ba6aSRichard Zhu } 556361b8482SLucas Stach 557361b8482SLucas Stach /* 558361b8482SLucas Stach * mask off the interrupt we get in response to the manually 559361b8482SLucas Stach * sent CMD12 560361b8482SLucas Stach */ 561361b8482SLucas Stach if ((imx_data->multiblock_status == WAIT_FOR_INT) && 562361b8482SLucas Stach ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) { 563361b8482SLucas Stach val &= ~SDHCI_INT_RESPONSE; 564361b8482SLucas Stach writel(SDHCI_INT_RESPONSE, host->ioaddr + 565361b8482SLucas Stach SDHCI_INT_STATUS); 566361b8482SLucas Stach imx_data->multiblock_status = NO_CMD_PENDING; 567361b8482SLucas Stach } 56897e4ba6aSRichard Zhu } 56997e4ba6aSRichard Zhu 5707e29c306SWolfram Sang return val; 5717e29c306SWolfram Sang } 5727e29c306SWolfram Sang 5737e29c306SWolfram Sang static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) 5747e29c306SWolfram Sang { 575e149860dSRichard Zhu struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 576070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 5770d58864bSTony Lin u32 data; 578e149860dSRichard Zhu 57977da3da0SAaron Brice if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE || 58077da3da0SAaron Brice reg == SDHCI_INT_STATUS)) { 581b7321042SDong Aisheng if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) { 5820d58864bSTony Lin /* 5830d58864bSTony Lin * Clear and then set D3CD bit to avoid missing the 584d04f8d5bSBenoît Thébaudeau * card interrupt. This is an eSDHC controller problem 5850d58864bSTony Lin * so we need to apply the following workaround: clear 5860d58864bSTony Lin * and set D3CD bit will make eSDHC re-sample the card 5870d58864bSTony Lin * interrupt. In case a card interrupt was lost, 5880d58864bSTony Lin * re-sample it by the following steps. 5890d58864bSTony Lin */ 5900d58864bSTony Lin data = readl(host->ioaddr + SDHCI_HOST_CONTROL); 59160bf6396SShawn Guo data &= ~ESDHC_CTRL_D3CD; 5920d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 59360bf6396SShawn Guo data |= ESDHC_CTRL_D3CD; 5940d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 5950d58864bSTony Lin } 596915be485SDong Aisheng 597915be485SDong Aisheng if (val & SDHCI_INT_ADMA_ERROR) { 598915be485SDong Aisheng val &= ~SDHCI_INT_ADMA_ERROR; 599915be485SDong Aisheng val |= ESDHC_INT_VENDOR_SPEC_DMA_ERR; 600915be485SDong Aisheng } 6010d58864bSTony Lin } 6020d58864bSTony Lin 603f47c4bbfSShawn Guo if (unlikely((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 60458ac8177SRichard Zhu && (reg == SDHCI_INT_STATUS) 60558ac8177SRichard Zhu && (val & SDHCI_INT_DATA_END))) { 60658ac8177SRichard Zhu u32 v; 60760bf6396SShawn Guo v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 60860bf6396SShawn Guo v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK; 60960bf6396SShawn Guo writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); 610361b8482SLucas Stach 611361b8482SLucas Stach if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS) 612361b8482SLucas Stach { 613361b8482SLucas Stach /* send a manual CMD12 with RESPTYP=none */ 614361b8482SLucas Stach data = MMC_STOP_TRANSMISSION << 24 | 615361b8482SLucas Stach SDHCI_CMD_ABORTCMD << 16; 616361b8482SLucas Stach writel(data, host->ioaddr + SDHCI_TRANSFER_MODE); 617361b8482SLucas Stach imx_data->multiblock_status = WAIT_FOR_INT; 618361b8482SLucas Stach } 61958ac8177SRichard Zhu } 62058ac8177SRichard Zhu 6217e29c306SWolfram Sang writel(val, host->ioaddr + reg); 6227e29c306SWolfram Sang } 6237e29c306SWolfram Sang 62495f25efeSWolfram Sang static u16 esdhc_readw_le(struct sdhci_host *host, int reg) 62595f25efeSWolfram Sang { 626ef4d0888SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 627070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 6280322191eSDong Aisheng u16 ret = 0; 6290322191eSDong Aisheng u32 val; 630ef4d0888SShawn Guo 63195a2482aSShawn Guo if (unlikely(reg == SDHCI_HOST_VERSION)) { 632ef4d0888SShawn Guo reg ^= 2; 6339d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 63495a2482aSShawn Guo /* 635ef4d0888SShawn Guo * The usdhc register returns a wrong host version. 636ef4d0888SShawn Guo * Correct it here. 63795a2482aSShawn Guo */ 638ef4d0888SShawn Guo return SDHCI_SPEC_300; 639ef4d0888SShawn Guo } 64095a2482aSShawn Guo } 64195f25efeSWolfram Sang 6420322191eSDong Aisheng if (unlikely(reg == SDHCI_HOST_CONTROL2)) { 6430322191eSDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6440322191eSDong Aisheng if (val & ESDHC_VENDOR_SPEC_VSELECT) 6450322191eSDong Aisheng ret |= SDHCI_CTRL_VDD_180; 6460322191eSDong Aisheng 6479d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 6486e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) 6490322191eSDong Aisheng val = readl(host->ioaddr + ESDHC_MIX_CTRL); 6506e9fd28eSDong Aisheng else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) 6516e9fd28eSDong Aisheng /* the std tuning bits is in ACMD12_ERR for imx6sl */ 652869f8a69SAdrian Hunter val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6536e9fd28eSDong Aisheng } 6546e9fd28eSDong Aisheng 6550322191eSDong Aisheng if (val & ESDHC_MIX_CTRL_EXE_TUNE) 6560322191eSDong Aisheng ret |= SDHCI_CTRL_EXEC_TUNING; 6570322191eSDong Aisheng if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) 6580322191eSDong Aisheng ret |= SDHCI_CTRL_TUNED_CLK; 6590322191eSDong Aisheng 6600322191eSDong Aisheng ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; 6610322191eSDong Aisheng 6620322191eSDong Aisheng return ret; 6630322191eSDong Aisheng } 6640322191eSDong Aisheng 6657dd109efSDong Aisheng if (unlikely(reg == SDHCI_TRANSFER_MODE)) { 6667dd109efSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 6677dd109efSDong Aisheng u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 6687dd109efSDong Aisheng ret = m & ESDHC_MIX_CTRL_SDHCI_MASK; 6697dd109efSDong Aisheng /* Swap AC23 bit */ 6707dd109efSDong Aisheng if (m & ESDHC_MIX_CTRL_AC23EN) { 6717dd109efSDong Aisheng ret &= ~ESDHC_MIX_CTRL_AC23EN; 6727dd109efSDong Aisheng ret |= SDHCI_TRNS_AUTO_CMD23; 6737dd109efSDong Aisheng } 6747dd109efSDong Aisheng } else { 6757dd109efSDong Aisheng ret = readw(host->ioaddr + SDHCI_TRANSFER_MODE); 6767dd109efSDong Aisheng } 6777dd109efSDong Aisheng 6787dd109efSDong Aisheng return ret; 6797dd109efSDong Aisheng } 6807dd109efSDong Aisheng 68195f25efeSWolfram Sang return readw(host->ioaddr + reg); 68295f25efeSWolfram Sang } 68395f25efeSWolfram Sang 68495f25efeSWolfram Sang static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) 68595f25efeSWolfram Sang { 68695f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 687070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 6880322191eSDong Aisheng u32 new_val = 0; 68995f25efeSWolfram Sang 69095f25efeSWolfram Sang switch (reg) { 6910322191eSDong Aisheng case SDHCI_CLOCK_CONTROL: 6920322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6930322191eSDong Aisheng if (val & SDHCI_CLOCK_CARD_EN) 6940322191eSDong Aisheng new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 6950322191eSDong Aisheng else 6960322191eSDong Aisheng new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 6970322191eSDong Aisheng writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); 698f581e909SHaibo Chen if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON)) 699f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 7000322191eSDong Aisheng return; 7010322191eSDong Aisheng case SDHCI_HOST_CONTROL2: 7020322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 7030322191eSDong Aisheng if (val & SDHCI_CTRL_VDD_180) 7040322191eSDong Aisheng new_val |= ESDHC_VENDOR_SPEC_VSELECT; 7050322191eSDong Aisheng else 7060322191eSDong Aisheng new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; 7070322191eSDong Aisheng writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); 708a0dbbdc2SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 709869f8a69SAdrian Hunter u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 7106e9fd28eSDong Aisheng u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 7118b2bb0adSDong Aisheng if (val & SDHCI_CTRL_TUNED_CLK) { 7128b2bb0adSDong Aisheng v |= ESDHC_MIX_CTRL_SMPCLK_SEL; 7136e9fd28eSDong Aisheng } else { 7148b2bb0adSDong Aisheng v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 7156e9fd28eSDong Aisheng m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; 7166e9fd28eSDong Aisheng } 7176e9fd28eSDong Aisheng 7188b2bb0adSDong Aisheng if (val & SDHCI_CTRL_EXEC_TUNING) { 7198b2bb0adSDong Aisheng v |= ESDHC_MIX_CTRL_EXE_TUNE; 7208b2bb0adSDong Aisheng m |= ESDHC_MIX_CTRL_FBCLK_SEL; 7218b2bb0adSDong Aisheng } else { 7228b2bb0adSDong Aisheng v &= ~ESDHC_MIX_CTRL_EXE_TUNE; 7238b2bb0adSDong Aisheng } 7246e9fd28eSDong Aisheng 725869f8a69SAdrian Hunter writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 7266e9fd28eSDong Aisheng writel(m, host->ioaddr + ESDHC_MIX_CTRL); 7276e9fd28eSDong Aisheng } 7280322191eSDong Aisheng return; 72995f25efeSWolfram Sang case SDHCI_TRANSFER_MODE: 730f47c4bbfSShawn Guo if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 73158ac8177SRichard Zhu && (host->cmd->opcode == SD_IO_RW_EXTENDED) 73258ac8177SRichard Zhu && (host->cmd->data->blocks > 1) 73358ac8177SRichard Zhu && (host->cmd->data->flags & MMC_DATA_READ)) { 73458ac8177SRichard Zhu u32 v; 73560bf6396SShawn Guo v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 73660bf6396SShawn Guo v |= ESDHC_VENDOR_SPEC_SDIO_QUIRK; 73760bf6396SShawn Guo writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); 73858ac8177SRichard Zhu } 73969f54698SShawn Guo 7409d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 7413fbd4322SAndrew Gabbasov u32 wml; 74269f54698SShawn Guo u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 7432a15f981SShawn Guo /* Swap AC23 bit */ 7442a15f981SShawn Guo if (val & SDHCI_TRNS_AUTO_CMD23) { 7452a15f981SShawn Guo val &= ~SDHCI_TRNS_AUTO_CMD23; 7462a15f981SShawn Guo val |= ESDHC_MIX_CTRL_AC23EN; 7472a15f981SShawn Guo } 7482a15f981SShawn Guo m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK); 74969f54698SShawn Guo writel(m, host->ioaddr + ESDHC_MIX_CTRL); 7503fbd4322SAndrew Gabbasov 7513fbd4322SAndrew Gabbasov /* Set watermark levels for PIO access to maximum value 7523fbd4322SAndrew Gabbasov * (128 words) to accommodate full 512 bytes buffer. 7533fbd4322SAndrew Gabbasov * For DMA access restore the levels to default value. 7543fbd4322SAndrew Gabbasov */ 7553fbd4322SAndrew Gabbasov m = readl(host->ioaddr + ESDHC_WTMK_LVL); 756e534b82fSHaibo Chen if (val & SDHCI_TRNS_DMA) { 7573fbd4322SAndrew Gabbasov wml = ESDHC_WTMK_LVL_WML_VAL_DEF; 758e534b82fSHaibo Chen } else { 759e534b82fSHaibo Chen u8 ctrl; 7603fbd4322SAndrew Gabbasov wml = ESDHC_WTMK_LVL_WML_VAL_MAX; 761e534b82fSHaibo Chen 762e534b82fSHaibo Chen /* 763e534b82fSHaibo Chen * Since already disable DMA mode, so also need 764e534b82fSHaibo Chen * to clear the DMASEL. Otherwise, for standard 765e534b82fSHaibo Chen * tuning, when send tuning command, usdhc will 766e534b82fSHaibo Chen * still prefetch the ADMA script from wrong 767e534b82fSHaibo Chen * DMA address, then we will see IOMMU report 768e534b82fSHaibo Chen * some error which show lack of TLB mapping. 769e534b82fSHaibo Chen */ 770e534b82fSHaibo Chen ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 771e534b82fSHaibo Chen ctrl &= ~SDHCI_CTRL_DMA_MASK; 772e534b82fSHaibo Chen sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 773e534b82fSHaibo Chen } 7743fbd4322SAndrew Gabbasov m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK | 7753fbd4322SAndrew Gabbasov ESDHC_WTMK_LVL_WR_WML_MASK); 7763fbd4322SAndrew Gabbasov m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) | 7773fbd4322SAndrew Gabbasov (wml << ESDHC_WTMK_LVL_WR_WML_SHIFT); 7783fbd4322SAndrew Gabbasov writel(m, host->ioaddr + ESDHC_WTMK_LVL); 77969f54698SShawn Guo } else { 78069f54698SShawn Guo /* 78169f54698SShawn Guo * Postpone this write, we must do it together with a 78269f54698SShawn Guo * command write that is down below. 78369f54698SShawn Guo */ 784e149860dSRichard Zhu imx_data->scratchpad = val; 78569f54698SShawn Guo } 78695f25efeSWolfram Sang return; 78795f25efeSWolfram Sang case SDHCI_COMMAND: 788361b8482SLucas Stach if (host->cmd->opcode == MMC_STOP_TRANSMISSION) 78958ac8177SRichard Zhu val |= SDHCI_CMD_ABORTCMD; 79095a2482aSShawn Guo 791361b8482SLucas Stach if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) && 792f47c4bbfSShawn Guo (imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) 793361b8482SLucas Stach imx_data->multiblock_status = MULTIBLK_IN_PROCESS; 794361b8482SLucas Stach 7959d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) 79695a2482aSShawn Guo writel(val << 16, 79795a2482aSShawn Guo host->ioaddr + SDHCI_TRANSFER_MODE); 79869f54698SShawn Guo else 799e149860dSRichard Zhu writel(val << 16 | imx_data->scratchpad, 80095f25efeSWolfram Sang host->ioaddr + SDHCI_TRANSFER_MODE); 80195f25efeSWolfram Sang return; 80295f25efeSWolfram Sang case SDHCI_BLOCK_SIZE: 80395f25efeSWolfram Sang val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 80495f25efeSWolfram Sang break; 80595f25efeSWolfram Sang } 80695f25efeSWolfram Sang esdhc_clrset_le(host, 0xffff, val, reg); 80795f25efeSWolfram Sang } 80895f25efeSWolfram Sang 80977da3da0SAaron Brice static u8 esdhc_readb_le(struct sdhci_host *host, int reg) 81077da3da0SAaron Brice { 81177da3da0SAaron Brice u8 ret; 81277da3da0SAaron Brice u32 val; 81377da3da0SAaron Brice 81477da3da0SAaron Brice switch (reg) { 81577da3da0SAaron Brice case SDHCI_HOST_CONTROL: 81677da3da0SAaron Brice val = readl(host->ioaddr + reg); 81777da3da0SAaron Brice 81877da3da0SAaron Brice ret = val & SDHCI_CTRL_LED; 81977da3da0SAaron Brice ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK; 82077da3da0SAaron Brice ret |= (val & ESDHC_CTRL_4BITBUS); 82177da3da0SAaron Brice ret |= (val & ESDHC_CTRL_8BITBUS) << 3; 82277da3da0SAaron Brice return ret; 82377da3da0SAaron Brice } 82477da3da0SAaron Brice 82577da3da0SAaron Brice return readb(host->ioaddr + reg); 82677da3da0SAaron Brice } 82777da3da0SAaron Brice 82895f25efeSWolfram Sang static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) 82995f25efeSWolfram Sang { 8309a0985b7SWilson Callan struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 831070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 83281a0a8bcSBenoît Thébaudeau u32 new_val = 0; 833af51079eSSascha Hauer u32 mask; 83495f25efeSWolfram Sang 83595f25efeSWolfram Sang switch (reg) { 83695f25efeSWolfram Sang case SDHCI_POWER_CONTROL: 83795f25efeSWolfram Sang /* 83895f25efeSWolfram Sang * FSL put some DMA bits here 83995f25efeSWolfram Sang * If your board has a regulator, code should be here 84095f25efeSWolfram Sang */ 84195f25efeSWolfram Sang return; 84295f25efeSWolfram Sang case SDHCI_HOST_CONTROL: 8436b40d182SShawn Guo /* FSL messed up here, so we need to manually compose it. */ 844af51079eSSascha Hauer new_val = val & SDHCI_CTRL_LED; 8457122bbb0SMasanari Iida /* ensure the endianness */ 84695f25efeSWolfram Sang new_val |= ESDHC_HOST_CONTROL_LE; 8479a0985b7SWilson Callan /* bits 8&9 are reserved on mx25 */ 8489a0985b7SWilson Callan if (!is_imx25_esdhc(imx_data)) { 84995f25efeSWolfram Sang /* DMA mode bits are shifted */ 85095f25efeSWolfram Sang new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 8519a0985b7SWilson Callan } 85295f25efeSWolfram Sang 853af51079eSSascha Hauer /* 854af51079eSSascha Hauer * Do not touch buswidth bits here. This is done in 855af51079eSSascha Hauer * esdhc_pltfm_bus_width. 856f6825748SMartin Fuzzey * Do not touch the D3CD bit either which is used for the 857d04f8d5bSBenoît Thébaudeau * SDIO interrupt erratum workaround. 858af51079eSSascha Hauer */ 859f6825748SMartin Fuzzey mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD); 860af51079eSSascha Hauer 861af51079eSSascha Hauer esdhc_clrset_le(host, mask, new_val, reg); 86295f25efeSWolfram Sang return; 86381a0a8bcSBenoît Thébaudeau case SDHCI_SOFTWARE_RESET: 86481a0a8bcSBenoît Thébaudeau if (val & SDHCI_RESET_DATA) 86581a0a8bcSBenoît Thébaudeau new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL); 86681a0a8bcSBenoît Thébaudeau break; 86795f25efeSWolfram Sang } 86895f25efeSWolfram Sang esdhc_clrset_le(host, 0xff, val, reg); 869913413c3SShawn Guo 87081a0a8bcSBenoît Thébaudeau if (reg == SDHCI_SOFTWARE_RESET) { 87181a0a8bcSBenoît Thébaudeau if (val & SDHCI_RESET_ALL) { 872913413c3SShawn Guo /* 87381a0a8bcSBenoît Thébaudeau * The esdhc has a design violation to SDHC spec which 87481a0a8bcSBenoît Thébaudeau * tells that software reset should not affect card 87581a0a8bcSBenoît Thébaudeau * detection circuit. But esdhc clears its SYSCTL 87681a0a8bcSBenoît Thébaudeau * register bits [0..2] during the software reset. This 87781a0a8bcSBenoît Thébaudeau * will stop those clocks that card detection circuit 87881a0a8bcSBenoît Thébaudeau * relies on. To work around it, we turn the clocks on 87981a0a8bcSBenoît Thébaudeau * back to keep card detection circuit functional. 880913413c3SShawn Guo */ 881913413c3SShawn Guo esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); 88258c8c4fbSShawn Guo /* 88358c8c4fbSShawn Guo * The reset on usdhc fails to clear MIX_CTRL register. 88458c8c4fbSShawn Guo * Do it manually here. 88558c8c4fbSShawn Guo */ 886de5bdbffSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 88781a0a8bcSBenoît Thébaudeau /* 88881a0a8bcSBenoît Thébaudeau * the tuning bits should be kept during reset 88981a0a8bcSBenoît Thébaudeau */ 890d131a71cSDong Aisheng new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); 891d131a71cSDong Aisheng writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK, 892d131a71cSDong Aisheng host->ioaddr + ESDHC_MIX_CTRL); 893de5bdbffSDong Aisheng imx_data->is_ddr = 0; 894de5bdbffSDong Aisheng } 89581a0a8bcSBenoît Thébaudeau } else if (val & SDHCI_RESET_DATA) { 89681a0a8bcSBenoît Thébaudeau /* 89781a0a8bcSBenoît Thébaudeau * The eSDHC DAT line software reset clears at least the 89881a0a8bcSBenoît Thébaudeau * data transfer width on i.MX25, so make sure that the 89981a0a8bcSBenoît Thébaudeau * Host Control register is unaffected. 90081a0a8bcSBenoît Thébaudeau */ 90181a0a8bcSBenoît Thébaudeau esdhc_clrset_le(host, 0xff, new_val, 90281a0a8bcSBenoît Thébaudeau SDHCI_HOST_CONTROL); 90381a0a8bcSBenoît Thébaudeau } 90458c8c4fbSShawn Guo } 90595f25efeSWolfram Sang } 90695f25efeSWolfram Sang 9070ddf03c9SLucas Stach static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) 9080ddf03c9SLucas Stach { 9090ddf03c9SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 9100ddf03c9SLucas Stach 911a974862fSDong Aisheng return pltfm_host->clock; 9120ddf03c9SLucas Stach } 9130ddf03c9SLucas Stach 91495f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) 91595f25efeSWolfram Sang { 91695f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 91795f25efeSWolfram Sang 918a974862fSDong Aisheng return pltfm_host->clock / 256 / 16; 91995f25efeSWolfram Sang } 92095f25efeSWolfram Sang 9218ba9580aSLucas Stach static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, 9228ba9580aSLucas Stach unsigned int clock) 9238ba9580aSLucas Stach { 9248ba9580aSLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 925070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 926a974862fSDong Aisheng unsigned int host_clock = pltfm_host->clock; 9275143c953SBenoît Thébaudeau int ddr_pre_div = imx_data->is_ddr ? 2 : 1; 9285143c953SBenoît Thébaudeau int pre_div = 1; 929d31fc00aSDong Aisheng int div = 1; 930f581e909SHaibo Chen int ret; 931fed2f6e2SDong Aisheng u32 temp, val; 9328ba9580aSLucas Stach 9339d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 934fed2f6e2SDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 935fed2f6e2SDong Aisheng writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 936fed2f6e2SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 937f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 938fed2f6e2SDong Aisheng } 93973e736f8SStefan Agner 94073e736f8SStefan Agner if (clock == 0) { 94173e736f8SStefan Agner host->mmc->actual_clock = 0; 942373073efSRussell King return; 943fed2f6e2SDong Aisheng } 944d31fc00aSDong Aisheng 945499ed50fSBenoît Thébaudeau /* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */ 946499ed50fSBenoît Thébaudeau if (is_imx53_esdhc(imx_data)) { 947499ed50fSBenoît Thébaudeau /* 948499ed50fSBenoît Thébaudeau * According to the i.MX53 reference manual, if DLLCTRL[10] can 949499ed50fSBenoît Thébaudeau * be set, then the controller is eSDHCv3, else it is eSDHCv2. 950499ed50fSBenoît Thébaudeau */ 951499ed50fSBenoît Thébaudeau val = readl(host->ioaddr + ESDHC_DLL_CTRL); 952499ed50fSBenoît Thébaudeau writel(val | BIT(10), host->ioaddr + ESDHC_DLL_CTRL); 953499ed50fSBenoît Thébaudeau temp = readl(host->ioaddr + ESDHC_DLL_CTRL); 954499ed50fSBenoît Thébaudeau writel(val, host->ioaddr + ESDHC_DLL_CTRL); 955499ed50fSBenoît Thébaudeau if (temp & BIT(10)) 956499ed50fSBenoît Thébaudeau pre_div = 2; 957499ed50fSBenoît Thébaudeau } 958499ed50fSBenoît Thébaudeau 959d31fc00aSDong Aisheng temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 960d31fc00aSDong Aisheng temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 961d31fc00aSDong Aisheng | ESDHC_CLOCK_MASK); 962d31fc00aSDong Aisheng sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 963d31fc00aSDong Aisheng 964af6a50d4SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) { 965af6a50d4SBOUGH CHEN unsigned int max_clock; 966af6a50d4SBOUGH CHEN 967af6a50d4SBOUGH CHEN max_clock = imx_data->is_ddr ? 45000000 : 150000000; 968af6a50d4SBOUGH CHEN 969af6a50d4SBOUGH CHEN clock = min(clock, max_clock); 970af6a50d4SBOUGH CHEN } 971af6a50d4SBOUGH CHEN 9725143c953SBenoît Thébaudeau while (host_clock / (16 * pre_div * ddr_pre_div) > clock && 9735143c953SBenoît Thébaudeau pre_div < 256) 974d31fc00aSDong Aisheng pre_div *= 2; 975d31fc00aSDong Aisheng 9765143c953SBenoît Thébaudeau while (host_clock / (div * pre_div * ddr_pre_div) > clock && div < 16) 977d31fc00aSDong Aisheng div++; 978d31fc00aSDong Aisheng 9795143c953SBenoît Thébaudeau host->mmc->actual_clock = host_clock / (div * pre_div * ddr_pre_div); 980d31fc00aSDong Aisheng dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", 981e76b8559SDong Aisheng clock, host->mmc->actual_clock); 982d31fc00aSDong Aisheng 983d31fc00aSDong Aisheng pre_div >>= 1; 984d31fc00aSDong Aisheng div--; 985d31fc00aSDong Aisheng 986d31fc00aSDong Aisheng temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 987d31fc00aSDong Aisheng temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 988d31fc00aSDong Aisheng | (div << ESDHC_DIVIDER_SHIFT) 989d31fc00aSDong Aisheng | (pre_div << ESDHC_PREDIV_SHIFT)); 990d31fc00aSDong Aisheng sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 991fed2f6e2SDong Aisheng 992f581e909SHaibo Chen /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */ 993f581e909SHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp, 994f581e909SHaibo Chen (temp & ESDHC_CLOCK_STABLE), 2, 100); 995f581e909SHaibo Chen if (ret == -ETIMEDOUT) 996f581e909SHaibo Chen dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n"); 997f581e909SHaibo Chen 9989d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 999fed2f6e2SDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 1000fed2f6e2SDong Aisheng writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 1001fed2f6e2SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 1002fed2f6e2SDong Aisheng } 1003fed2f6e2SDong Aisheng 10048ba9580aSLucas Stach } 10058ba9580aSLucas Stach 1006913413c3SShawn Guo static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) 1007913413c3SShawn Guo { 1008842afc02SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1009070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1010842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1011913413c3SShawn Guo 1012913413c3SShawn Guo switch (boarddata->wp_type) { 1013913413c3SShawn Guo case ESDHC_WP_GPIO: 1014fbe5fdd1SShawn Guo return mmc_gpio_get_ro(host->mmc); 1015913413c3SShawn Guo case ESDHC_WP_CONTROLLER: 1016913413c3SShawn Guo return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 1017913413c3SShawn Guo SDHCI_WRITE_PROTECT); 1018913413c3SShawn Guo case ESDHC_WP_NONE: 1019913413c3SShawn Guo break; 1020913413c3SShawn Guo } 1021913413c3SShawn Guo 1022913413c3SShawn Guo return -ENOSYS; 1023913413c3SShawn Guo } 1024913413c3SShawn Guo 10252317f56cSRussell King static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) 1026af51079eSSascha Hauer { 1027af51079eSSascha Hauer u32 ctrl; 1028af51079eSSascha Hauer 1029af51079eSSascha Hauer switch (width) { 1030af51079eSSascha Hauer case MMC_BUS_WIDTH_8: 1031af51079eSSascha Hauer ctrl = ESDHC_CTRL_8BITBUS; 1032af51079eSSascha Hauer break; 1033af51079eSSascha Hauer case MMC_BUS_WIDTH_4: 1034af51079eSSascha Hauer ctrl = ESDHC_CTRL_4BITBUS; 1035af51079eSSascha Hauer break; 1036af51079eSSascha Hauer default: 1037af51079eSSascha Hauer ctrl = 0; 1038af51079eSSascha Hauer break; 1039af51079eSSascha Hauer } 1040af51079eSSascha Hauer 1041af51079eSSascha Hauer esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl, 1042af51079eSSascha Hauer SDHCI_HOST_CONTROL); 1043af51079eSSascha Hauer } 1044af51079eSSascha Hauer 10454fb27869SHaibo Chen static void esdhc_reset_tuning(struct sdhci_host *host) 10464fb27869SHaibo Chen { 10474fb27869SHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 10484fb27869SHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 10494fb27869SHaibo Chen u32 ctrl; 10504fb27869SHaibo Chen int ret; 10514fb27869SHaibo Chen 10524fb27869SHaibo Chen /* Reset the tuning circuit */ 10534fb27869SHaibo Chen if (esdhc_is_usdhc(imx_data)) { 10544fb27869SHaibo Chen ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL); 1055c8c49a5aSHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN; 1056c8c49a5aSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 10574fb27869SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 10584fb27869SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL; 10594fb27869SHaibo Chen writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); 10604fb27869SHaibo Chen writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 10614fb27869SHaibo Chen } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 1062c8c49a5aSHaibo Chen writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); 10634fb27869SHaibo Chen ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 10644fb27869SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 10654fb27869SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; 10664fb27869SHaibo Chen writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 10674fb27869SHaibo Chen /* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */ 10684fb27869SHaibo Chen ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS, 10694fb27869SHaibo Chen ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50); 10704fb27869SHaibo Chen if (ret == -ETIMEDOUT) 10714fb27869SHaibo Chen dev_warn(mmc_dev(host->mmc), 10724fb27869SHaibo Chen "Warning! clear execute tuning bit failed\n"); 10734fb27869SHaibo Chen /* 10744fb27869SHaibo Chen * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the 10754fb27869SHaibo Chen * usdhc IP internal logic flag execute_tuning_with_clr_buf, which 10764fb27869SHaibo Chen * will finally make sure the normal data transfer logic correct. 10774fb27869SHaibo Chen */ 10784fb27869SHaibo Chen ctrl = readl(host->ioaddr + SDHCI_INT_STATUS); 10794fb27869SHaibo Chen ctrl |= SDHCI_INT_DATA_AVAIL; 10804fb27869SHaibo Chen writel(ctrl, host->ioaddr + SDHCI_INT_STATUS); 10814fb27869SHaibo Chen } 10824fb27869SHaibo Chen } 10834fb27869SHaibo Chen } 10844fb27869SHaibo Chen 108552e4c32bSHaibo Chen static void usdhc_init_card(struct mmc_host *mmc, struct mmc_card *card) 108652e4c32bSHaibo Chen { 108752e4c32bSHaibo Chen struct sdhci_host *host = mmc_priv(mmc); 108852e4c32bSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 108952e4c32bSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 109052e4c32bSHaibo Chen 109152e4c32bSHaibo Chen imx_data->init_card_type = card->type; 109252e4c32bSHaibo Chen } 109352e4c32bSHaibo Chen 1094de3e1dd0SBOUGH CHEN static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) 1095de3e1dd0SBOUGH CHEN { 1096de3e1dd0SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 1097c8c49a5aSHaibo Chen int err; 1098de3e1dd0SBOUGH CHEN 1099de3e1dd0SBOUGH CHEN /* 1100de3e1dd0SBOUGH CHEN * i.MX uSDHC internally already uses a fixed optimized timing for 1101de3e1dd0SBOUGH CHEN * DDR50, normally does not require tuning for DDR50 mode. 1102de3e1dd0SBOUGH CHEN */ 1103de3e1dd0SBOUGH CHEN if (host->timing == MMC_TIMING_UHS_DDR50) 1104de3e1dd0SBOUGH CHEN return 0; 1105de3e1dd0SBOUGH CHEN 11064fb27869SHaibo Chen /* 11074fb27869SHaibo Chen * Reset tuning circuit logic. If not, the previous tuning result 11084fb27869SHaibo Chen * will impact current tuning, make current tuning can't set the 11094fb27869SHaibo Chen * correct delay cell. 11104fb27869SHaibo Chen */ 11114fb27869SHaibo Chen esdhc_reset_tuning(host); 1112c8c49a5aSHaibo Chen err = sdhci_execute_tuning(mmc, opcode); 1113c8c49a5aSHaibo Chen /* If tuning done, enable auto tuning */ 1114c8c49a5aSHaibo Chen if (!err && !host->tuning_err) 1115c8c49a5aSHaibo Chen usdhc_auto_tuning_mode_sel_and_en(host); 1116c8c49a5aSHaibo Chen 1117c8c49a5aSHaibo Chen return err; 1118de3e1dd0SBOUGH CHEN } 1119de3e1dd0SBOUGH CHEN 11200322191eSDong Aisheng static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) 11210322191eSDong Aisheng { 11220322191eSDong Aisheng u32 reg; 11230ac4f496SHaibo Chen u8 sw_rst; 11240ac4f496SHaibo Chen int ret; 11250322191eSDong Aisheng 11260322191eSDong Aisheng /* FIXME: delay a bit for card to be ready for next tuning due to errors */ 11270322191eSDong Aisheng mdelay(1); 11280322191eSDong Aisheng 11290ac4f496SHaibo Chen /* IC suggest to reset USDHC before every tuning command */ 11300ac4f496SHaibo Chen esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET); 11310ac4f496SHaibo Chen ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst, 11320ac4f496SHaibo Chen !(sw_rst & SDHCI_RESET_ALL), 10, 100); 11330ac4f496SHaibo Chen if (ret == -ETIMEDOUT) 11340ac4f496SHaibo Chen dev_warn(mmc_dev(host->mmc), 11350ac4f496SHaibo Chen "warning! RESET_ALL never complete before sending tuning command\n"); 11360ac4f496SHaibo Chen 11370322191eSDong Aisheng reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 11380322191eSDong Aisheng reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | 11390322191eSDong Aisheng ESDHC_MIX_CTRL_FBCLK_SEL; 11400322191eSDong Aisheng writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 11410322191eSDong Aisheng writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 11420322191eSDong Aisheng dev_dbg(mmc_dev(host->mmc), 1143d04f8d5bSBenoît Thébaudeau "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", 11440322191eSDong Aisheng val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); 11450322191eSDong Aisheng } 11460322191eSDong Aisheng 11470322191eSDong Aisheng static void esdhc_post_tuning(struct sdhci_host *host) 11480322191eSDong Aisheng { 11490322191eSDong Aisheng u32 reg; 11500322191eSDong Aisheng 11510322191eSDong Aisheng reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 11520322191eSDong Aisheng reg &= ~ESDHC_MIX_CTRL_EXE_TUNE; 11530322191eSDong Aisheng writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 11540322191eSDong Aisheng } 11550322191eSDong Aisheng 11560322191eSDong Aisheng static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) 11570322191eSDong Aisheng { 11580322191eSDong Aisheng int min, max, avg, ret; 11590322191eSDong Aisheng 11600322191eSDong Aisheng /* find the mininum delay first which can pass tuning */ 11610322191eSDong Aisheng min = ESDHC_TUNE_CTRL_MIN; 11620322191eSDong Aisheng while (min < ESDHC_TUNE_CTRL_MAX) { 11630322191eSDong Aisheng esdhc_prepare_tuning(host, min); 11649979dbe5SChaotian Jing if (!mmc_send_tuning(host->mmc, opcode, NULL)) 11650322191eSDong Aisheng break; 11660322191eSDong Aisheng min += ESDHC_TUNE_CTRL_STEP; 11670322191eSDong Aisheng } 11680322191eSDong Aisheng 11690322191eSDong Aisheng /* find the maxinum delay which can not pass tuning */ 11700322191eSDong Aisheng max = min + ESDHC_TUNE_CTRL_STEP; 11710322191eSDong Aisheng while (max < ESDHC_TUNE_CTRL_MAX) { 11720322191eSDong Aisheng esdhc_prepare_tuning(host, max); 11739979dbe5SChaotian Jing if (mmc_send_tuning(host->mmc, opcode, NULL)) { 11740322191eSDong Aisheng max -= ESDHC_TUNE_CTRL_STEP; 11750322191eSDong Aisheng break; 11760322191eSDong Aisheng } 11770322191eSDong Aisheng max += ESDHC_TUNE_CTRL_STEP; 11780322191eSDong Aisheng } 11790322191eSDong Aisheng 11800322191eSDong Aisheng /* use average delay to get the best timing */ 11810322191eSDong Aisheng avg = (min + max) / 2; 11820322191eSDong Aisheng esdhc_prepare_tuning(host, avg); 11839979dbe5SChaotian Jing ret = mmc_send_tuning(host->mmc, opcode, NULL); 11840322191eSDong Aisheng esdhc_post_tuning(host); 11850322191eSDong Aisheng 1186d04f8d5bSBenoît Thébaudeau dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n", 11870322191eSDong Aisheng ret ? "failed" : "passed", avg, ret); 11880322191eSDong Aisheng 11890322191eSDong Aisheng return ret; 11900322191eSDong Aisheng } 11910322191eSDong Aisheng 1192029e2476SBOUGH CHEN static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) 1193029e2476SBOUGH CHEN { 1194029e2476SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 1195029e2476SBOUGH CHEN u32 m; 1196029e2476SBOUGH CHEN 1197029e2476SBOUGH CHEN m = readl(host->ioaddr + ESDHC_MIX_CTRL); 1198029e2476SBOUGH CHEN if (ios->enhanced_strobe) 1199029e2476SBOUGH CHEN m |= ESDHC_MIX_CTRL_HS400_ES_EN; 1200029e2476SBOUGH CHEN else 1201029e2476SBOUGH CHEN m &= ~ESDHC_MIX_CTRL_HS400_ES_EN; 1202029e2476SBOUGH CHEN writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1203029e2476SBOUGH CHEN } 1204029e2476SBOUGH CHEN 1205ad93220dSDong Aisheng static int esdhc_change_pinstate(struct sdhci_host *host, 1206ad93220dSDong Aisheng unsigned int uhs) 1207ad93220dSDong Aisheng { 1208ad93220dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1209070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1210ad93220dSDong Aisheng struct pinctrl_state *pinctrl; 1211ad93220dSDong Aisheng 1212ad93220dSDong Aisheng dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs); 1213ad93220dSDong Aisheng 1214ad93220dSDong Aisheng if (IS_ERR(imx_data->pinctrl) || 1215ad93220dSDong Aisheng IS_ERR(imx_data->pins_100mhz) || 1216ad93220dSDong Aisheng IS_ERR(imx_data->pins_200mhz)) 1217ad93220dSDong Aisheng return -EINVAL; 1218ad93220dSDong Aisheng 1219ad93220dSDong Aisheng switch (uhs) { 1220ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR50: 12219f327845SHaibo Chen case MMC_TIMING_UHS_DDR50: 1222ad93220dSDong Aisheng pinctrl = imx_data->pins_100mhz; 1223ad93220dSDong Aisheng break; 1224ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR104: 1225429a5b45SDong Aisheng case MMC_TIMING_MMC_HS200: 122628b07674SHaibo Chen case MMC_TIMING_MMC_HS400: 1227ad93220dSDong Aisheng pinctrl = imx_data->pins_200mhz; 1228ad93220dSDong Aisheng break; 1229ad93220dSDong Aisheng default: 1230ad93220dSDong Aisheng /* back to default state for other legacy timing */ 12312480b720SUlf Hansson return pinctrl_select_default_state(mmc_dev(host->mmc)); 1232ad93220dSDong Aisheng } 1233ad93220dSDong Aisheng 1234ad93220dSDong Aisheng return pinctrl_select_state(imx_data->pinctrl, pinctrl); 1235ad93220dSDong Aisheng } 1236ad93220dSDong Aisheng 123728b07674SHaibo Chen /* 1238d04f8d5bSBenoît Thébaudeau * For HS400 eMMC, there is a data_strobe line. This signal is generated 123928b07674SHaibo Chen * by the device and used for data output and CRC status response output 124028b07674SHaibo Chen * in HS400 mode. The frequency of this signal follows the frequency of 1241d04f8d5bSBenoît Thébaudeau * CLK generated by host. The host receives the data which is aligned to the 124228b07674SHaibo Chen * edge of data_strobe line. Due to the time delay between CLK line and 124328b07674SHaibo Chen * data_strobe line, if the delay time is larger than one clock cycle, 1244d04f8d5bSBenoît Thébaudeau * then CLK and data_strobe line will be misaligned, read error shows up. 124528b07674SHaibo Chen */ 124628b07674SHaibo Chen static void esdhc_set_strobe_dll(struct sdhci_host *host) 124728b07674SHaibo Chen { 12485bd2acdcSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 12495bd2acdcSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 12505bd2acdcSHaibo Chen u32 strobe_delay; 125128b07674SHaibo Chen u32 v; 1252373e800bSHaibo Chen int ret; 125328b07674SHaibo Chen 12547ac6da26SDong Aisheng /* disable clock before enabling strobe dll */ 12557ac6da26SDong Aisheng writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & 12567ac6da26SDong Aisheng ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 12577ac6da26SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 1258f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 12597ac6da26SDong Aisheng 126028b07674SHaibo Chen /* force a reset on strobe dll */ 126128b07674SHaibo Chen writel(ESDHC_STROBE_DLL_CTRL_RESET, 126228b07674SHaibo Chen host->ioaddr + ESDHC_STROBE_DLL_CTRL); 12632eaf5a53SBOUGH CHEN /* clear the reset bit on strobe dll before any setting */ 12642eaf5a53SBOUGH CHEN writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL); 12652eaf5a53SBOUGH CHEN 126628b07674SHaibo Chen /* 126728b07674SHaibo Chen * enable strobe dll ctrl and adjust the delay target 126828b07674SHaibo Chen * for the uSDHC loopback read clock 126928b07674SHaibo Chen */ 12705bd2acdcSHaibo Chen if (imx_data->boarddata.strobe_dll_delay_target) 12715bd2acdcSHaibo Chen strobe_delay = imx_data->boarddata.strobe_dll_delay_target; 12725bd2acdcSHaibo Chen else 12735bd2acdcSHaibo Chen strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT; 127428b07674SHaibo Chen v = ESDHC_STROBE_DLL_CTRL_ENABLE | 12752eaf5a53SBOUGH CHEN ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT | 12765bd2acdcSHaibo Chen (strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); 127728b07674SHaibo Chen writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); 1278373e800bSHaibo Chen 1279373e800bSHaibo Chen /* wait max 50us to get the REF/SLV lock */ 1280373e800bSHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_STROBE_DLL_STATUS, v, 1281373e800bSHaibo Chen ((v & ESDHC_STROBE_DLL_STS_REF_LOCK) && (v & ESDHC_STROBE_DLL_STS_SLV_LOCK)), 1, 50); 1282373e800bSHaibo Chen if (ret == -ETIMEDOUT) 128328b07674SHaibo Chen dev_warn(mmc_dev(host->mmc), 1284373e800bSHaibo Chen "warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v); 128528b07674SHaibo Chen } 128628b07674SHaibo Chen 1287850a29b8SRussell King static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) 1288ad93220dSDong Aisheng { 128928b07674SHaibo Chen u32 m; 1290ad93220dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1291070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1292602519b2SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1293ad93220dSDong Aisheng 129428b07674SHaibo Chen /* disable ddr mode and disable HS400 mode */ 129528b07674SHaibo Chen m = readl(host->ioaddr + ESDHC_MIX_CTRL); 129628b07674SHaibo Chen m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN); 129728b07674SHaibo Chen imx_data->is_ddr = 0; 129828b07674SHaibo Chen 1299850a29b8SRussell King switch (timing) { 1300ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR12: 1301ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR25: 1302ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR50: 1303ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR104: 1304de0a0decSBOUGH CHEN case MMC_TIMING_MMC_HS: 1305429a5b45SDong Aisheng case MMC_TIMING_MMC_HS200: 130628b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1307ad93220dSDong Aisheng break; 1308ad93220dSDong Aisheng case MMC_TIMING_UHS_DDR50: 130969f5bf38SAisheng Dong case MMC_TIMING_MMC_DDR52: 131028b07674SHaibo Chen m |= ESDHC_MIX_CTRL_DDREN; 131128b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1312de5bdbffSDong Aisheng imx_data->is_ddr = 1; 1313602519b2SDong Aisheng if (boarddata->delay_line) { 1314602519b2SDong Aisheng u32 v; 1315602519b2SDong Aisheng v = boarddata->delay_line << 1316602519b2SDong Aisheng ESDHC_DLL_OVERRIDE_VAL_SHIFT | 1317602519b2SDong Aisheng (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT); 1318602519b2SDong Aisheng if (is_imx53_esdhc(imx_data)) 1319602519b2SDong Aisheng v <<= 1; 1320602519b2SDong Aisheng writel(v, host->ioaddr + ESDHC_DLL_CTRL); 1321602519b2SDong Aisheng } 1322ad93220dSDong Aisheng break; 132328b07674SHaibo Chen case MMC_TIMING_MMC_HS400: 132428b07674SHaibo Chen m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN; 132528b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 132628b07674SHaibo Chen imx_data->is_ddr = 1; 13277ac6da26SDong Aisheng /* update clock after enable DDR for strobe DLL lock */ 13287ac6da26SDong Aisheng host->ops->set_clock(host, host->clock); 132928b07674SHaibo Chen esdhc_set_strobe_dll(host); 133028b07674SHaibo Chen break; 1331d9370424SHaibo Chen case MMC_TIMING_LEGACY: 1332d9370424SHaibo Chen default: 1333d9370424SHaibo Chen esdhc_reset_tuning(host); 1334d9370424SHaibo Chen break; 1335ad93220dSDong Aisheng } 1336ad93220dSDong Aisheng 1337850a29b8SRussell King esdhc_change_pinstate(host, timing); 1338ad93220dSDong Aisheng } 1339ad93220dSDong Aisheng 13400718e59aSRussell King static void esdhc_reset(struct sdhci_host *host, u8 mask) 13410718e59aSRussell King { 1342fb1dec44SBrian Norris sdhci_and_cqhci_reset(host, mask); 13430718e59aSRussell King 13440718e59aSRussell King sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); 13450718e59aSRussell King sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); 13460718e59aSRussell King } 13470718e59aSRussell King 134810fd0ad9SAisheng Dong static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) 134910fd0ad9SAisheng Dong { 135010fd0ad9SAisheng Dong struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1351070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 135210fd0ad9SAisheng Dong 1353d04f8d5bSBenoît Thébaudeau /* Doc Erratum: the uSDHC actual maximum timeout count is 1 << 29 */ 13542fb0b02bSHaibo Chen return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27; 135510fd0ad9SAisheng Dong } 135610fd0ad9SAisheng Dong 1357e33eb8e2SAisheng Dong static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) 1358e33eb8e2SAisheng Dong { 1359e33eb8e2SAisheng Dong struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1360070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1361e33eb8e2SAisheng Dong 1362e33eb8e2SAisheng Dong /* use maximum timeout counter */ 1363a215186dSHaibo Chen esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK, 1364a215186dSHaibo Chen esdhc_is_usdhc(imx_data) ? 0xF : 0xE, 1365e33eb8e2SAisheng Dong SDHCI_TIMEOUT_CONTROL); 1366e33eb8e2SAisheng Dong } 1367e33eb8e2SAisheng Dong 1368bb6e3581SBOUGH CHEN static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) 1369bb6e3581SBOUGH CHEN { 1370bb6e3581SBOUGH CHEN int cmd_error = 0; 1371bb6e3581SBOUGH CHEN int data_error = 0; 1372bb6e3581SBOUGH CHEN 1373bb6e3581SBOUGH CHEN if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 1374bb6e3581SBOUGH CHEN return intmask; 1375bb6e3581SBOUGH CHEN 1376bb6e3581SBOUGH CHEN cqhci_irq(host->mmc, intmask, cmd_error, data_error); 1377bb6e3581SBOUGH CHEN 1378bb6e3581SBOUGH CHEN return 0; 1379bb6e3581SBOUGH CHEN } 1380bb6e3581SBOUGH CHEN 13816e9fd28eSDong Aisheng static struct sdhci_ops sdhci_esdhc_ops = { 1382e149860dSRichard Zhu .read_l = esdhc_readl_le, 13830c6d49ceSWolfram Sang .read_w = esdhc_readw_le, 138477da3da0SAaron Brice .read_b = esdhc_readb_le, 1385e149860dSRichard Zhu .write_l = esdhc_writel_le, 13860c6d49ceSWolfram Sang .write_w = esdhc_writew_le, 13870c6d49ceSWolfram Sang .write_b = esdhc_writeb_le, 13888ba9580aSLucas Stach .set_clock = esdhc_pltfm_set_clock, 13890ddf03c9SLucas Stach .get_max_clock = esdhc_pltfm_get_max_clock, 13900c6d49ceSWolfram Sang .get_min_clock = esdhc_pltfm_get_min_clock, 139110fd0ad9SAisheng Dong .get_max_timeout_count = esdhc_get_max_timeout_count, 1392913413c3SShawn Guo .get_ro = esdhc_pltfm_get_ro, 1393e33eb8e2SAisheng Dong .set_timeout = esdhc_set_timeout, 13942317f56cSRussell King .set_bus_width = esdhc_pltfm_set_bus_width, 1395ad93220dSDong Aisheng .set_uhs_signaling = esdhc_set_uhs_signaling, 13960718e59aSRussell King .reset = esdhc_reset, 1397bb6e3581SBOUGH CHEN .irq = esdhc_cqhci_irq, 13983722c74cSHaibo Chen .dump_vendor_regs = esdhc_dump_debug_regs, 13990c6d49ceSWolfram Sang }; 14000c6d49ceSWolfram Sang 14011db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 140297e4ba6aSRichard Zhu .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT 140397e4ba6aSRichard Zhu | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC 140497e4ba6aSRichard Zhu | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC 140585d6509dSShawn Guo | SDHCI_QUIRK_BROKEN_CARD_DETECTION, 140685d6509dSShawn Guo .ops = &sdhci_esdhc_ops, 140785d6509dSShawn Guo }; 140885d6509dSShawn Guo 1409f3f5cf3dSDong Aisheng static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) 1410f3f5cf3dSDong Aisheng { 1411f3f5cf3dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1412f3f5cf3dSDong Aisheng struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1413982cf37dSHaibo Chen struct cqhci_host *cq_host = host->mmc->cqe_private; 14141e336aa0SHaibo Chen u32 tmp; 1415f3f5cf3dSDong Aisheng 1416f3f5cf3dSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 1417f3f5cf3dSDong Aisheng /* 1418f3f5cf3dSDong Aisheng * The imx6q ROM code will change the default watermark 1419f3f5cf3dSDong Aisheng * level setting to something insane. Change it back here. 1420f3f5cf3dSDong Aisheng */ 1421f3f5cf3dSDong Aisheng writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL); 1422f3f5cf3dSDong Aisheng 1423f3f5cf3dSDong Aisheng /* 1424f3f5cf3dSDong Aisheng * ROM code will change the bit burst_length_enable setting 1425d04f8d5bSBenoît Thébaudeau * to zero if this usdhc is chosen to boot system. Change 1426f3f5cf3dSDong Aisheng * it back here, otherwise it will impact the performance a 1427f3f5cf3dSDong Aisheng * lot. This bit is used to enable/disable the burst length 1428d04f8d5bSBenoît Thébaudeau * for the external AHB2AXI bridge. It's useful especially 1429f3f5cf3dSDong Aisheng * for INCR transfer because without burst length indicator, 1430f3f5cf3dSDong Aisheng * the AHB2AXI bridge does not know the burst length in 1431f3f5cf3dSDong Aisheng * advance. And without burst length indicator, AHB INCR 1432f3f5cf3dSDong Aisheng * transfer can only be converted to singles on the AXI side. 1433f3f5cf3dSDong Aisheng */ 1434f3f5cf3dSDong Aisheng writel(readl(host->ioaddr + SDHCI_HOST_CONTROL) 1435f3f5cf3dSDong Aisheng | ESDHC_BURST_LEN_EN_INCR, 1436f3f5cf3dSDong Aisheng host->ioaddr + SDHCI_HOST_CONTROL); 1437e30be063SBOUGH CHEN 1438f3f5cf3dSDong Aisheng /* 1439d04f8d5bSBenoît Thébaudeau * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL 1440f3f5cf3dSDong Aisheng * TO1.1, it's harmless for MX6SL 1441f3f5cf3dSDong Aisheng */ 14425c4f0062SChester Lin if (!(imx_data->socdata->flags & ESDHC_FLAG_SKIP_ERR004536)) { 1443e30be063SBOUGH CHEN writel(readl(host->ioaddr + 0x6c) & ~BIT(7), 1444f3f5cf3dSDong Aisheng host->ioaddr + 0x6c); 14455c4f0062SChester Lin } 1446f3f5cf3dSDong Aisheng 1447f3f5cf3dSDong Aisheng /* disable DLL_CTRL delay line settings */ 1448f3f5cf3dSDong Aisheng writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); 14492b16cf32SDong Aisheng 1450bcdb5301SBOUGH CHEN /* 1451bcdb5301SBOUGH CHEN * For the case of command with busy, if set the bit 1452bcdb5301SBOUGH CHEN * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a 1453bcdb5301SBOUGH CHEN * transfer complete interrupt when busy is deasserted. 1454bcdb5301SBOUGH CHEN * When CQHCI use DCMD to send a CMD need R1b respons, 1455bcdb5301SBOUGH CHEN * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ, 1456bcdb5301SBOUGH CHEN * otherwise DCMD will always meet timeout waiting for 1457bcdb5301SBOUGH CHEN * hardware interrupt issue. 1458bcdb5301SBOUGH CHEN */ 1459bcdb5301SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { 1460bcdb5301SBOUGH CHEN tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2); 1461bcdb5301SBOUGH CHEN tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ; 1462bcdb5301SBOUGH CHEN writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2); 1463bcdb5301SBOUGH CHEN 1464bcdb5301SBOUGH CHEN host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; 1465bcdb5301SBOUGH CHEN } 1466bcdb5301SBOUGH CHEN 14672b16cf32SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 14682b16cf32SDong Aisheng tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); 14691e336aa0SHaibo Chen tmp |= ESDHC_STD_TUNING_EN; 14701e336aa0SHaibo Chen 14711e336aa0SHaibo Chen /* 14721e336aa0SHaibo Chen * ROM code or bootloader may config the start tap 14731e336aa0SHaibo Chen * and step, unmask them first. 14741e336aa0SHaibo Chen */ 14751e336aa0SHaibo Chen tmp &= ~(ESDHC_TUNING_START_TAP_MASK | ESDHC_TUNING_STEP_MASK); 14761e336aa0SHaibo Chen if (imx_data->boarddata.tuning_start_tap) 14772b16cf32SDong Aisheng tmp |= imx_data->boarddata.tuning_start_tap; 14781e336aa0SHaibo Chen else 14791e336aa0SHaibo Chen tmp |= ESDHC_TUNING_START_TAP_DEFAULT; 14802b16cf32SDong Aisheng 14812b16cf32SDong Aisheng if (imx_data->boarddata.tuning_step) { 14822b16cf32SDong Aisheng tmp |= imx_data->boarddata.tuning_step 14832b16cf32SDong Aisheng << ESDHC_TUNING_STEP_SHIFT; 14841e336aa0SHaibo Chen } else { 14851e336aa0SHaibo Chen tmp |= ESDHC_TUNING_STEP_DEFAULT 14861e336aa0SHaibo Chen << ESDHC_TUNING_STEP_SHIFT; 14872b16cf32SDong Aisheng } 148816e40e5bSHaibo Chen 148916e40e5bSHaibo Chen /* Disable the CMD CRC check for tuning, if not, need to 149016e40e5bSHaibo Chen * add some delay after every tuning command, because 149116e40e5bSHaibo Chen * hardware standard tuning logic will directly go to next 149216e40e5bSHaibo Chen * step once it detect the CMD CRC error, will not wait for 149316e40e5bSHaibo Chen * the card side to finally send out the tuning data, trigger 149416e40e5bSHaibo Chen * the buffer read ready interrupt immediately. If usdhc send 149516e40e5bSHaibo Chen * the next tuning command some eMMC card will stuck, can't 149616e40e5bSHaibo Chen * response, block the tuning procedure or the first command 149716e40e5bSHaibo Chen * after the whole tuning procedure always can't get any response. 149816e40e5bSHaibo Chen */ 149916e40e5bSHaibo Chen tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; 15002b16cf32SDong Aisheng writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); 1501a98c557eSBOUGH CHEN } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 1502a98c557eSBOUGH CHEN /* 1503a98c557eSBOUGH CHEN * ESDHC_STD_TUNING_EN may be configed in bootloader 1504a98c557eSBOUGH CHEN * or ROM code, so clear this bit here to make sure 1505a98c557eSBOUGH CHEN * the manual tuning can work. 1506a98c557eSBOUGH CHEN */ 1507a98c557eSBOUGH CHEN tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); 1508a98c557eSBOUGH CHEN tmp &= ~ESDHC_STD_TUNING_EN; 1509a98c557eSBOUGH CHEN writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); 15102b16cf32SDong Aisheng } 1511982cf37dSHaibo Chen 1512982cf37dSHaibo Chen /* 1513982cf37dSHaibo Chen * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card 15141ad0dcb9Swangjianli * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let 1515982cf37dSHaibo Chen * the 1st linux configure power/clock for the 2nd Linux. 1516982cf37dSHaibo Chen * 1517982cf37dSHaibo Chen * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux 1518982cf37dSHaibo Chen * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump. 1519982cf37dSHaibo Chen * After we clear the pending interrupt and halt CQCTL, issue gone. 1520982cf37dSHaibo Chen */ 1521982cf37dSHaibo Chen if (cq_host) { 1522982cf37dSHaibo Chen tmp = cqhci_readl(cq_host, CQHCI_IS); 1523982cf37dSHaibo Chen cqhci_writel(cq_host, tmp, CQHCI_IS); 1524982cf37dSHaibo Chen cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL); 1525982cf37dSHaibo Chen } 1526f3f5cf3dSDong Aisheng } 1527f3f5cf3dSDong Aisheng } 1528f3f5cf3dSDong Aisheng 1529bb6e3581SBOUGH CHEN static void esdhc_cqe_enable(struct mmc_host *mmc) 1530bb6e3581SBOUGH CHEN { 1531bb6e3581SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 153285236d2bSBOUGH CHEN struct cqhci_host *cq_host = mmc->cqe_private; 1533bb6e3581SBOUGH CHEN u32 reg; 1534bb6e3581SBOUGH CHEN u16 mode; 1535bb6e3581SBOUGH CHEN int count = 10; 1536bb6e3581SBOUGH CHEN 1537bb6e3581SBOUGH CHEN /* 1538bb6e3581SBOUGH CHEN * CQE gets stuck if it sees Buffer Read Enable bit set, which can be 1539bb6e3581SBOUGH CHEN * the case after tuning, so ensure the buffer is drained. 1540bb6e3581SBOUGH CHEN */ 1541bb6e3581SBOUGH CHEN reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 1542bb6e3581SBOUGH CHEN while (reg & SDHCI_DATA_AVAILABLE) { 1543bb6e3581SBOUGH CHEN sdhci_readl(host, SDHCI_BUFFER); 1544bb6e3581SBOUGH CHEN reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 1545bb6e3581SBOUGH CHEN if (count-- == 0) { 1546bb6e3581SBOUGH CHEN dev_warn(mmc_dev(host->mmc), 1547bb6e3581SBOUGH CHEN "CQE may get stuck because the Buffer Read Enable bit is set\n"); 1548bb6e3581SBOUGH CHEN break; 1549bb6e3581SBOUGH CHEN } 1550bb6e3581SBOUGH CHEN mdelay(1); 1551bb6e3581SBOUGH CHEN } 1552bb6e3581SBOUGH CHEN 1553bb6e3581SBOUGH CHEN /* 1554bb6e3581SBOUGH CHEN * Runtime resume will reset the entire host controller, which 1555bb6e3581SBOUGH CHEN * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL. 1556bb6e3581SBOUGH CHEN * Here set DMAEN and BCEN when enable CMDQ. 1557bb6e3581SBOUGH CHEN */ 1558bb6e3581SBOUGH CHEN mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); 1559bb6e3581SBOUGH CHEN if (host->flags & SDHCI_REQ_USE_DMA) 1560bb6e3581SBOUGH CHEN mode |= SDHCI_TRNS_DMA; 1561bb6e3581SBOUGH CHEN if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) 1562bb6e3581SBOUGH CHEN mode |= SDHCI_TRNS_BLK_CNT_EN; 1563bb6e3581SBOUGH CHEN sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); 1564bb6e3581SBOUGH CHEN 156585236d2bSBOUGH CHEN /* 156685236d2bSBOUGH CHEN * Though Runtime resume reset the entire host controller, 156785236d2bSBOUGH CHEN * but do not impact the CQHCI side, need to clear the 156885236d2bSBOUGH CHEN * HALT bit, avoid CQHCI stuck in the first request when 156985236d2bSBOUGH CHEN * system resume back. 157085236d2bSBOUGH CHEN */ 157185236d2bSBOUGH CHEN cqhci_writel(cq_host, 0, CQHCI_CTL); 1572a3cab1d2SSebastian Falbesoner if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) 157385236d2bSBOUGH CHEN dev_err(mmc_dev(host->mmc), 157485236d2bSBOUGH CHEN "failed to exit halt state when enable CQE\n"); 157585236d2bSBOUGH CHEN 157685236d2bSBOUGH CHEN 1577bb6e3581SBOUGH CHEN sdhci_cqe_enable(mmc); 1578bb6e3581SBOUGH CHEN } 1579bb6e3581SBOUGH CHEN 1580bb6e3581SBOUGH CHEN static void esdhc_sdhci_dumpregs(struct mmc_host *mmc) 1581bb6e3581SBOUGH CHEN { 1582bb6e3581SBOUGH CHEN sdhci_dumpregs(mmc_priv(mmc)); 1583bb6e3581SBOUGH CHEN } 1584bb6e3581SBOUGH CHEN 1585bb6e3581SBOUGH CHEN static const struct cqhci_host_ops esdhc_cqhci_ops = { 1586bb6e3581SBOUGH CHEN .enable = esdhc_cqe_enable, 1587bb6e3581SBOUGH CHEN .disable = sdhci_cqe_disable, 1588bb6e3581SBOUGH CHEN .dumpregs = esdhc_sdhci_dumpregs, 1589bb6e3581SBOUGH CHEN }; 1590bb6e3581SBOUGH CHEN 1591c3be1efdSBill Pemberton static int 1592abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 159307bf2b54SSascha Hauer struct sdhci_host *host, 159491fa4252SDong Aisheng struct pltfm_imx_data *imx_data) 1595abfafc2dSShawn Guo { 1596abfafc2dSShawn Guo struct device_node *np = pdev->dev.of_node; 159791fa4252SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 15984800e87aSDong Aisheng int ret; 1599abfafc2dSShawn Guo 1600ca6b5fe2SRob Herring if (of_property_read_bool(np, "fsl,wp-controller")) 1601abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_CONTROLLER; 1602abfafc2dSShawn Guo 160374ff81e1SLinus Walleij /* 160474ff81e1SLinus Walleij * If we have this property, then activate WP check. 160574ff81e1SLinus Walleij * Retrieveing and requesting the actual WP GPIO will happen 160674ff81e1SLinus Walleij * in the call to mmc_of_parse(). 160774ff81e1SLinus Walleij */ 160874ff81e1SLinus Walleij if (of_property_read_bool(np, "wp-gpios")) 1609abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_GPIO; 1610abfafc2dSShawn Guo 1611d407e30bSHaibo Chen of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step); 1612d87fc966SDong Aisheng of_property_read_u32(np, "fsl,tuning-start-tap", 1613d87fc966SDong Aisheng &boarddata->tuning_start_tap); 1614d407e30bSHaibo Chen 16155bd2acdcSHaibo Chen of_property_read_u32(np, "fsl,strobe-dll-delay-target", 16165bd2acdcSHaibo Chen &boarddata->strobe_dll_delay_target); 1617ca6b5fe2SRob Herring if (of_property_read_bool(np, "no-1-8-v")) 161886f495c5SStefan Agner host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; 1619ad93220dSDong Aisheng 1620602519b2SDong Aisheng if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line)) 1621602519b2SDong Aisheng boarddata->delay_line = 0; 1622602519b2SDong Aisheng 16236dab809bSAndy Shevchenko mmc_of_parse_voltage(host->mmc, &host->ocr_mask); 162407bf2b54SSascha Hauer 1625f410ee0aSPeng Fan if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pinctrl)) { 162691fa4252SDong Aisheng imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl, 162791fa4252SDong Aisheng ESDHC_PINCTRL_STATE_100MHZ); 162891fa4252SDong Aisheng imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl, 162991fa4252SDong Aisheng ESDHC_PINCTRL_STATE_200MHZ); 163091fa4252SDong Aisheng } 163191fa4252SDong Aisheng 163215064119SFabio Estevam /* call to generic mmc_of_parse to support additional capabilities */ 16334800e87aSDong Aisheng ret = mmc_of_parse(host->mmc); 16344800e87aSDong Aisheng if (ret) 16354800e87aSDong Aisheng return ret; 16364800e87aSDong Aisheng 163781dce149SHaibo Chen /* HS400/HS400ES require 8 bit bus */ 163881dce149SHaibo Chen if (!(host->mmc->caps & MMC_CAP_8_BIT_DATA)) 163981dce149SHaibo Chen host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES); 164081dce149SHaibo Chen 1641287980e4SArnd Bergmann if (mmc_gpio_get_cd(host->mmc) >= 0) 16424800e87aSDong Aisheng host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 16434800e87aSDong Aisheng 16444800e87aSDong Aisheng return 0; 1645abfafc2dSShawn Guo } 1646abfafc2dSShawn Guo 1647c3be1efdSBill Pemberton static int sdhci_esdhc_imx_probe(struct platform_device *pdev) 164895f25efeSWolfram Sang { 164985d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 165085d6509dSShawn Guo struct sdhci_host *host; 1651bb6e3581SBOUGH CHEN struct cqhci_host *cq_host; 16520c6d49ceSWolfram Sang int err; 1653e149860dSRichard Zhu struct pltfm_imx_data *imx_data; 165495f25efeSWolfram Sang 1655070e6d3fSJisheng Zhang host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 1656070e6d3fSJisheng Zhang sizeof(*imx_data)); 165785d6509dSShawn Guo if (IS_ERR(host)) 165885d6509dSShawn Guo return PTR_ERR(host); 165985d6509dSShawn Guo 166085d6509dSShawn Guo pltfm_host = sdhci_priv(host); 166185d6509dSShawn Guo 1662070e6d3fSJisheng Zhang imx_data = sdhci_pltfm_priv(pltfm_host); 166357ed3314SShawn Guo 166491b3d2e5SFabio Estevam imx_data->socdata = device_get_match_data(&pdev->dev); 166585d6509dSShawn Guo 16661c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1667d1b98305SRafael J. Wysocki cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 16681c4989b0SBOUGH CHEN 166952dac615SSascha Hauer imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 167052dac615SSascha Hauer if (IS_ERR(imx_data->clk_ipg)) { 167152dac615SSascha Hauer err = PTR_ERR(imx_data->clk_ipg); 1672e3af31c6SShawn Guo goto free_sdhci; 167395f25efeSWolfram Sang } 167452dac615SSascha Hauer 167552dac615SSascha Hauer imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); 167652dac615SSascha Hauer if (IS_ERR(imx_data->clk_ahb)) { 167752dac615SSascha Hauer err = PTR_ERR(imx_data->clk_ahb); 1678e3af31c6SShawn Guo goto free_sdhci; 167952dac615SSascha Hauer } 168052dac615SSascha Hauer 168152dac615SSascha Hauer imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); 168252dac615SSascha Hauer if (IS_ERR(imx_data->clk_per)) { 168352dac615SSascha Hauer err = PTR_ERR(imx_data->clk_per); 1684e3af31c6SShawn Guo goto free_sdhci; 168552dac615SSascha Hauer } 168652dac615SSascha Hauer 168752dac615SSascha Hauer pltfm_host->clk = imx_data->clk_per; 1688a974862fSDong Aisheng pltfm_host->clock = clk_get_rate(pltfm_host->clk); 168917b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_per); 169017b1eb7fSFabio Estevam if (err) 169117b1eb7fSFabio Estevam goto free_sdhci; 169217b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ipg); 169317b1eb7fSFabio Estevam if (err) 169417b1eb7fSFabio Estevam goto disable_per_clk; 169517b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ahb); 169617b1eb7fSFabio Estevam if (err) 169717b1eb7fSFabio Estevam goto disable_ipg_clk; 169895f25efeSWolfram Sang 1699ad93220dSDong Aisheng imx_data->pinctrl = devm_pinctrl_get(&pdev->dev); 17009e70ff99SHaibo Chen if (IS_ERR(imx_data->pinctrl)) 1701b62eee9fSHaibo Chen dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n"); 1702e62d8b8fSDong Aisheng 170369ed60e0SDong Aisheng if (esdhc_is_usdhc(imx_data)) { 170469ed60e0SDong Aisheng host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; 170509c8192bSStefan Agner host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR; 1706f6140462SHaibo Chen 1707f6140462SHaibo Chen /* GPIO CD can be set as a wakeup source */ 1708f6140462SHaibo Chen host->mmc->caps |= MMC_CAP_CD_WAKE; 1709f6140462SHaibo Chen 17104245afffSDong Aisheng if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) 17114245afffSDong Aisheng host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; 1712a75dcbf4SDong Aisheng 1713a75dcbf4SDong Aisheng /* clear tuning bits in case ROM has set it already */ 1714a75dcbf4SDong Aisheng writel(0x0, host->ioaddr + ESDHC_MIX_CTRL); 1715869f8a69SAdrian Hunter writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1716a75dcbf4SDong Aisheng writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 1717de3e1dd0SBOUGH CHEN 1718de3e1dd0SBOUGH CHEN /* 1719de3e1dd0SBOUGH CHEN * Link usdhc specific mmc_host_ops execute_tuning function, 1720de3e1dd0SBOUGH CHEN * to replace the standard one in sdhci_ops. 1721de3e1dd0SBOUGH CHEN */ 1722de3e1dd0SBOUGH CHEN host->mmc_host_ops.execute_tuning = usdhc_execute_tuning; 172352e4c32bSHaibo Chen 172452e4c32bSHaibo Chen /* 172552e4c32bSHaibo Chen * Link usdhc specific mmc_host_ops init card function, 172652e4c32bSHaibo Chen * to distinguish the card type. 172752e4c32bSHaibo Chen */ 172852e4c32bSHaibo Chen host->mmc_host_ops.init_card = usdhc_init_card; 172969ed60e0SDong Aisheng } 1730f750ba9bSShawn Guo 17316e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) 17326e9fd28eSDong Aisheng sdhci_esdhc_ops.platform_execute_tuning = 17336e9fd28eSDong Aisheng esdhc_executing_tuning; 17348b2bb0adSDong Aisheng 173518094430SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) 173618094430SDong Aisheng host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; 173718094430SDong Aisheng 173881dce149SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_HS400) 17392991ad76SLucas Stach host->mmc->caps2 |= MMC_CAP2_HS400; 174028b07674SHaibo Chen 174174898cbcSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23) 174274898cbcSHaibo Chen host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN; 174374898cbcSHaibo Chen 174481dce149SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) { 1745029e2476SBOUGH CHEN host->mmc->caps2 |= MMC_CAP2_HS400_ES; 1746029e2476SBOUGH CHEN host->mmc_host_ops.hs400_enhanced_strobe = 1747029e2476SBOUGH CHEN esdhc_hs400_enhanced_strobe; 1748029e2476SBOUGH CHEN } 1749029e2476SBOUGH CHEN 1750bb6e3581SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { 1751bcdb5301SBOUGH CHEN host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 1752bb6e3581SBOUGH CHEN cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL); 17539a633f3bSWei Yongjun if (!cq_host) { 17549a633f3bSWei Yongjun err = -ENOMEM; 1755bb6e3581SBOUGH CHEN goto disable_ahb_clk; 1756bb6e3581SBOUGH CHEN } 1757bb6e3581SBOUGH CHEN 1758bb6e3581SBOUGH CHEN cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET; 1759bb6e3581SBOUGH CHEN cq_host->ops = &esdhc_cqhci_ops; 1760bb6e3581SBOUGH CHEN 1761bb6e3581SBOUGH CHEN err = cqhci_init(cq_host, host->mmc, false); 1762bb6e3581SBOUGH CHEN if (err) 1763bb6e3581SBOUGH CHEN goto disable_ahb_clk; 1764bb6e3581SBOUGH CHEN } 1765bb6e3581SBOUGH CHEN 176681dce149SHaibo Chen err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); 176781dce149SHaibo Chen if (err) 176881dce149SHaibo Chen goto disable_ahb_clk; 176981dce149SHaibo Chen 1770f3f5cf3dSDong Aisheng sdhci_esdhc_imx_hwinit(host); 1771f3f5cf3dSDong Aisheng 177285d6509dSShawn Guo err = sdhci_add_host(host); 177385d6509dSShawn Guo if (err) 177417b1eb7fSFabio Estevam goto disable_ahb_clk; 177585d6509dSShawn Guo 1776f62f7bccSHaibo Chen /* 1777f62f7bccSHaibo Chen * Setup the wakeup capability here, let user to decide 1778f62f7bccSHaibo Chen * whether need to enable this wakeup through sysfs interface. 1779f62f7bccSHaibo Chen */ 1780f62f7bccSHaibo Chen if ((host->mmc->pm_caps & MMC_PM_KEEP_POWER) && 1781f62f7bccSHaibo Chen (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ)) 1782f62f7bccSHaibo Chen device_set_wakeup_capable(&pdev->dev, true); 1783f62f7bccSHaibo Chen 178489d7e5c1SDong Aisheng pm_runtime_set_active(&pdev->dev); 178589d7e5c1SDong Aisheng pm_runtime_set_autosuspend_delay(&pdev->dev, 50); 178689d7e5c1SDong Aisheng pm_runtime_use_autosuspend(&pdev->dev); 178789d7e5c1SDong Aisheng pm_suspend_ignore_children(&pdev->dev, 1); 178877903c01SUlf Hansson pm_runtime_enable(&pdev->dev); 178989d7e5c1SDong Aisheng 17907e29c306SWolfram Sang return 0; 17917e29c306SWolfram Sang 179217b1eb7fSFabio Estevam disable_ahb_clk: 179352dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ahb); 179417b1eb7fSFabio Estevam disable_ipg_clk: 179517b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_ipg); 179617b1eb7fSFabio Estevam disable_per_clk: 179717b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_per); 1798e3af31c6SShawn Guo free_sdhci: 17991c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1800d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 180185d6509dSShawn Guo sdhci_pltfm_free(pdev); 180285d6509dSShawn Guo return err; 180395f25efeSWolfram Sang } 180495f25efeSWolfram Sang 1805*53b9222eSYangtao Li static void sdhci_esdhc_imx_remove(struct platform_device *pdev) 180695f25efeSWolfram Sang { 180785d6509dSShawn Guo struct sdhci_host *host = platform_get_drvdata(pdev); 180895f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1809070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1810a56f4413SFrank Li int dead; 181185d6509dSShawn Guo 18120b414368SUlf Hansson pm_runtime_get_sync(&pdev->dev); 1813a56f4413SFrank Li dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 18140b414368SUlf Hansson pm_runtime_disable(&pdev->dev); 18150b414368SUlf Hansson pm_runtime_put_noidle(&pdev->dev); 18160b414368SUlf Hansson 181785d6509dSShawn Guo sdhci_remove_host(host, dead); 18180c6d49ceSWolfram Sang 181952dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_per); 182052dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ipg); 182152dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ahb); 182252dac615SSascha Hauer 18231c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1824d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 18251c4989b0SBOUGH CHEN 182685d6509dSShawn Guo sdhci_pltfm_free(pdev); 182795f25efeSWolfram Sang } 182895f25efeSWolfram Sang 18292788ed42SUlf Hansson #ifdef CONFIG_PM_SLEEP 183004143fbaSDong Aisheng static int sdhci_esdhc_suspend(struct device *dev) 183104143fbaSDong Aisheng { 18323e3274abSUlf Hansson struct sdhci_host *host = dev_get_drvdata(dev); 1833a26a4f1bSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1834a26a4f1bSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1835bb6e3581SBOUGH CHEN int ret; 1836bb6e3581SBOUGH CHEN 1837bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) { 1838bb6e3581SBOUGH CHEN ret = cqhci_suspend(host->mmc); 1839bb6e3581SBOUGH CHEN if (ret) 1840bb6e3581SBOUGH CHEN return ret; 1841bb6e3581SBOUGH CHEN } 18423e3274abSUlf Hansson 1843a26a4f1bSHaibo Chen if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) && 1844a26a4f1bSHaibo Chen (host->tuning_mode != SDHCI_TUNING_MODE_1)) { 1845a26a4f1bSHaibo Chen mmc_retune_timer_stop(host->mmc); 1846a26a4f1bSHaibo Chen mmc_retune_needed(host->mmc); 1847a26a4f1bSHaibo Chen } 1848a26a4f1bSHaibo Chen 1849d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 1850d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 1851d38dcad4SAdrian Hunter 1852af8fade4SHaibo Chen ret = sdhci_suspend_host(host); 1853f6140462SHaibo Chen if (ret) 1854f6140462SHaibo Chen return ret; 1855f6140462SHaibo Chen 1856f6140462SHaibo Chen ret = pinctrl_pm_select_sleep_state(dev); 1857f6140462SHaibo Chen if (ret) 1858f6140462SHaibo Chen return ret; 1859f6140462SHaibo Chen 1860f6140462SHaibo Chen ret = mmc_gpio_set_cd_wake(host->mmc, true); 1861af8fade4SHaibo Chen 1862af8fade4SHaibo Chen return ret; 186304143fbaSDong Aisheng } 186404143fbaSDong Aisheng 186504143fbaSDong Aisheng static int sdhci_esdhc_resume(struct device *dev) 186604143fbaSDong Aisheng { 1867cc17e129SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 1868bb6e3581SBOUGH CHEN int ret; 1869cc17e129SDong Aisheng 1870af8fade4SHaibo Chen ret = pinctrl_pm_select_default_state(dev); 1871af8fade4SHaibo Chen if (ret) 1872af8fade4SHaibo Chen return ret; 1873af8fade4SHaibo Chen 187419dbfdd3SDong Aisheng /* re-initialize hw state in case it's lost in low power mode */ 187519dbfdd3SDong Aisheng sdhci_esdhc_imx_hwinit(host); 1876cc17e129SDong Aisheng 1877bb6e3581SBOUGH CHEN ret = sdhci_resume_host(host); 1878bb6e3581SBOUGH CHEN if (ret) 1879bb6e3581SBOUGH CHEN return ret; 1880bb6e3581SBOUGH CHEN 1881bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) 1882bb6e3581SBOUGH CHEN ret = cqhci_resume(host->mmc); 1883bb6e3581SBOUGH CHEN 1884f6140462SHaibo Chen if (!ret) 1885f6140462SHaibo Chen ret = mmc_gpio_set_cd_wake(host->mmc, false); 1886f6140462SHaibo Chen 1887bb6e3581SBOUGH CHEN return ret; 188804143fbaSDong Aisheng } 18892788ed42SUlf Hansson #endif 189004143fbaSDong Aisheng 18912788ed42SUlf Hansson #ifdef CONFIG_PM 189289d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_suspend(struct device *dev) 189389d7e5c1SDong Aisheng { 189489d7e5c1SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 189589d7e5c1SDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1896070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 189789d7e5c1SDong Aisheng int ret; 189889d7e5c1SDong Aisheng 1899bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) { 1900bb6e3581SBOUGH CHEN ret = cqhci_suspend(host->mmc); 1901bb6e3581SBOUGH CHEN if (ret) 1902bb6e3581SBOUGH CHEN return ret; 1903bb6e3581SBOUGH CHEN } 1904bb6e3581SBOUGH CHEN 190589d7e5c1SDong Aisheng ret = sdhci_runtime_suspend_host(host); 1906371d39faSMichael Trimarchi if (ret) 1907371d39faSMichael Trimarchi return ret; 190889d7e5c1SDong Aisheng 1909d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 1910d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 1911d38dcad4SAdrian Hunter 19123602785bSMichael Trimarchi imx_data->actual_clock = host->mmc->actual_clock; 19133602785bSMichael Trimarchi esdhc_pltfm_set_clock(host, 0); 191489d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_per); 191589d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_ipg); 191689d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_ahb); 191789d7e5c1SDong Aisheng 19181c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1919d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 19201c4989b0SBOUGH CHEN 192189d7e5c1SDong Aisheng return ret; 192289d7e5c1SDong Aisheng } 192389d7e5c1SDong Aisheng 192489d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_resume(struct device *dev) 192589d7e5c1SDong Aisheng { 192689d7e5c1SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 192789d7e5c1SDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1928070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 192917b1eb7fSFabio Estevam int err; 193089d7e5c1SDong Aisheng 19311c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1932d1b98305SRafael J. Wysocki cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 19331c4989b0SBOUGH CHEN 19345c11f1ffSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME) 19355c11f1ffSHaibo Chen clk_set_rate(imx_data->clk_per, pltfm_host->clock); 19365c11f1ffSHaibo Chen 1937a0ad3087SMichael Trimarchi err = clk_prepare_enable(imx_data->clk_ahb); 1938a0ad3087SMichael Trimarchi if (err) 19391c4989b0SBOUGH CHEN goto remove_pm_qos_request; 1940a0ad3087SMichael Trimarchi 194117b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_per); 194217b1eb7fSFabio Estevam if (err) 1943a0ad3087SMichael Trimarchi goto disable_ahb_clk; 1944af5d2b7bSUlf Hansson 194517b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ipg); 194617b1eb7fSFabio Estevam if (err) 194717b1eb7fSFabio Estevam goto disable_per_clk; 1948af5d2b7bSUlf Hansson 19493602785bSMichael Trimarchi esdhc_pltfm_set_clock(host, imx_data->actual_clock); 1950a0ad3087SMichael Trimarchi 1951c6303c5dSBaolin Wang err = sdhci_runtime_resume_host(host, 0); 195217b1eb7fSFabio Estevam if (err) 1953a0ad3087SMichael Trimarchi goto disable_ipg_clk; 195489d7e5c1SDong Aisheng 1955bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) 1956bb6e3581SBOUGH CHEN err = cqhci_resume(host->mmc); 1957bb6e3581SBOUGH CHEN 1958bb6e3581SBOUGH CHEN return err; 195917b1eb7fSFabio Estevam 196017b1eb7fSFabio Estevam disable_ipg_clk: 196117b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_ipg); 196217b1eb7fSFabio Estevam disable_per_clk: 196317b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_per); 1964a0ad3087SMichael Trimarchi disable_ahb_clk: 1965a0ad3087SMichael Trimarchi clk_disable_unprepare(imx_data->clk_ahb); 19661c4989b0SBOUGH CHEN remove_pm_qos_request: 19671c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1968d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 196917b1eb7fSFabio Estevam return err; 197089d7e5c1SDong Aisheng } 197189d7e5c1SDong Aisheng #endif 197289d7e5c1SDong Aisheng 197389d7e5c1SDong Aisheng static const struct dev_pm_ops sdhci_esdhc_pmops = { 197404143fbaSDong Aisheng SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume) 197589d7e5c1SDong Aisheng SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend, 197689d7e5c1SDong Aisheng sdhci_esdhc_runtime_resume, NULL) 197789d7e5c1SDong Aisheng }; 197889d7e5c1SDong Aisheng 197985d6509dSShawn Guo static struct platform_driver sdhci_esdhc_imx_driver = { 198085d6509dSShawn Guo .driver = { 198185d6509dSShawn Guo .name = "sdhci-esdhc-imx", 198221b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 1983abfafc2dSShawn Guo .of_match_table = imx_esdhc_dt_ids, 198489d7e5c1SDong Aisheng .pm = &sdhci_esdhc_pmops, 198585d6509dSShawn Guo }, 198685d6509dSShawn Guo .probe = sdhci_esdhc_imx_probe, 1987*53b9222eSYangtao Li .remove_new = sdhci_esdhc_imx_remove, 198895f25efeSWolfram Sang }; 198985d6509dSShawn Guo 1990d1f81a64SAxel Lin module_platform_driver(sdhci_esdhc_imx_driver); 199185d6509dSShawn Guo 199285d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); 1993035ff831SWolfram Sang MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>"); 199485d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 1995