1a6e7e407SFabio Estevam // SPDX-License-Identifier: GPL-2.0 295f25efeSWolfram Sang /* 395f25efeSWolfram Sang * Freescale eSDHC i.MX controller driver for the platform bus. 495f25efeSWolfram Sang * 595f25efeSWolfram Sang * derived from the OF-version. 695f25efeSWolfram Sang * 795f25efeSWolfram Sang * Copyright (c) 2010 Pengutronix e.K. 8035ff831SWolfram Sang * Author: Wolfram Sang <kernel@pengutronix.de> 995f25efeSWolfram Sang */ 1095f25efeSWolfram Sang 11a8e809ecSMasahiro Yamada #include <linux/bitfield.h> 1295f25efeSWolfram Sang #include <linux/io.h> 13f581e909SHaibo Chen #include <linux/iopoll.h> 1495f25efeSWolfram Sang #include <linux/delay.h> 1595f25efeSWolfram Sang #include <linux/err.h> 1695f25efeSWolfram Sang #include <linux/clk.h> 1766506f76SShawn Guo #include <linux/module.h> 18e149860dSRichard Zhu #include <linux/slab.h> 191c4989b0SBOUGH CHEN #include <linux/pm_qos.h> 2095f25efeSWolfram Sang #include <linux/mmc/host.h> 2158ac8177SRichard Zhu #include <linux/mmc/mmc.h> 2258ac8177SRichard Zhu #include <linux/mmc/sdio.h> 23fbe5fdd1SShawn Guo #include <linux/mmc/slot-gpio.h> 24abfafc2dSShawn Guo #include <linux/of.h> 25abfafc2dSShawn Guo #include <linux/of_device.h> 26e62d8b8fSDong Aisheng #include <linux/pinctrl/consumer.h> 2789d7e5c1SDong Aisheng #include <linux/pm_runtime.h> 2895f25efeSWolfram Sang #include "sdhci-pltfm.h" 2995f25efeSWolfram Sang #include "sdhci-esdhc.h" 30bb6e3581SBOUGH CHEN #include "cqhci.h" 3195f25efeSWolfram Sang 32a215186dSHaibo Chen #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f 3360bf6396SShawn Guo #define ESDHC_CTRL_D3CD 0x08 34fd44954eSHaibo Chen #define ESDHC_BURST_LEN_EN_INCR (1 << 27) 3558ac8177SRichard Zhu /* VENDOR SPEC register */ 3660bf6396SShawn Guo #define ESDHC_VENDOR_SPEC 0xc0 3760bf6396SShawn Guo #define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1) 380322191eSDong Aisheng #define ESDHC_VENDOR_SPEC_VSELECT (1 << 1) 39fed2f6e2SDong Aisheng #define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8) 403722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_AND_STATUS_REG 0xc2 413722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_REG 0xc3 423722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_MASK 0xf 433722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_CMD_STATE 1 443722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_DATA_STATE 2 453722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_TRANS_STATE 3 463722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_DMA_STATE 4 473722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_ADMA_STATE 5 483722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_FIFO_STATE 6 493722c74cSHaibo Chen #define ESDHC_DEBUG_SEL_ASYNC_FIFO_STATE 7 5060bf6396SShawn Guo #define ESDHC_WTMK_LVL 0x44 51cc17e129SDong Aisheng #define ESDHC_WTMK_DEFAULT_VAL 0x10401040 523fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_RD_WML_MASK 0x000000FF 533fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_RD_WML_SHIFT 0 543fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_WR_WML_MASK 0x00FF0000 553fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_WR_WML_SHIFT 16 563fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_WML_VAL_DEF 64 573fbd4322SAndrew Gabbasov #define ESDHC_WTMK_LVL_WML_VAL_MAX 128 5860bf6396SShawn Guo #define ESDHC_MIX_CTRL 0x48 59de5bdbffSDong Aisheng #define ESDHC_MIX_CTRL_DDREN (1 << 3) 602a15f981SShawn Guo #define ESDHC_MIX_CTRL_AC23EN (1 << 7) 610322191eSDong Aisheng #define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22) 620322191eSDong Aisheng #define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23) 630b330e38SDong Aisheng #define ESDHC_MIX_CTRL_AUTO_TUNE_EN (1 << 24) 640322191eSDong Aisheng #define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25) 6528b07674SHaibo Chen #define ESDHC_MIX_CTRL_HS400_EN (1 << 26) 66029e2476SBOUGH CHEN #define ESDHC_MIX_CTRL_HS400_ES_EN (1 << 27) 672a15f981SShawn Guo /* Bits 3 and 6 are not SDHCI standard definitions */ 682a15f981SShawn Guo #define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7 69d131a71cSDong Aisheng /* Tuning bits */ 70d131a71cSDong Aisheng #define ESDHC_MIX_CTRL_TUNING_MASK 0x03c00000 7158ac8177SRichard Zhu 72602519b2SDong Aisheng /* dll control register */ 73602519b2SDong Aisheng #define ESDHC_DLL_CTRL 0x60 74602519b2SDong Aisheng #define ESDHC_DLL_OVERRIDE_VAL_SHIFT 9 75602519b2SDong Aisheng #define ESDHC_DLL_OVERRIDE_EN_SHIFT 8 76602519b2SDong Aisheng 770322191eSDong Aisheng /* tune control register */ 780322191eSDong Aisheng #define ESDHC_TUNE_CTRL_STATUS 0x68 790322191eSDong Aisheng #define ESDHC_TUNE_CTRL_STEP 1 800322191eSDong Aisheng #define ESDHC_TUNE_CTRL_MIN 0 810322191eSDong Aisheng #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) 820322191eSDong Aisheng 8328b07674SHaibo Chen /* strobe dll register */ 8428b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL 0x70 8528b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0) 8628b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1) 875bd2acdcSHaibo Chen #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT 0x7 8828b07674SHaibo Chen #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3 892eaf5a53SBOUGH CHEN #define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT (4 << 20) 9028b07674SHaibo Chen 9128b07674SHaibo Chen #define ESDHC_STROBE_DLL_STATUS 0x74 9228b07674SHaibo Chen #define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1) 9328b07674SHaibo Chen #define ESDHC_STROBE_DLL_STS_SLV_LOCK 0x1 9428b07674SHaibo Chen 95bcdb5301SBOUGH CHEN #define ESDHC_VEND_SPEC2 0xc8 96bcdb5301SBOUGH CHEN #define ESDHC_VEND_SPEC2_EN_BUSY_IRQ (1 << 8) 9745334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN (1 << 4) 9845334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN (0 << 4) 9945334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN (2 << 4) 10045334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN (1 << 6) 10145334ee1SHaibo Chen #define ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK (7 << 4) 102bcdb5301SBOUGH CHEN 1036e9fd28eSDong Aisheng #define ESDHC_TUNING_CTRL 0xcc 1046e9fd28eSDong Aisheng #define ESDHC_STD_TUNING_EN (1 << 24) 1056e9fd28eSDong Aisheng /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ 106d87fc966SDong Aisheng #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 1071194be8cSHaibo Chen #define ESDHC_TUNING_START_TAP_MASK 0x7f 10816e40e5bSHaibo Chen #define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE (1 << 7) 109260ecb3cSHaibo Chen #define ESDHC_TUNING_STEP_MASK 0x00070000 110d407e30bSHaibo Chen #define ESDHC_TUNING_STEP_SHIFT 16 1116e9fd28eSDong Aisheng 112ad93220dSDong Aisheng /* pinctrl state */ 113ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" 114ad93220dSDong Aisheng #define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz" 115ad93220dSDong Aisheng 11658ac8177SRichard Zhu /* 117af51079eSSascha Hauer * Our interpretation of the SDHCI_HOST_CONTROL register 118af51079eSSascha Hauer */ 119af51079eSSascha Hauer #define ESDHC_CTRL_4BITBUS (0x1 << 1) 120af51079eSSascha Hauer #define ESDHC_CTRL_8BITBUS (0x2 << 1) 121af51079eSSascha Hauer #define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) 12245334ee1SHaibo Chen #define USDHC_GET_BUSWIDTH(c) (c & ESDHC_CTRL_BUSWIDTH_MASK) 123af51079eSSascha Hauer 124af51079eSSascha Hauer /* 125d04f8d5bSBenoît Thébaudeau * There is an INT DMA ERR mismatch between eSDHC and STD SDHC SPEC: 12697e4ba6aSRichard Zhu * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, 12797e4ba6aSRichard Zhu * but bit28 is used as the INT DMA ERR in fsl eSDHC design. 12897e4ba6aSRichard Zhu * Define this macro DMA error INT for fsl eSDHC 12997e4ba6aSRichard Zhu */ 13060bf6396SShawn Guo #define ESDHC_INT_VENDOR_SPEC_DMA_ERR (1 << 28) 13197e4ba6aSRichard Zhu 132bb6e3581SBOUGH CHEN /* the address offset of CQHCI */ 133bb6e3581SBOUGH CHEN #define ESDHC_CQHCI_ADDR_OFFSET 0x100 134bb6e3581SBOUGH CHEN 13597e4ba6aSRichard Zhu /* 13658ac8177SRichard Zhu * The CMDTYPE of the CMD register (offset 0xE) should be set to 13758ac8177SRichard Zhu * "11" when the STOP CMD12 is issued on imx53 to abort one 13858ac8177SRichard Zhu * open ended multi-blk IO. Otherwise the TC INT wouldn't 13958ac8177SRichard Zhu * be generated. 14058ac8177SRichard Zhu * In exact block transfer, the controller doesn't complete the 14158ac8177SRichard Zhu * operations automatically as required at the end of the 14258ac8177SRichard Zhu * transfer and remains on hold if the abort command is not sent. 14358ac8177SRichard Zhu * As a result, the TC flag is not asserted and SW received timeout 144d04f8d5bSBenoît Thébaudeau * exception. Bit1 of Vendor Spec register is used to fix it. 14558ac8177SRichard Zhu */ 14631fbb301SShawn Guo #define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1) 14731fbb301SShawn Guo /* 1489d61c009SShawn Guo * The flag tells that the ESDHC controller is an USDHC block that is 1499d61c009SShawn Guo * integrated on the i.MX6 series. 1509d61c009SShawn Guo */ 1519d61c009SShawn Guo #define ESDHC_FLAG_USDHC BIT(3) 1526e9fd28eSDong Aisheng /* The IP supports manual tuning process */ 1536e9fd28eSDong Aisheng #define ESDHC_FLAG_MAN_TUNING BIT(4) 1546e9fd28eSDong Aisheng /* The IP supports standard tuning process */ 1556e9fd28eSDong Aisheng #define ESDHC_FLAG_STD_TUNING BIT(5) 1566e9fd28eSDong Aisheng /* The IP has SDHCI_CAPABILITIES_1 register */ 1576e9fd28eSDong Aisheng #define ESDHC_FLAG_HAVE_CAP1 BIT(6) 15818094430SDong Aisheng /* 159d04f8d5bSBenoît Thébaudeau * The IP has erratum ERR004536 16018094430SDong Aisheng * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow, 16118094430SDong Aisheng * when reading data from the card 162667123f6SBenoît Thébaudeau * This flag is also set for i.MX25 and i.MX35 in order to get 163667123f6SBenoît Thébaudeau * SDHCI_QUIRK_BROKEN_ADMA, but for different reasons (ADMA capability bits). 16418094430SDong Aisheng */ 16518094430SDong Aisheng #define ESDHC_FLAG_ERR004536 BIT(7) 1664245afffSDong Aisheng /* The IP supports HS200 mode */ 1674245afffSDong Aisheng #define ESDHC_FLAG_HS200 BIT(8) 16828b07674SHaibo Chen /* The IP supports HS400 mode */ 16928b07674SHaibo Chen #define ESDHC_FLAG_HS400 BIT(9) 170af6a50d4SBOUGH CHEN /* 171af6a50d4SBOUGH CHEN * The IP has errata ERR010450 172af6a50d4SBOUGH CHEN * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't 173af6a50d4SBOUGH CHEN * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz. 174af6a50d4SBOUGH CHEN */ 175af6a50d4SBOUGH CHEN #define ESDHC_FLAG_ERR010450 BIT(10) 176029e2476SBOUGH CHEN /* The IP supports HS400ES mode */ 177029e2476SBOUGH CHEN #define ESDHC_FLAG_HS400_ES BIT(11) 178bb6e3581SBOUGH CHEN /* The IP has Host Controller Interface for Command Queuing */ 179bb6e3581SBOUGH CHEN #define ESDHC_FLAG_CQHCI BIT(12) 1801c4989b0SBOUGH CHEN /* need request pmqos during low power */ 1811c4989b0SBOUGH CHEN #define ESDHC_FLAG_PMQOS BIT(13) 182a26a4f1bSHaibo Chen /* The IP state got lost in low power mode */ 183a26a4f1bSHaibo Chen #define ESDHC_FLAG_STATE_LOST_IN_LPMODE BIT(14) 1845c11f1ffSHaibo Chen /* The IP lost clock rate in PM_RUNTIME */ 1855c11f1ffSHaibo Chen #define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME BIT(15) 18674898cbcSHaibo Chen /* 18774898cbcSHaibo Chen * The IP do not support the ACMD23 feature completely when use ADMA mode. 18874898cbcSHaibo Chen * In ADMA mode, it only use the 16 bit block count of the register 0x4 18974898cbcSHaibo Chen * (BLOCK_ATT) as the CMD23's argument for ACMD23 mode, which means it will 19074898cbcSHaibo Chen * ignore the upper 16 bit of the CMD23's argument. This will block the reliable 19174898cbcSHaibo Chen * write operation in RPMB, because RPMB reliable write need to set the bit31 19274898cbcSHaibo Chen * of the CMD23's argument. 19374898cbcSHaibo Chen * imx6qpdl/imx6sx/imx6sl/imx7d has this limitation only for ADMA mode, SDMA 19474898cbcSHaibo Chen * do not has this limitation. so when these SoC use ADMA mode, it need to 19574898cbcSHaibo Chen * disable the ACMD23 feature. 19674898cbcSHaibo Chen */ 19774898cbcSHaibo Chen #define ESDHC_FLAG_BROKEN_AUTO_CMD23 BIT(16) 198e149860dSRichard Zhu 1995c4f0062SChester Lin /* ERR004536 is not applicable for the IP */ 2005c4f0062SChester Lin #define ESDHC_FLAG_SKIP_ERR004536 BIT(17) 2015c4f0062SChester Lin 2024a11cc64SFabio Estevam enum wp_types { 2034a11cc64SFabio Estevam ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ 2044a11cc64SFabio Estevam ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ 2054a11cc64SFabio Estevam ESDHC_WP_GPIO, /* external gpio pin for WP */ 2064a11cc64SFabio Estevam }; 2074a11cc64SFabio Estevam 2084a11cc64SFabio Estevam enum cd_types { 2094a11cc64SFabio Estevam ESDHC_CD_NONE, /* no CD, neither controller nor gpio */ 2104a11cc64SFabio Estevam ESDHC_CD_CONTROLLER, /* mmc controller internal CD */ 2114a11cc64SFabio Estevam ESDHC_CD_GPIO, /* external gpio pin for CD */ 2124a11cc64SFabio Estevam ESDHC_CD_PERMANENT, /* no CD, card permanently wired to host */ 2134a11cc64SFabio Estevam }; 2144a11cc64SFabio Estevam 2154a11cc64SFabio Estevam /* 2164a11cc64SFabio Estevam * struct esdhc_platform_data - platform data for esdhc on i.MX 2174a11cc64SFabio Estevam * 2184a11cc64SFabio Estevam * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35. 2194a11cc64SFabio Estevam * 2204a11cc64SFabio Estevam * @wp_type: type of write_protect method (see wp_types enum above) 2214a11cc64SFabio Estevam * @cd_type: type of card_detect method (see cd_types enum above) 2224a11cc64SFabio Estevam */ 2234a11cc64SFabio Estevam 2244a11cc64SFabio Estevam struct esdhc_platform_data { 2254a11cc64SFabio Estevam enum wp_types wp_type; 2264a11cc64SFabio Estevam enum cd_types cd_type; 2274a11cc64SFabio Estevam int max_bus_width; 2284a11cc64SFabio Estevam unsigned int delay_line; 2294a11cc64SFabio Estevam unsigned int tuning_step; /* The delay cell steps in tuning procedure */ 2304a11cc64SFabio Estevam unsigned int tuning_start_tap; /* The start delay cell point in tuning procedure */ 2314a11cc64SFabio Estevam unsigned int strobe_dll_delay_target; /* The delay cell for strobe pad (read clock) */ 2324a11cc64SFabio Estevam }; 2334a11cc64SFabio Estevam 234f47c4bbfSShawn Guo struct esdhc_soc_data { 235f47c4bbfSShawn Guo u32 flags; 236f47c4bbfSShawn Guo }; 237f47c4bbfSShawn Guo 2384f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx25_data = { 239667123f6SBenoît Thébaudeau .flags = ESDHC_FLAG_ERR004536, 240f47c4bbfSShawn Guo }; 241f47c4bbfSShawn Guo 2424f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx35_data = { 243667123f6SBenoît Thébaudeau .flags = ESDHC_FLAG_ERR004536, 244f47c4bbfSShawn Guo }; 245f47c4bbfSShawn Guo 2464f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx51_data = { 247f47c4bbfSShawn Guo .flags = 0, 248f47c4bbfSShawn Guo }; 249f47c4bbfSShawn Guo 2504f100012SAndrey Smirnov static const struct esdhc_soc_data esdhc_imx53_data = { 251f47c4bbfSShawn Guo .flags = ESDHC_FLAG_MULTIBLK_NO_INT, 252f47c4bbfSShawn Guo }; 253f47c4bbfSShawn Guo 2544f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6q_data = { 25574898cbcSHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING 25674898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 2576e9fd28eSDong Aisheng }; 2586e9fd28eSDong Aisheng 2594f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sl_data = { 2606e9fd28eSDong Aisheng .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 2614245afffSDong Aisheng | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 26274898cbcSHaibo Chen | ESDHC_FLAG_HS200 26374898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 26474898cbcSHaibo Chen }; 26574898cbcSHaibo Chen 26674898cbcSHaibo Chen static const struct esdhc_soc_data usdhc_imx6sll_data = { 26774898cbcSHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 26874898cbcSHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 26986b59671SHaibo Chen | ESDHC_FLAG_HS400 27074898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 27157ed3314SShawn Guo }; 27257ed3314SShawn Guo 2734f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx6sx_data = { 274913d4951SDong Aisheng .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 275a26a4f1bSHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 27674898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 27774898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 278913d4951SDong Aisheng }; 279913d4951SDong Aisheng 280af6a50d4SBOUGH CHEN static const struct esdhc_soc_data usdhc_imx6ull_data = { 281af6a50d4SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 282af6a50d4SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 283a26a4f1bSHaibo Chen | ESDHC_FLAG_ERR010450 284a26a4f1bSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 285af6a50d4SBOUGH CHEN }; 286af6a50d4SBOUGH CHEN 2874f100012SAndrey Smirnov static const struct esdhc_soc_data usdhc_imx7d_data = { 28828b07674SHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 28928b07674SHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 290a26a4f1bSHaibo Chen | ESDHC_FLAG_HS400 29174898cbcSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 29274898cbcSHaibo Chen | ESDHC_FLAG_BROKEN_AUTO_CMD23, 29328b07674SHaibo Chen }; 29428b07674SHaibo Chen 2955c4f0062SChester Lin static struct esdhc_soc_data usdhc_s32g2_data = { 2965c4f0062SChester Lin .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING 2975c4f0062SChester Lin | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 2985c4f0062SChester Lin | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 2995c4f0062SChester Lin | ESDHC_FLAG_SKIP_ERR004536, 3005c4f0062SChester Lin }; 3015c4f0062SChester Lin 3021c4989b0SBOUGH CHEN static struct esdhc_soc_data usdhc_imx7ulp_data = { 3031c4989b0SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 3041c4989b0SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 305a26a4f1bSHaibo Chen | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 306a26a4f1bSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 3071c4989b0SBOUGH CHEN }; 3082f4788f3SJesse Taube static struct esdhc_soc_data usdhc_imxrt1050_data = { 3092f4788f3SJesse Taube .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_HS200 | ESDHC_FLAG_ERR004536, 3102f4788f3SJesse Taube }; 3111c4989b0SBOUGH CHEN 312029e2476SBOUGH CHEN static struct esdhc_soc_data usdhc_imx8qxp_data = { 313029e2476SBOUGH CHEN .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 314029e2476SBOUGH CHEN | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 315bb6e3581SBOUGH CHEN | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 3165c11f1ffSHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE 3175c11f1ffSHaibo Chen | ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME, 318029e2476SBOUGH CHEN }; 319029e2476SBOUGH CHEN 320cde5e8e9SHaibo Chen static struct esdhc_soc_data usdhc_imx8mm_data = { 321cde5e8e9SHaibo Chen .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING 322cde5e8e9SHaibo Chen | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 323cde5e8e9SHaibo Chen | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES 324cde5e8e9SHaibo Chen | ESDHC_FLAG_STATE_LOST_IN_LPMODE, 325e149860dSRichard Zhu }; 326e149860dSRichard Zhu 327e149860dSRichard Zhu struct pltfm_imx_data { 328e149860dSRichard Zhu u32 scratchpad; 329e62d8b8fSDong Aisheng struct pinctrl *pinctrl; 330ad93220dSDong Aisheng struct pinctrl_state *pins_100mhz; 331ad93220dSDong Aisheng struct pinctrl_state *pins_200mhz; 332f47c4bbfSShawn Guo const struct esdhc_soc_data *socdata; 333842afc02SShawn Guo struct esdhc_platform_data boarddata; 33452dac615SSascha Hauer struct clk *clk_ipg; 33552dac615SSascha Hauer struct clk *clk_ahb; 33652dac615SSascha Hauer struct clk *clk_per; 3373602785bSMichael Trimarchi unsigned int actual_clock; 338361b8482SLucas Stach enum { 339361b8482SLucas Stach NO_CMD_PENDING, /* no multiblock command pending */ 340361b8482SLucas Stach MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ 341361b8482SLucas Stach WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ 342361b8482SLucas Stach } multiblock_status; 343de5bdbffSDong Aisheng u32 is_ddr; 3441c4989b0SBOUGH CHEN struct pm_qos_request pm_qos_req; 345e149860dSRichard Zhu }; 346e149860dSRichard Zhu 347abfafc2dSShawn Guo static const struct of_device_id imx_esdhc_dt_ids[] = { 348f47c4bbfSShawn Guo { .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, }, 349f47c4bbfSShawn Guo { .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, }, 350f47c4bbfSShawn Guo { .compatible = "fsl,imx51-esdhc", .data = &esdhc_imx51_data, }, 351f47c4bbfSShawn Guo { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, 352913d4951SDong Aisheng { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, }, 3536e9fd28eSDong Aisheng { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, 35474898cbcSHaibo Chen { .compatible = "fsl,imx6sll-usdhc", .data = &usdhc_imx6sll_data, }, 355f47c4bbfSShawn Guo { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, 356af6a50d4SBOUGH CHEN { .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, }, 35728b07674SHaibo Chen { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, 3581c4989b0SBOUGH CHEN { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, 359029e2476SBOUGH CHEN { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, 360cde5e8e9SHaibo Chen { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, 3612f4788f3SJesse Taube { .compatible = "fsl,imxrt1050-usdhc", .data = &usdhc_imxrt1050_data, }, 3625c4f0062SChester Lin { .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, }, 363abfafc2dSShawn Guo { /* sentinel */ } 364abfafc2dSShawn Guo }; 365abfafc2dSShawn Guo MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); 366abfafc2dSShawn Guo 36757ed3314SShawn Guo static inline int is_imx25_esdhc(struct pltfm_imx_data *data) 36857ed3314SShawn Guo { 369f47c4bbfSShawn Guo return data->socdata == &esdhc_imx25_data; 37057ed3314SShawn Guo } 37157ed3314SShawn Guo 37257ed3314SShawn Guo static inline int is_imx53_esdhc(struct pltfm_imx_data *data) 37357ed3314SShawn Guo { 374f47c4bbfSShawn Guo return data->socdata == &esdhc_imx53_data; 37557ed3314SShawn Guo } 37657ed3314SShawn Guo 3779d61c009SShawn Guo static inline int esdhc_is_usdhc(struct pltfm_imx_data *data) 3789d61c009SShawn Guo { 379f47c4bbfSShawn Guo return !!(data->socdata->flags & ESDHC_FLAG_USDHC); 3809d61c009SShawn Guo } 3819d61c009SShawn Guo 38295f25efeSWolfram Sang static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) 38395f25efeSWolfram Sang { 38495f25efeSWolfram Sang void __iomem *base = host->ioaddr + (reg & ~0x3); 38595f25efeSWolfram Sang u32 shift = (reg & 0x3) * 8; 38695f25efeSWolfram Sang 38795f25efeSWolfram Sang writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); 38895f25efeSWolfram Sang } 38995f25efeSWolfram Sang 3903722c74cSHaibo Chen #define DRIVER_NAME "sdhci-esdhc-imx" 3913722c74cSHaibo Chen #define ESDHC_IMX_DUMP(f, x...) \ 3923722c74cSHaibo Chen pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) 3933722c74cSHaibo Chen static void esdhc_dump_debug_regs(struct sdhci_host *host) 3943722c74cSHaibo Chen { 3953722c74cSHaibo Chen int i; 3963722c74cSHaibo Chen char *debug_status[7] = { 3973722c74cSHaibo Chen "cmd debug status", 3983722c74cSHaibo Chen "data debug status", 3993722c74cSHaibo Chen "trans debug status", 4003722c74cSHaibo Chen "dma debug status", 4013722c74cSHaibo Chen "adma debug status", 4023722c74cSHaibo Chen "fifo debug status", 4033722c74cSHaibo Chen "async fifo debug status" 4043722c74cSHaibo Chen }; 4053722c74cSHaibo Chen 4063722c74cSHaibo Chen ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n"); 4073722c74cSHaibo Chen for (i = 0; i < 7; i++) { 4083722c74cSHaibo Chen esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 4093722c74cSHaibo Chen ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG); 4103722c74cSHaibo Chen ESDHC_IMX_DUMP("%s: 0x%04x\n", debug_status[i], 4113722c74cSHaibo Chen readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG)); 4123722c74cSHaibo Chen } 4133722c74cSHaibo Chen 4143722c74cSHaibo Chen esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG); 4153722c74cSHaibo Chen 4163722c74cSHaibo Chen } 4173722c74cSHaibo Chen 418f581e909SHaibo Chen static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host) 419f581e909SHaibo Chen { 420f581e909SHaibo Chen u32 present_state; 421f581e909SHaibo Chen int ret; 422f581e909SHaibo Chen 423f581e909SHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state, 424f581e909SHaibo Chen (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100); 425f581e909SHaibo Chen if (ret == -ETIMEDOUT) 426f581e909SHaibo Chen dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__); 427f581e909SHaibo Chen } 428f581e909SHaibo Chen 42945334ee1SHaibo Chen /* Enable the auto tuning circuit to check the CMD line and BUS line */ 43045334ee1SHaibo Chen static inline void usdhc_auto_tuning_mode_sel(struct sdhci_host *host) 43145334ee1SHaibo Chen { 43245334ee1SHaibo Chen u32 buswidth, auto_tune_buswidth; 43345334ee1SHaibo Chen 43445334ee1SHaibo Chen buswidth = USDHC_GET_BUSWIDTH(readl(host->ioaddr + SDHCI_HOST_CONTROL)); 43545334ee1SHaibo Chen 43645334ee1SHaibo Chen switch (buswidth) { 43745334ee1SHaibo Chen case ESDHC_CTRL_8BITBUS: 43845334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN; 43945334ee1SHaibo Chen break; 44045334ee1SHaibo Chen case ESDHC_CTRL_4BITBUS: 44145334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN; 44245334ee1SHaibo Chen break; 44345334ee1SHaibo Chen default: /* 1BITBUS */ 44445334ee1SHaibo Chen auto_tune_buswidth = ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN; 44545334ee1SHaibo Chen break; 44645334ee1SHaibo Chen } 44745334ee1SHaibo Chen 44845334ee1SHaibo Chen esdhc_clrset_le(host, ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK, 44945334ee1SHaibo Chen auto_tune_buswidth | ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN, 45045334ee1SHaibo Chen ESDHC_VEND_SPEC2); 45145334ee1SHaibo Chen } 45245334ee1SHaibo Chen 4537e29c306SWolfram Sang static u32 esdhc_readl_le(struct sdhci_host *host, int reg) 4547e29c306SWolfram Sang { 455361b8482SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 456070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 457913413c3SShawn Guo u32 val = readl(host->ioaddr + reg); 458913413c3SShawn Guo 4590322191eSDong Aisheng if (unlikely(reg == SDHCI_PRESENT_STATE)) { 4600322191eSDong Aisheng u32 fsl_prss = val; 4610322191eSDong Aisheng /* save the least 20 bits */ 4620322191eSDong Aisheng val = fsl_prss & 0x000FFFFF; 4630322191eSDong Aisheng /* move dat[0-3] bits */ 4640322191eSDong Aisheng val |= (fsl_prss & 0x0F000000) >> 4; 4650322191eSDong Aisheng /* move cmd line bit */ 4660322191eSDong Aisheng val |= (fsl_prss & 0x00800000) << 1; 4670322191eSDong Aisheng } 4680322191eSDong Aisheng 46997e4ba6aSRichard Zhu if (unlikely(reg == SDHCI_CAPABILITIES)) { 4706b4fb671SDong Aisheng /* ignore bit[0-15] as it stores cap_1 register val for mx6sl */ 4716b4fb671SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) 4726b4fb671SDong Aisheng val &= 0xffff0000; 4736b4fb671SDong Aisheng 47497e4ba6aSRichard Zhu /* In FSL esdhc IC module, only bit20 is used to indicate the 47597e4ba6aSRichard Zhu * ADMA2 capability of esdhc, but this bit is messed up on 47697e4ba6aSRichard Zhu * some SOCs (e.g. on MX25, MX35 this bit is set, but they 47797e4ba6aSRichard Zhu * don't actually support ADMA2). So set the BROKEN_ADMA 478d04f8d5bSBenoît Thébaudeau * quirk on MX25/35 platforms. 47997e4ba6aSRichard Zhu */ 48097e4ba6aSRichard Zhu 48197e4ba6aSRichard Zhu if (val & SDHCI_CAN_DO_ADMA1) { 48297e4ba6aSRichard Zhu val &= ~SDHCI_CAN_DO_ADMA1; 48397e4ba6aSRichard Zhu val |= SDHCI_CAN_DO_ADMA2; 48497e4ba6aSRichard Zhu } 48597e4ba6aSRichard Zhu } 48697e4ba6aSRichard Zhu 4876e9fd28eSDong Aisheng if (unlikely(reg == SDHCI_CAPABILITIES_1)) { 4886e9fd28eSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 4896e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_HAVE_CAP1) 4906e9fd28eSDong Aisheng val = readl(host->ioaddr + SDHCI_CAPABILITIES) & 0xFFFF; 4916e9fd28eSDong Aisheng else 4926e9fd28eSDong Aisheng /* imx6q/dl does not have cap_1 register, fake one */ 4930322191eSDong Aisheng val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 494888824bbSDong Aisheng | SDHCI_SUPPORT_SDR50 495da0295ffSDong Aisheng | SDHCI_USE_SDR50_TUNING 496a8e809ecSMasahiro Yamada | FIELD_PREP(SDHCI_RETUNING_MODE_MASK, 497a8e809ecSMasahiro Yamada SDHCI_TUNING_MODE_3); 49828b07674SHaibo Chen 49992748beaSStefan Agner /* 50092748beaSStefan Agner * Do not advertise faster UHS modes if there are no 50192748beaSStefan Agner * pinctrl states for 100MHz/200MHz. 50292748beaSStefan Agner */ 50325e8b9ebSShawn Guo if (IS_ERR_OR_NULL(imx_data->pins_100mhz)) 50425e8b9ebSShawn Guo val &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); 50525e8b9ebSShawn Guo if (IS_ERR_OR_NULL(imx_data->pins_200mhz)) 50625e8b9ebSShawn Guo val &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_HS400); 5076e9fd28eSDong Aisheng } 5086e9fd28eSDong Aisheng } 5090322191eSDong Aisheng 5109d61c009SShawn Guo if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { 5110322191eSDong Aisheng val = 0; 512804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF); 513804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF); 514804a65b3SMasahiro Yamada val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF); 5150322191eSDong Aisheng } 5160322191eSDong Aisheng 51797e4ba6aSRichard Zhu if (unlikely(reg == SDHCI_INT_STATUS)) { 51860bf6396SShawn Guo if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) { 51960bf6396SShawn Guo val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; 52097e4ba6aSRichard Zhu val |= SDHCI_INT_ADMA_ERROR; 52197e4ba6aSRichard Zhu } 522361b8482SLucas Stach 523361b8482SLucas Stach /* 524361b8482SLucas Stach * mask off the interrupt we get in response to the manually 525361b8482SLucas Stach * sent CMD12 526361b8482SLucas Stach */ 527361b8482SLucas Stach if ((imx_data->multiblock_status == WAIT_FOR_INT) && 528361b8482SLucas Stach ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) { 529361b8482SLucas Stach val &= ~SDHCI_INT_RESPONSE; 530361b8482SLucas Stach writel(SDHCI_INT_RESPONSE, host->ioaddr + 531361b8482SLucas Stach SDHCI_INT_STATUS); 532361b8482SLucas Stach imx_data->multiblock_status = NO_CMD_PENDING; 533361b8482SLucas Stach } 53497e4ba6aSRichard Zhu } 53597e4ba6aSRichard Zhu 5367e29c306SWolfram Sang return val; 5377e29c306SWolfram Sang } 5387e29c306SWolfram Sang 5397e29c306SWolfram Sang static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) 5407e29c306SWolfram Sang { 541e149860dSRichard Zhu struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 542070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 5430d58864bSTony Lin u32 data; 544e149860dSRichard Zhu 54577da3da0SAaron Brice if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE || 54677da3da0SAaron Brice reg == SDHCI_INT_STATUS)) { 547b7321042SDong Aisheng if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) { 5480d58864bSTony Lin /* 5490d58864bSTony Lin * Clear and then set D3CD bit to avoid missing the 550d04f8d5bSBenoît Thébaudeau * card interrupt. This is an eSDHC controller problem 5510d58864bSTony Lin * so we need to apply the following workaround: clear 5520d58864bSTony Lin * and set D3CD bit will make eSDHC re-sample the card 5530d58864bSTony Lin * interrupt. In case a card interrupt was lost, 5540d58864bSTony Lin * re-sample it by the following steps. 5550d58864bSTony Lin */ 5560d58864bSTony Lin data = readl(host->ioaddr + SDHCI_HOST_CONTROL); 55760bf6396SShawn Guo data &= ~ESDHC_CTRL_D3CD; 5580d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 55960bf6396SShawn Guo data |= ESDHC_CTRL_D3CD; 5600d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 5610d58864bSTony Lin } 562915be485SDong Aisheng 563915be485SDong Aisheng if (val & SDHCI_INT_ADMA_ERROR) { 564915be485SDong Aisheng val &= ~SDHCI_INT_ADMA_ERROR; 565915be485SDong Aisheng val |= ESDHC_INT_VENDOR_SPEC_DMA_ERR; 566915be485SDong Aisheng } 5670d58864bSTony Lin } 5680d58864bSTony Lin 569f47c4bbfSShawn Guo if (unlikely((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 57058ac8177SRichard Zhu && (reg == SDHCI_INT_STATUS) 57158ac8177SRichard Zhu && (val & SDHCI_INT_DATA_END))) { 57258ac8177SRichard Zhu u32 v; 57360bf6396SShawn Guo v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 57460bf6396SShawn Guo v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK; 57560bf6396SShawn Guo writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); 576361b8482SLucas Stach 577361b8482SLucas Stach if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS) 578361b8482SLucas Stach { 579361b8482SLucas Stach /* send a manual CMD12 with RESPTYP=none */ 580361b8482SLucas Stach data = MMC_STOP_TRANSMISSION << 24 | 581361b8482SLucas Stach SDHCI_CMD_ABORTCMD << 16; 582361b8482SLucas Stach writel(data, host->ioaddr + SDHCI_TRANSFER_MODE); 583361b8482SLucas Stach imx_data->multiblock_status = WAIT_FOR_INT; 584361b8482SLucas Stach } 58558ac8177SRichard Zhu } 58658ac8177SRichard Zhu 5877e29c306SWolfram Sang writel(val, host->ioaddr + reg); 5887e29c306SWolfram Sang } 5897e29c306SWolfram Sang 59095f25efeSWolfram Sang static u16 esdhc_readw_le(struct sdhci_host *host, int reg) 59195f25efeSWolfram Sang { 592ef4d0888SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 593070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 5940322191eSDong Aisheng u16 ret = 0; 5950322191eSDong Aisheng u32 val; 596ef4d0888SShawn Guo 59795a2482aSShawn Guo if (unlikely(reg == SDHCI_HOST_VERSION)) { 598ef4d0888SShawn Guo reg ^= 2; 5999d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 60095a2482aSShawn Guo /* 601ef4d0888SShawn Guo * The usdhc register returns a wrong host version. 602ef4d0888SShawn Guo * Correct it here. 60395a2482aSShawn Guo */ 604ef4d0888SShawn Guo return SDHCI_SPEC_300; 605ef4d0888SShawn Guo } 60695a2482aSShawn Guo } 60795f25efeSWolfram Sang 6080322191eSDong Aisheng if (unlikely(reg == SDHCI_HOST_CONTROL2)) { 6090322191eSDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6100322191eSDong Aisheng if (val & ESDHC_VENDOR_SPEC_VSELECT) 6110322191eSDong Aisheng ret |= SDHCI_CTRL_VDD_180; 6120322191eSDong Aisheng 6139d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 6146e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) 6150322191eSDong Aisheng val = readl(host->ioaddr + ESDHC_MIX_CTRL); 6166e9fd28eSDong Aisheng else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) 6176e9fd28eSDong Aisheng /* the std tuning bits is in ACMD12_ERR for imx6sl */ 618869f8a69SAdrian Hunter val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6196e9fd28eSDong Aisheng } 6206e9fd28eSDong Aisheng 6210322191eSDong Aisheng if (val & ESDHC_MIX_CTRL_EXE_TUNE) 6220322191eSDong Aisheng ret |= SDHCI_CTRL_EXEC_TUNING; 6230322191eSDong Aisheng if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) 6240322191eSDong Aisheng ret |= SDHCI_CTRL_TUNED_CLK; 6250322191eSDong Aisheng 6260322191eSDong Aisheng ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; 6270322191eSDong Aisheng 6280322191eSDong Aisheng return ret; 6290322191eSDong Aisheng } 6300322191eSDong Aisheng 6317dd109efSDong Aisheng if (unlikely(reg == SDHCI_TRANSFER_MODE)) { 6327dd109efSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 6337dd109efSDong Aisheng u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 6347dd109efSDong Aisheng ret = m & ESDHC_MIX_CTRL_SDHCI_MASK; 6357dd109efSDong Aisheng /* Swap AC23 bit */ 6367dd109efSDong Aisheng if (m & ESDHC_MIX_CTRL_AC23EN) { 6377dd109efSDong Aisheng ret &= ~ESDHC_MIX_CTRL_AC23EN; 6387dd109efSDong Aisheng ret |= SDHCI_TRNS_AUTO_CMD23; 6397dd109efSDong Aisheng } 6407dd109efSDong Aisheng } else { 6417dd109efSDong Aisheng ret = readw(host->ioaddr + SDHCI_TRANSFER_MODE); 6427dd109efSDong Aisheng } 6437dd109efSDong Aisheng 6447dd109efSDong Aisheng return ret; 6457dd109efSDong Aisheng } 6467dd109efSDong Aisheng 64795f25efeSWolfram Sang return readw(host->ioaddr + reg); 64895f25efeSWolfram Sang } 64995f25efeSWolfram Sang 65095f25efeSWolfram Sang static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) 65195f25efeSWolfram Sang { 65295f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 653070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 6540322191eSDong Aisheng u32 new_val = 0; 65595f25efeSWolfram Sang 65695f25efeSWolfram Sang switch (reg) { 6570322191eSDong Aisheng case SDHCI_CLOCK_CONTROL: 6580322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6590322191eSDong Aisheng if (val & SDHCI_CLOCK_CARD_EN) 6600322191eSDong Aisheng new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 6610322191eSDong Aisheng else 6620322191eSDong Aisheng new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 6630322191eSDong Aisheng writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); 664f581e909SHaibo Chen if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON)) 665f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 6660322191eSDong Aisheng return; 6670322191eSDong Aisheng case SDHCI_HOST_CONTROL2: 6680322191eSDong Aisheng new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 6690322191eSDong Aisheng if (val & SDHCI_CTRL_VDD_180) 6700322191eSDong Aisheng new_val |= ESDHC_VENDOR_SPEC_VSELECT; 6710322191eSDong Aisheng else 6720322191eSDong Aisheng new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; 6730322191eSDong Aisheng writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); 674a0dbbdc2SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 675869f8a69SAdrian Hunter u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6766e9fd28eSDong Aisheng u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 6778b2bb0adSDong Aisheng if (val & SDHCI_CTRL_TUNED_CLK) { 6788b2bb0adSDong Aisheng v |= ESDHC_MIX_CTRL_SMPCLK_SEL; 6796e9fd28eSDong Aisheng } else { 6808b2bb0adSDong Aisheng v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 6816e9fd28eSDong Aisheng m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; 6820b330e38SDong Aisheng m &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN; 6836e9fd28eSDong Aisheng } 6846e9fd28eSDong Aisheng 6858b2bb0adSDong Aisheng if (val & SDHCI_CTRL_EXEC_TUNING) { 6868b2bb0adSDong Aisheng v |= ESDHC_MIX_CTRL_EXE_TUNE; 6878b2bb0adSDong Aisheng m |= ESDHC_MIX_CTRL_FBCLK_SEL; 6880b330e38SDong Aisheng m |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; 68945334ee1SHaibo Chen usdhc_auto_tuning_mode_sel(host); 6908b2bb0adSDong Aisheng } else { 6918b2bb0adSDong Aisheng v &= ~ESDHC_MIX_CTRL_EXE_TUNE; 6928b2bb0adSDong Aisheng } 6936e9fd28eSDong Aisheng 694869f8a69SAdrian Hunter writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 6956e9fd28eSDong Aisheng writel(m, host->ioaddr + ESDHC_MIX_CTRL); 6966e9fd28eSDong Aisheng } 6970322191eSDong Aisheng return; 69895f25efeSWolfram Sang case SDHCI_TRANSFER_MODE: 699f47c4bbfSShawn Guo if ((imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 70058ac8177SRichard Zhu && (host->cmd->opcode == SD_IO_RW_EXTENDED) 70158ac8177SRichard Zhu && (host->cmd->data->blocks > 1) 70258ac8177SRichard Zhu && (host->cmd->data->flags & MMC_DATA_READ)) { 70358ac8177SRichard Zhu u32 v; 70460bf6396SShawn Guo v = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 70560bf6396SShawn Guo v |= ESDHC_VENDOR_SPEC_SDIO_QUIRK; 70660bf6396SShawn Guo writel(v, host->ioaddr + ESDHC_VENDOR_SPEC); 70758ac8177SRichard Zhu } 70869f54698SShawn Guo 7099d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 7103fbd4322SAndrew Gabbasov u32 wml; 71169f54698SShawn Guo u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); 7122a15f981SShawn Guo /* Swap AC23 bit */ 7132a15f981SShawn Guo if (val & SDHCI_TRNS_AUTO_CMD23) { 7142a15f981SShawn Guo val &= ~SDHCI_TRNS_AUTO_CMD23; 7152a15f981SShawn Guo val |= ESDHC_MIX_CTRL_AC23EN; 7162a15f981SShawn Guo } 7172a15f981SShawn Guo m = val | (m & ~ESDHC_MIX_CTRL_SDHCI_MASK); 71869f54698SShawn Guo writel(m, host->ioaddr + ESDHC_MIX_CTRL); 7193fbd4322SAndrew Gabbasov 7203fbd4322SAndrew Gabbasov /* Set watermark levels for PIO access to maximum value 7213fbd4322SAndrew Gabbasov * (128 words) to accommodate full 512 bytes buffer. 7223fbd4322SAndrew Gabbasov * For DMA access restore the levels to default value. 7233fbd4322SAndrew Gabbasov */ 7243fbd4322SAndrew Gabbasov m = readl(host->ioaddr + ESDHC_WTMK_LVL); 725e534b82fSHaibo Chen if (val & SDHCI_TRNS_DMA) { 7263fbd4322SAndrew Gabbasov wml = ESDHC_WTMK_LVL_WML_VAL_DEF; 727e534b82fSHaibo Chen } else { 728e534b82fSHaibo Chen u8 ctrl; 7293fbd4322SAndrew Gabbasov wml = ESDHC_WTMK_LVL_WML_VAL_MAX; 730e534b82fSHaibo Chen 731e534b82fSHaibo Chen /* 732e534b82fSHaibo Chen * Since already disable DMA mode, so also need 733e534b82fSHaibo Chen * to clear the DMASEL. Otherwise, for standard 734e534b82fSHaibo Chen * tuning, when send tuning command, usdhc will 735e534b82fSHaibo Chen * still prefetch the ADMA script from wrong 736e534b82fSHaibo Chen * DMA address, then we will see IOMMU report 737e534b82fSHaibo Chen * some error which show lack of TLB mapping. 738e534b82fSHaibo Chen */ 739e534b82fSHaibo Chen ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 740e534b82fSHaibo Chen ctrl &= ~SDHCI_CTRL_DMA_MASK; 741e534b82fSHaibo Chen sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 742e534b82fSHaibo Chen } 7433fbd4322SAndrew Gabbasov m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK | 7443fbd4322SAndrew Gabbasov ESDHC_WTMK_LVL_WR_WML_MASK); 7453fbd4322SAndrew Gabbasov m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) | 7463fbd4322SAndrew Gabbasov (wml << ESDHC_WTMK_LVL_WR_WML_SHIFT); 7473fbd4322SAndrew Gabbasov writel(m, host->ioaddr + ESDHC_WTMK_LVL); 74869f54698SShawn Guo } else { 74969f54698SShawn Guo /* 75069f54698SShawn Guo * Postpone this write, we must do it together with a 75169f54698SShawn Guo * command write that is down below. 75269f54698SShawn Guo */ 753e149860dSRichard Zhu imx_data->scratchpad = val; 75469f54698SShawn Guo } 75595f25efeSWolfram Sang return; 75695f25efeSWolfram Sang case SDHCI_COMMAND: 757361b8482SLucas Stach if (host->cmd->opcode == MMC_STOP_TRANSMISSION) 75858ac8177SRichard Zhu val |= SDHCI_CMD_ABORTCMD; 75995a2482aSShawn Guo 760361b8482SLucas Stach if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) && 761f47c4bbfSShawn Guo (imx_data->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) 762361b8482SLucas Stach imx_data->multiblock_status = MULTIBLK_IN_PROCESS; 763361b8482SLucas Stach 7649d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) 76595a2482aSShawn Guo writel(val << 16, 76695a2482aSShawn Guo host->ioaddr + SDHCI_TRANSFER_MODE); 76769f54698SShawn Guo else 768e149860dSRichard Zhu writel(val << 16 | imx_data->scratchpad, 76995f25efeSWolfram Sang host->ioaddr + SDHCI_TRANSFER_MODE); 77095f25efeSWolfram Sang return; 77195f25efeSWolfram Sang case SDHCI_BLOCK_SIZE: 77295f25efeSWolfram Sang val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 77395f25efeSWolfram Sang break; 77495f25efeSWolfram Sang } 77595f25efeSWolfram Sang esdhc_clrset_le(host, 0xffff, val, reg); 77695f25efeSWolfram Sang } 77795f25efeSWolfram Sang 77877da3da0SAaron Brice static u8 esdhc_readb_le(struct sdhci_host *host, int reg) 77977da3da0SAaron Brice { 78077da3da0SAaron Brice u8 ret; 78177da3da0SAaron Brice u32 val; 78277da3da0SAaron Brice 78377da3da0SAaron Brice switch (reg) { 78477da3da0SAaron Brice case SDHCI_HOST_CONTROL: 78577da3da0SAaron Brice val = readl(host->ioaddr + reg); 78677da3da0SAaron Brice 78777da3da0SAaron Brice ret = val & SDHCI_CTRL_LED; 78877da3da0SAaron Brice ret |= (val >> 5) & SDHCI_CTRL_DMA_MASK; 78977da3da0SAaron Brice ret |= (val & ESDHC_CTRL_4BITBUS); 79077da3da0SAaron Brice ret |= (val & ESDHC_CTRL_8BITBUS) << 3; 79177da3da0SAaron Brice return ret; 79277da3da0SAaron Brice } 79377da3da0SAaron Brice 79477da3da0SAaron Brice return readb(host->ioaddr + reg); 79577da3da0SAaron Brice } 79677da3da0SAaron Brice 79795f25efeSWolfram Sang static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) 79895f25efeSWolfram Sang { 7999a0985b7SWilson Callan struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 800070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 80181a0a8bcSBenoît Thébaudeau u32 new_val = 0; 802af51079eSSascha Hauer u32 mask; 80395f25efeSWolfram Sang 80495f25efeSWolfram Sang switch (reg) { 80595f25efeSWolfram Sang case SDHCI_POWER_CONTROL: 80695f25efeSWolfram Sang /* 80795f25efeSWolfram Sang * FSL put some DMA bits here 80895f25efeSWolfram Sang * If your board has a regulator, code should be here 80995f25efeSWolfram Sang */ 81095f25efeSWolfram Sang return; 81195f25efeSWolfram Sang case SDHCI_HOST_CONTROL: 8126b40d182SShawn Guo /* FSL messed up here, so we need to manually compose it. */ 813af51079eSSascha Hauer new_val = val & SDHCI_CTRL_LED; 8147122bbb0SMasanari Iida /* ensure the endianness */ 81595f25efeSWolfram Sang new_val |= ESDHC_HOST_CONTROL_LE; 8169a0985b7SWilson Callan /* bits 8&9 are reserved on mx25 */ 8179a0985b7SWilson Callan if (!is_imx25_esdhc(imx_data)) { 81895f25efeSWolfram Sang /* DMA mode bits are shifted */ 81995f25efeSWolfram Sang new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 8209a0985b7SWilson Callan } 82195f25efeSWolfram Sang 822af51079eSSascha Hauer /* 823af51079eSSascha Hauer * Do not touch buswidth bits here. This is done in 824af51079eSSascha Hauer * esdhc_pltfm_bus_width. 825f6825748SMartin Fuzzey * Do not touch the D3CD bit either which is used for the 826d04f8d5bSBenoît Thébaudeau * SDIO interrupt erratum workaround. 827af51079eSSascha Hauer */ 828f6825748SMartin Fuzzey mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD); 829af51079eSSascha Hauer 830af51079eSSascha Hauer esdhc_clrset_le(host, mask, new_val, reg); 83195f25efeSWolfram Sang return; 83281a0a8bcSBenoît Thébaudeau case SDHCI_SOFTWARE_RESET: 83381a0a8bcSBenoît Thébaudeau if (val & SDHCI_RESET_DATA) 83481a0a8bcSBenoît Thébaudeau new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL); 83581a0a8bcSBenoît Thébaudeau break; 83695f25efeSWolfram Sang } 83795f25efeSWolfram Sang esdhc_clrset_le(host, 0xff, val, reg); 838913413c3SShawn Guo 83981a0a8bcSBenoît Thébaudeau if (reg == SDHCI_SOFTWARE_RESET) { 84081a0a8bcSBenoît Thébaudeau if (val & SDHCI_RESET_ALL) { 841913413c3SShawn Guo /* 84281a0a8bcSBenoît Thébaudeau * The esdhc has a design violation to SDHC spec which 84381a0a8bcSBenoît Thébaudeau * tells that software reset should not affect card 84481a0a8bcSBenoît Thébaudeau * detection circuit. But esdhc clears its SYSCTL 84581a0a8bcSBenoît Thébaudeau * register bits [0..2] during the software reset. This 84681a0a8bcSBenoît Thébaudeau * will stop those clocks that card detection circuit 84781a0a8bcSBenoît Thébaudeau * relies on. To work around it, we turn the clocks on 84881a0a8bcSBenoît Thébaudeau * back to keep card detection circuit functional. 849913413c3SShawn Guo */ 850913413c3SShawn Guo esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); 85158c8c4fbSShawn Guo /* 85258c8c4fbSShawn Guo * The reset on usdhc fails to clear MIX_CTRL register. 85358c8c4fbSShawn Guo * Do it manually here. 85458c8c4fbSShawn Guo */ 855de5bdbffSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 85681a0a8bcSBenoît Thébaudeau /* 85781a0a8bcSBenoît Thébaudeau * the tuning bits should be kept during reset 85881a0a8bcSBenoît Thébaudeau */ 859d131a71cSDong Aisheng new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); 860d131a71cSDong Aisheng writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK, 861d131a71cSDong Aisheng host->ioaddr + ESDHC_MIX_CTRL); 862de5bdbffSDong Aisheng imx_data->is_ddr = 0; 863de5bdbffSDong Aisheng } 86481a0a8bcSBenoît Thébaudeau } else if (val & SDHCI_RESET_DATA) { 86581a0a8bcSBenoît Thébaudeau /* 86681a0a8bcSBenoît Thébaudeau * The eSDHC DAT line software reset clears at least the 86781a0a8bcSBenoît Thébaudeau * data transfer width on i.MX25, so make sure that the 86881a0a8bcSBenoît Thébaudeau * Host Control register is unaffected. 86981a0a8bcSBenoît Thébaudeau */ 87081a0a8bcSBenoît Thébaudeau esdhc_clrset_le(host, 0xff, new_val, 87181a0a8bcSBenoît Thébaudeau SDHCI_HOST_CONTROL); 87281a0a8bcSBenoît Thébaudeau } 87358c8c4fbSShawn Guo } 87495f25efeSWolfram Sang } 87595f25efeSWolfram Sang 8760ddf03c9SLucas Stach static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) 8770ddf03c9SLucas Stach { 8780ddf03c9SLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 8790ddf03c9SLucas Stach 880a974862fSDong Aisheng return pltfm_host->clock; 8810ddf03c9SLucas Stach } 8820ddf03c9SLucas Stach 88395f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) 88495f25efeSWolfram Sang { 88595f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 88695f25efeSWolfram Sang 887a974862fSDong Aisheng return pltfm_host->clock / 256 / 16; 88895f25efeSWolfram Sang } 88995f25efeSWolfram Sang 8908ba9580aSLucas Stach static inline void esdhc_pltfm_set_clock(struct sdhci_host *host, 8918ba9580aSLucas Stach unsigned int clock) 8928ba9580aSLucas Stach { 8938ba9580aSLucas Stach struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 894070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 895a974862fSDong Aisheng unsigned int host_clock = pltfm_host->clock; 8965143c953SBenoît Thébaudeau int ddr_pre_div = imx_data->is_ddr ? 2 : 1; 8975143c953SBenoît Thébaudeau int pre_div = 1; 898d31fc00aSDong Aisheng int div = 1; 899f581e909SHaibo Chen int ret; 900fed2f6e2SDong Aisheng u32 temp, val; 9018ba9580aSLucas Stach 9029d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 903fed2f6e2SDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 904fed2f6e2SDong Aisheng writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 905fed2f6e2SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 906f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 907fed2f6e2SDong Aisheng } 90873e736f8SStefan Agner 90973e736f8SStefan Agner if (clock == 0) { 91073e736f8SStefan Agner host->mmc->actual_clock = 0; 911373073efSRussell King return; 912fed2f6e2SDong Aisheng } 913d31fc00aSDong Aisheng 914499ed50fSBenoît Thébaudeau /* For i.MX53 eSDHCv3, SYSCTL.SDCLKFS may not be set to 0. */ 915499ed50fSBenoît Thébaudeau if (is_imx53_esdhc(imx_data)) { 916499ed50fSBenoît Thébaudeau /* 917499ed50fSBenoît Thébaudeau * According to the i.MX53 reference manual, if DLLCTRL[10] can 918499ed50fSBenoît Thébaudeau * be set, then the controller is eSDHCv3, else it is eSDHCv2. 919499ed50fSBenoît Thébaudeau */ 920499ed50fSBenoît Thébaudeau val = readl(host->ioaddr + ESDHC_DLL_CTRL); 921499ed50fSBenoît Thébaudeau writel(val | BIT(10), host->ioaddr + ESDHC_DLL_CTRL); 922499ed50fSBenoît Thébaudeau temp = readl(host->ioaddr + ESDHC_DLL_CTRL); 923499ed50fSBenoît Thébaudeau writel(val, host->ioaddr + ESDHC_DLL_CTRL); 924499ed50fSBenoît Thébaudeau if (temp & BIT(10)) 925499ed50fSBenoît Thébaudeau pre_div = 2; 926499ed50fSBenoît Thébaudeau } 927499ed50fSBenoît Thébaudeau 928d31fc00aSDong Aisheng temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 929d31fc00aSDong Aisheng temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 930d31fc00aSDong Aisheng | ESDHC_CLOCK_MASK); 931d31fc00aSDong Aisheng sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 932d31fc00aSDong Aisheng 933af6a50d4SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) { 934af6a50d4SBOUGH CHEN unsigned int max_clock; 935af6a50d4SBOUGH CHEN 936af6a50d4SBOUGH CHEN max_clock = imx_data->is_ddr ? 45000000 : 150000000; 937af6a50d4SBOUGH CHEN 938af6a50d4SBOUGH CHEN clock = min(clock, max_clock); 939af6a50d4SBOUGH CHEN } 940af6a50d4SBOUGH CHEN 9415143c953SBenoît Thébaudeau while (host_clock / (16 * pre_div * ddr_pre_div) > clock && 9425143c953SBenoît Thébaudeau pre_div < 256) 943d31fc00aSDong Aisheng pre_div *= 2; 944d31fc00aSDong Aisheng 9455143c953SBenoît Thébaudeau while (host_clock / (div * pre_div * ddr_pre_div) > clock && div < 16) 946d31fc00aSDong Aisheng div++; 947d31fc00aSDong Aisheng 9485143c953SBenoît Thébaudeau host->mmc->actual_clock = host_clock / (div * pre_div * ddr_pre_div); 949d31fc00aSDong Aisheng dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n", 950e76b8559SDong Aisheng clock, host->mmc->actual_clock); 951d31fc00aSDong Aisheng 952d31fc00aSDong Aisheng pre_div >>= 1; 953d31fc00aSDong Aisheng div--; 954d31fc00aSDong Aisheng 955d31fc00aSDong Aisheng temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); 956d31fc00aSDong Aisheng temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN 957d31fc00aSDong Aisheng | (div << ESDHC_DIVIDER_SHIFT) 958d31fc00aSDong Aisheng | (pre_div << ESDHC_PREDIV_SHIFT)); 959d31fc00aSDong Aisheng sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); 960fed2f6e2SDong Aisheng 961f581e909SHaibo Chen /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */ 962f581e909SHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp, 963f581e909SHaibo Chen (temp & ESDHC_CLOCK_STABLE), 2, 100); 964f581e909SHaibo Chen if (ret == -ETIMEDOUT) 965f581e909SHaibo Chen dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n"); 966f581e909SHaibo Chen 9679d61c009SShawn Guo if (esdhc_is_usdhc(imx_data)) { 968fed2f6e2SDong Aisheng val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); 969fed2f6e2SDong Aisheng writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 970fed2f6e2SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 971fed2f6e2SDong Aisheng } 972fed2f6e2SDong Aisheng 9738ba9580aSLucas Stach } 9748ba9580aSLucas Stach 975913413c3SShawn Guo static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) 976913413c3SShawn Guo { 977842afc02SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 978070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 979842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 980913413c3SShawn Guo 981913413c3SShawn Guo switch (boarddata->wp_type) { 982913413c3SShawn Guo case ESDHC_WP_GPIO: 983fbe5fdd1SShawn Guo return mmc_gpio_get_ro(host->mmc); 984913413c3SShawn Guo case ESDHC_WP_CONTROLLER: 985913413c3SShawn Guo return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 986913413c3SShawn Guo SDHCI_WRITE_PROTECT); 987913413c3SShawn Guo case ESDHC_WP_NONE: 988913413c3SShawn Guo break; 989913413c3SShawn Guo } 990913413c3SShawn Guo 991913413c3SShawn Guo return -ENOSYS; 992913413c3SShawn Guo } 993913413c3SShawn Guo 9942317f56cSRussell King static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) 995af51079eSSascha Hauer { 996af51079eSSascha Hauer u32 ctrl; 997af51079eSSascha Hauer 998af51079eSSascha Hauer switch (width) { 999af51079eSSascha Hauer case MMC_BUS_WIDTH_8: 1000af51079eSSascha Hauer ctrl = ESDHC_CTRL_8BITBUS; 1001af51079eSSascha Hauer break; 1002af51079eSSascha Hauer case MMC_BUS_WIDTH_4: 1003af51079eSSascha Hauer ctrl = ESDHC_CTRL_4BITBUS; 1004af51079eSSascha Hauer break; 1005af51079eSSascha Hauer default: 1006af51079eSSascha Hauer ctrl = 0; 1007af51079eSSascha Hauer break; 1008af51079eSSascha Hauer } 1009af51079eSSascha Hauer 1010af51079eSSascha Hauer esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl, 1011af51079eSSascha Hauer SDHCI_HOST_CONTROL); 1012af51079eSSascha Hauer } 1013af51079eSSascha Hauer 1014de3e1dd0SBOUGH CHEN static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) 1015de3e1dd0SBOUGH CHEN { 1016de3e1dd0SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 1017de3e1dd0SBOUGH CHEN 1018de3e1dd0SBOUGH CHEN /* 1019de3e1dd0SBOUGH CHEN * i.MX uSDHC internally already uses a fixed optimized timing for 1020de3e1dd0SBOUGH CHEN * DDR50, normally does not require tuning for DDR50 mode. 1021de3e1dd0SBOUGH CHEN */ 1022de3e1dd0SBOUGH CHEN if (host->timing == MMC_TIMING_UHS_DDR50) 1023de3e1dd0SBOUGH CHEN return 0; 1024de3e1dd0SBOUGH CHEN 1025de3e1dd0SBOUGH CHEN return sdhci_execute_tuning(mmc, opcode); 1026de3e1dd0SBOUGH CHEN } 1027de3e1dd0SBOUGH CHEN 10280322191eSDong Aisheng static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) 10290322191eSDong Aisheng { 10300322191eSDong Aisheng u32 reg; 10310ac4f496SHaibo Chen u8 sw_rst; 10320ac4f496SHaibo Chen int ret; 10330322191eSDong Aisheng 10340322191eSDong Aisheng /* FIXME: delay a bit for card to be ready for next tuning due to errors */ 10350322191eSDong Aisheng mdelay(1); 10360322191eSDong Aisheng 10370ac4f496SHaibo Chen /* IC suggest to reset USDHC before every tuning command */ 10380ac4f496SHaibo Chen esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET); 10390ac4f496SHaibo Chen ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst, 10400ac4f496SHaibo Chen !(sw_rst & SDHCI_RESET_ALL), 10, 100); 10410ac4f496SHaibo Chen if (ret == -ETIMEDOUT) 10420ac4f496SHaibo Chen dev_warn(mmc_dev(host->mmc), 10430ac4f496SHaibo Chen "warning! RESET_ALL never complete before sending tuning command\n"); 10440ac4f496SHaibo Chen 10450322191eSDong Aisheng reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 10460322191eSDong Aisheng reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | 10470322191eSDong Aisheng ESDHC_MIX_CTRL_FBCLK_SEL; 10480322191eSDong Aisheng writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 10490322191eSDong Aisheng writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 10500322191eSDong Aisheng dev_dbg(mmc_dev(host->mmc), 1051d04f8d5bSBenoît Thébaudeau "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", 10520322191eSDong Aisheng val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); 10530322191eSDong Aisheng } 10540322191eSDong Aisheng 10550322191eSDong Aisheng static void esdhc_post_tuning(struct sdhci_host *host) 10560322191eSDong Aisheng { 10570322191eSDong Aisheng u32 reg; 10580322191eSDong Aisheng 105945334ee1SHaibo Chen usdhc_auto_tuning_mode_sel(host); 106045334ee1SHaibo Chen 10610322191eSDong Aisheng reg = readl(host->ioaddr + ESDHC_MIX_CTRL); 10620322191eSDong Aisheng reg &= ~ESDHC_MIX_CTRL_EXE_TUNE; 1063da0295ffSDong Aisheng reg |= ESDHC_MIX_CTRL_AUTO_TUNE_EN; 10640322191eSDong Aisheng writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 10650322191eSDong Aisheng } 10660322191eSDong Aisheng 10670322191eSDong Aisheng static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) 10680322191eSDong Aisheng { 10690322191eSDong Aisheng int min, max, avg, ret; 10700322191eSDong Aisheng 10710322191eSDong Aisheng /* find the mininum delay first which can pass tuning */ 10720322191eSDong Aisheng min = ESDHC_TUNE_CTRL_MIN; 10730322191eSDong Aisheng while (min < ESDHC_TUNE_CTRL_MAX) { 10740322191eSDong Aisheng esdhc_prepare_tuning(host, min); 10759979dbe5SChaotian Jing if (!mmc_send_tuning(host->mmc, opcode, NULL)) 10760322191eSDong Aisheng break; 10770322191eSDong Aisheng min += ESDHC_TUNE_CTRL_STEP; 10780322191eSDong Aisheng } 10790322191eSDong Aisheng 10800322191eSDong Aisheng /* find the maxinum delay which can not pass tuning */ 10810322191eSDong Aisheng max = min + ESDHC_TUNE_CTRL_STEP; 10820322191eSDong Aisheng while (max < ESDHC_TUNE_CTRL_MAX) { 10830322191eSDong Aisheng esdhc_prepare_tuning(host, max); 10849979dbe5SChaotian Jing if (mmc_send_tuning(host->mmc, opcode, NULL)) { 10850322191eSDong Aisheng max -= ESDHC_TUNE_CTRL_STEP; 10860322191eSDong Aisheng break; 10870322191eSDong Aisheng } 10880322191eSDong Aisheng max += ESDHC_TUNE_CTRL_STEP; 10890322191eSDong Aisheng } 10900322191eSDong Aisheng 10910322191eSDong Aisheng /* use average delay to get the best timing */ 10920322191eSDong Aisheng avg = (min + max) / 2; 10930322191eSDong Aisheng esdhc_prepare_tuning(host, avg); 10949979dbe5SChaotian Jing ret = mmc_send_tuning(host->mmc, opcode, NULL); 10950322191eSDong Aisheng esdhc_post_tuning(host); 10960322191eSDong Aisheng 1097d04f8d5bSBenoît Thébaudeau dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n", 10980322191eSDong Aisheng ret ? "failed" : "passed", avg, ret); 10990322191eSDong Aisheng 11000322191eSDong Aisheng return ret; 11010322191eSDong Aisheng } 11020322191eSDong Aisheng 1103029e2476SBOUGH CHEN static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) 1104029e2476SBOUGH CHEN { 1105029e2476SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 1106029e2476SBOUGH CHEN u32 m; 1107029e2476SBOUGH CHEN 1108029e2476SBOUGH CHEN m = readl(host->ioaddr + ESDHC_MIX_CTRL); 1109029e2476SBOUGH CHEN if (ios->enhanced_strobe) 1110029e2476SBOUGH CHEN m |= ESDHC_MIX_CTRL_HS400_ES_EN; 1111029e2476SBOUGH CHEN else 1112029e2476SBOUGH CHEN m &= ~ESDHC_MIX_CTRL_HS400_ES_EN; 1113029e2476SBOUGH CHEN writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1114029e2476SBOUGH CHEN } 1115029e2476SBOUGH CHEN 1116ad93220dSDong Aisheng static int esdhc_change_pinstate(struct sdhci_host *host, 1117ad93220dSDong Aisheng unsigned int uhs) 1118ad93220dSDong Aisheng { 1119ad93220dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1120070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1121ad93220dSDong Aisheng struct pinctrl_state *pinctrl; 1122ad93220dSDong Aisheng 1123ad93220dSDong Aisheng dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs); 1124ad93220dSDong Aisheng 1125ad93220dSDong Aisheng if (IS_ERR(imx_data->pinctrl) || 1126ad93220dSDong Aisheng IS_ERR(imx_data->pins_100mhz) || 1127ad93220dSDong Aisheng IS_ERR(imx_data->pins_200mhz)) 1128ad93220dSDong Aisheng return -EINVAL; 1129ad93220dSDong Aisheng 1130ad93220dSDong Aisheng switch (uhs) { 1131ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR50: 11329f327845SHaibo Chen case MMC_TIMING_UHS_DDR50: 1133ad93220dSDong Aisheng pinctrl = imx_data->pins_100mhz; 1134ad93220dSDong Aisheng break; 1135ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR104: 1136429a5b45SDong Aisheng case MMC_TIMING_MMC_HS200: 113728b07674SHaibo Chen case MMC_TIMING_MMC_HS400: 1138ad93220dSDong Aisheng pinctrl = imx_data->pins_200mhz; 1139ad93220dSDong Aisheng break; 1140ad93220dSDong Aisheng default: 1141ad93220dSDong Aisheng /* back to default state for other legacy timing */ 11422480b720SUlf Hansson return pinctrl_select_default_state(mmc_dev(host->mmc)); 1143ad93220dSDong Aisheng } 1144ad93220dSDong Aisheng 1145ad93220dSDong Aisheng return pinctrl_select_state(imx_data->pinctrl, pinctrl); 1146ad93220dSDong Aisheng } 1147ad93220dSDong Aisheng 114828b07674SHaibo Chen /* 1149d04f8d5bSBenoît Thébaudeau * For HS400 eMMC, there is a data_strobe line. This signal is generated 115028b07674SHaibo Chen * by the device and used for data output and CRC status response output 115128b07674SHaibo Chen * in HS400 mode. The frequency of this signal follows the frequency of 1152d04f8d5bSBenoît Thébaudeau * CLK generated by host. The host receives the data which is aligned to the 115328b07674SHaibo Chen * edge of data_strobe line. Due to the time delay between CLK line and 115428b07674SHaibo Chen * data_strobe line, if the delay time is larger than one clock cycle, 1155d04f8d5bSBenoît Thébaudeau * then CLK and data_strobe line will be misaligned, read error shows up. 115628b07674SHaibo Chen */ 115728b07674SHaibo Chen static void esdhc_set_strobe_dll(struct sdhci_host *host) 115828b07674SHaibo Chen { 11595bd2acdcSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 11605bd2acdcSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 11615bd2acdcSHaibo Chen u32 strobe_delay; 116228b07674SHaibo Chen u32 v; 1163373e800bSHaibo Chen int ret; 116428b07674SHaibo Chen 11657ac6da26SDong Aisheng /* disable clock before enabling strobe dll */ 11667ac6da26SDong Aisheng writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & 11677ac6da26SDong Aisheng ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, 11687ac6da26SDong Aisheng host->ioaddr + ESDHC_VENDOR_SPEC); 1169f581e909SHaibo Chen esdhc_wait_for_card_clock_gate_off(host); 11707ac6da26SDong Aisheng 117128b07674SHaibo Chen /* force a reset on strobe dll */ 117228b07674SHaibo Chen writel(ESDHC_STROBE_DLL_CTRL_RESET, 117328b07674SHaibo Chen host->ioaddr + ESDHC_STROBE_DLL_CTRL); 11742eaf5a53SBOUGH CHEN /* clear the reset bit on strobe dll before any setting */ 11752eaf5a53SBOUGH CHEN writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL); 11762eaf5a53SBOUGH CHEN 117728b07674SHaibo Chen /* 117828b07674SHaibo Chen * enable strobe dll ctrl and adjust the delay target 117928b07674SHaibo Chen * for the uSDHC loopback read clock 118028b07674SHaibo Chen */ 11815bd2acdcSHaibo Chen if (imx_data->boarddata.strobe_dll_delay_target) 11825bd2acdcSHaibo Chen strobe_delay = imx_data->boarddata.strobe_dll_delay_target; 11835bd2acdcSHaibo Chen else 11845bd2acdcSHaibo Chen strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT; 118528b07674SHaibo Chen v = ESDHC_STROBE_DLL_CTRL_ENABLE | 11862eaf5a53SBOUGH CHEN ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT | 11875bd2acdcSHaibo Chen (strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); 118828b07674SHaibo Chen writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); 1189373e800bSHaibo Chen 1190373e800bSHaibo Chen /* wait max 50us to get the REF/SLV lock */ 1191373e800bSHaibo Chen ret = readl_poll_timeout(host->ioaddr + ESDHC_STROBE_DLL_STATUS, v, 1192373e800bSHaibo Chen ((v & ESDHC_STROBE_DLL_STS_REF_LOCK) && (v & ESDHC_STROBE_DLL_STS_SLV_LOCK)), 1, 50); 1193373e800bSHaibo Chen if (ret == -ETIMEDOUT) 119428b07674SHaibo Chen dev_warn(mmc_dev(host->mmc), 1195373e800bSHaibo Chen "warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v); 119628b07674SHaibo Chen } 119728b07674SHaibo Chen 1198d9370424SHaibo Chen static void esdhc_reset_tuning(struct sdhci_host *host) 1199d9370424SHaibo Chen { 1200d9370424SHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1201d9370424SHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1202d9370424SHaibo Chen u32 ctrl; 12039af372dcSHaibo Chen int ret; 1204d9370424SHaibo Chen 1205d04f8d5bSBenoît Thébaudeau /* Reset the tuning circuit */ 1206d9370424SHaibo Chen if (esdhc_is_usdhc(imx_data)) { 1207d9370424SHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 1208d9370424SHaibo Chen ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL); 1209d9370424SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 1210d9370424SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL; 1211d9370424SHaibo Chen writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); 1212d9370424SHaibo Chen writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 1213d9370424SHaibo Chen } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 1214869f8a69SAdrian Hunter ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1215d9370424SHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; 12169af372dcSHaibo Chen ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; 1217869f8a69SAdrian Hunter writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 12189af372dcSHaibo Chen /* Make sure ESDHC_MIX_CTRL_EXE_TUNE cleared */ 12199af372dcSHaibo Chen ret = readl_poll_timeout(host->ioaddr + SDHCI_AUTO_CMD_STATUS, 12209af372dcSHaibo Chen ctrl, !(ctrl & ESDHC_MIX_CTRL_EXE_TUNE), 1, 50); 12219af372dcSHaibo Chen if (ret == -ETIMEDOUT) 12229af372dcSHaibo Chen dev_warn(mmc_dev(host->mmc), 12239af372dcSHaibo Chen "Warning! clear execute tuning bit failed\n"); 12249af372dcSHaibo Chen /* 12259af372dcSHaibo Chen * SDHCI_INT_DATA_AVAIL is W1C bit, set this bit will clear the 12269af372dcSHaibo Chen * usdhc IP internal logic flag execute_tuning_with_clr_buf, which 12279af372dcSHaibo Chen * will finally make sure the normal data transfer logic correct. 12289af372dcSHaibo Chen */ 12299af372dcSHaibo Chen ctrl = readl(host->ioaddr + SDHCI_INT_STATUS); 12309af372dcSHaibo Chen ctrl |= SDHCI_INT_DATA_AVAIL; 12319af372dcSHaibo Chen writel(ctrl, host->ioaddr + SDHCI_INT_STATUS); 1232d9370424SHaibo Chen } 1233d9370424SHaibo Chen } 1234d9370424SHaibo Chen } 1235d9370424SHaibo Chen 1236850a29b8SRussell King static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) 1237ad93220dSDong Aisheng { 123828b07674SHaibo Chen u32 m; 1239ad93220dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1240070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1241602519b2SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1242ad93220dSDong Aisheng 124328b07674SHaibo Chen /* disable ddr mode and disable HS400 mode */ 124428b07674SHaibo Chen m = readl(host->ioaddr + ESDHC_MIX_CTRL); 124528b07674SHaibo Chen m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN); 124628b07674SHaibo Chen imx_data->is_ddr = 0; 124728b07674SHaibo Chen 1248850a29b8SRussell King switch (timing) { 1249ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR12: 1250ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR25: 1251ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR50: 1252ad93220dSDong Aisheng case MMC_TIMING_UHS_SDR104: 1253de0a0decSBOUGH CHEN case MMC_TIMING_MMC_HS: 1254429a5b45SDong Aisheng case MMC_TIMING_MMC_HS200: 125528b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1256ad93220dSDong Aisheng break; 1257ad93220dSDong Aisheng case MMC_TIMING_UHS_DDR50: 125869f5bf38SAisheng Dong case MMC_TIMING_MMC_DDR52: 125928b07674SHaibo Chen m |= ESDHC_MIX_CTRL_DDREN; 126028b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 1261de5bdbffSDong Aisheng imx_data->is_ddr = 1; 1262602519b2SDong Aisheng if (boarddata->delay_line) { 1263602519b2SDong Aisheng u32 v; 1264602519b2SDong Aisheng v = boarddata->delay_line << 1265602519b2SDong Aisheng ESDHC_DLL_OVERRIDE_VAL_SHIFT | 1266602519b2SDong Aisheng (1 << ESDHC_DLL_OVERRIDE_EN_SHIFT); 1267602519b2SDong Aisheng if (is_imx53_esdhc(imx_data)) 1268602519b2SDong Aisheng v <<= 1; 1269602519b2SDong Aisheng writel(v, host->ioaddr + ESDHC_DLL_CTRL); 1270602519b2SDong Aisheng } 1271ad93220dSDong Aisheng break; 127228b07674SHaibo Chen case MMC_TIMING_MMC_HS400: 127328b07674SHaibo Chen m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN; 127428b07674SHaibo Chen writel(m, host->ioaddr + ESDHC_MIX_CTRL); 127528b07674SHaibo Chen imx_data->is_ddr = 1; 12767ac6da26SDong Aisheng /* update clock after enable DDR for strobe DLL lock */ 12777ac6da26SDong Aisheng host->ops->set_clock(host, host->clock); 127828b07674SHaibo Chen esdhc_set_strobe_dll(host); 127928b07674SHaibo Chen break; 1280d9370424SHaibo Chen case MMC_TIMING_LEGACY: 1281d9370424SHaibo Chen default: 1282d9370424SHaibo Chen esdhc_reset_tuning(host); 1283d9370424SHaibo Chen break; 1284ad93220dSDong Aisheng } 1285ad93220dSDong Aisheng 1286850a29b8SRussell King esdhc_change_pinstate(host, timing); 1287ad93220dSDong Aisheng } 1288ad93220dSDong Aisheng 12890718e59aSRussell King static void esdhc_reset(struct sdhci_host *host, u8 mask) 12900718e59aSRussell King { 12910718e59aSRussell King sdhci_reset(host, mask); 12920718e59aSRussell King 12930718e59aSRussell King sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); 12940718e59aSRussell King sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); 12950718e59aSRussell King } 12960718e59aSRussell King 129710fd0ad9SAisheng Dong static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) 129810fd0ad9SAisheng Dong { 129910fd0ad9SAisheng Dong struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1300070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 130110fd0ad9SAisheng Dong 1302d04f8d5bSBenoît Thébaudeau /* Doc Erratum: the uSDHC actual maximum timeout count is 1 << 29 */ 13032fb0b02bSHaibo Chen return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27; 130410fd0ad9SAisheng Dong } 130510fd0ad9SAisheng Dong 1306e33eb8e2SAisheng Dong static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) 1307e33eb8e2SAisheng Dong { 1308e33eb8e2SAisheng Dong struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1309070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1310e33eb8e2SAisheng Dong 1311e33eb8e2SAisheng Dong /* use maximum timeout counter */ 1312a215186dSHaibo Chen esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK, 1313a215186dSHaibo Chen esdhc_is_usdhc(imx_data) ? 0xF : 0xE, 1314e33eb8e2SAisheng Dong SDHCI_TIMEOUT_CONTROL); 1315e33eb8e2SAisheng Dong } 1316e33eb8e2SAisheng Dong 1317bb6e3581SBOUGH CHEN static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) 1318bb6e3581SBOUGH CHEN { 1319bb6e3581SBOUGH CHEN int cmd_error = 0; 1320bb6e3581SBOUGH CHEN int data_error = 0; 1321bb6e3581SBOUGH CHEN 1322bb6e3581SBOUGH CHEN if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 1323bb6e3581SBOUGH CHEN return intmask; 1324bb6e3581SBOUGH CHEN 1325bb6e3581SBOUGH CHEN cqhci_irq(host->mmc, intmask, cmd_error, data_error); 1326bb6e3581SBOUGH CHEN 1327bb6e3581SBOUGH CHEN return 0; 1328bb6e3581SBOUGH CHEN } 1329bb6e3581SBOUGH CHEN 13306e9fd28eSDong Aisheng static struct sdhci_ops sdhci_esdhc_ops = { 1331e149860dSRichard Zhu .read_l = esdhc_readl_le, 13320c6d49ceSWolfram Sang .read_w = esdhc_readw_le, 133377da3da0SAaron Brice .read_b = esdhc_readb_le, 1334e149860dSRichard Zhu .write_l = esdhc_writel_le, 13350c6d49ceSWolfram Sang .write_w = esdhc_writew_le, 13360c6d49ceSWolfram Sang .write_b = esdhc_writeb_le, 13378ba9580aSLucas Stach .set_clock = esdhc_pltfm_set_clock, 13380ddf03c9SLucas Stach .get_max_clock = esdhc_pltfm_get_max_clock, 13390c6d49ceSWolfram Sang .get_min_clock = esdhc_pltfm_get_min_clock, 134010fd0ad9SAisheng Dong .get_max_timeout_count = esdhc_get_max_timeout_count, 1341913413c3SShawn Guo .get_ro = esdhc_pltfm_get_ro, 1342e33eb8e2SAisheng Dong .set_timeout = esdhc_set_timeout, 13432317f56cSRussell King .set_bus_width = esdhc_pltfm_set_bus_width, 1344ad93220dSDong Aisheng .set_uhs_signaling = esdhc_set_uhs_signaling, 13450718e59aSRussell King .reset = esdhc_reset, 1346bb6e3581SBOUGH CHEN .irq = esdhc_cqhci_irq, 13473722c74cSHaibo Chen .dump_vendor_regs = esdhc_dump_debug_regs, 13480c6d49ceSWolfram Sang }; 13490c6d49ceSWolfram Sang 13501db5eebfSLars-Peter Clausen static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 135197e4ba6aSRichard Zhu .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT 135297e4ba6aSRichard Zhu | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC 135397e4ba6aSRichard Zhu | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC 135485d6509dSShawn Guo | SDHCI_QUIRK_BROKEN_CARD_DETECTION, 135585d6509dSShawn Guo .ops = &sdhci_esdhc_ops, 135685d6509dSShawn Guo }; 135785d6509dSShawn Guo 1358f3f5cf3dSDong Aisheng static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) 1359f3f5cf3dSDong Aisheng { 1360f3f5cf3dSDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1361f3f5cf3dSDong Aisheng struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1362982cf37dSHaibo Chen struct cqhci_host *cq_host = host->mmc->cqe_private; 13632b16cf32SDong Aisheng int tmp; 1364f3f5cf3dSDong Aisheng 1365f3f5cf3dSDong Aisheng if (esdhc_is_usdhc(imx_data)) { 1366f3f5cf3dSDong Aisheng /* 1367f3f5cf3dSDong Aisheng * The imx6q ROM code will change the default watermark 1368f3f5cf3dSDong Aisheng * level setting to something insane. Change it back here. 1369f3f5cf3dSDong Aisheng */ 1370f3f5cf3dSDong Aisheng writel(ESDHC_WTMK_DEFAULT_VAL, host->ioaddr + ESDHC_WTMK_LVL); 1371f3f5cf3dSDong Aisheng 1372f3f5cf3dSDong Aisheng /* 1373f3f5cf3dSDong Aisheng * ROM code will change the bit burst_length_enable setting 1374d04f8d5bSBenoît Thébaudeau * to zero if this usdhc is chosen to boot system. Change 1375f3f5cf3dSDong Aisheng * it back here, otherwise it will impact the performance a 1376f3f5cf3dSDong Aisheng * lot. This bit is used to enable/disable the burst length 1377d04f8d5bSBenoît Thébaudeau * for the external AHB2AXI bridge. It's useful especially 1378f3f5cf3dSDong Aisheng * for INCR transfer because without burst length indicator, 1379f3f5cf3dSDong Aisheng * the AHB2AXI bridge does not know the burst length in 1380f3f5cf3dSDong Aisheng * advance. And without burst length indicator, AHB INCR 1381f3f5cf3dSDong Aisheng * transfer can only be converted to singles on the AXI side. 1382f3f5cf3dSDong Aisheng */ 1383f3f5cf3dSDong Aisheng writel(readl(host->ioaddr + SDHCI_HOST_CONTROL) 1384f3f5cf3dSDong Aisheng | ESDHC_BURST_LEN_EN_INCR, 1385f3f5cf3dSDong Aisheng host->ioaddr + SDHCI_HOST_CONTROL); 1386e30be063SBOUGH CHEN 1387f3f5cf3dSDong Aisheng /* 1388d04f8d5bSBenoît Thébaudeau * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL 1389f3f5cf3dSDong Aisheng * TO1.1, it's harmless for MX6SL 1390f3f5cf3dSDong Aisheng */ 13915c4f0062SChester Lin if (!(imx_data->socdata->flags & ESDHC_FLAG_SKIP_ERR004536)) { 1392e30be063SBOUGH CHEN writel(readl(host->ioaddr + 0x6c) & ~BIT(7), 1393f3f5cf3dSDong Aisheng host->ioaddr + 0x6c); 13945c4f0062SChester Lin } 1395f3f5cf3dSDong Aisheng 1396f3f5cf3dSDong Aisheng /* disable DLL_CTRL delay line settings */ 1397f3f5cf3dSDong Aisheng writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); 13982b16cf32SDong Aisheng 1399bcdb5301SBOUGH CHEN /* 1400bcdb5301SBOUGH CHEN * For the case of command with busy, if set the bit 1401bcdb5301SBOUGH CHEN * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a 1402bcdb5301SBOUGH CHEN * transfer complete interrupt when busy is deasserted. 1403bcdb5301SBOUGH CHEN * When CQHCI use DCMD to send a CMD need R1b respons, 1404bcdb5301SBOUGH CHEN * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ, 1405bcdb5301SBOUGH CHEN * otherwise DCMD will always meet timeout waiting for 1406bcdb5301SBOUGH CHEN * hardware interrupt issue. 1407bcdb5301SBOUGH CHEN */ 1408bcdb5301SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { 1409bcdb5301SBOUGH CHEN tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2); 1410bcdb5301SBOUGH CHEN tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ; 1411bcdb5301SBOUGH CHEN writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2); 1412bcdb5301SBOUGH CHEN 1413bcdb5301SBOUGH CHEN host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; 1414bcdb5301SBOUGH CHEN } 1415bcdb5301SBOUGH CHEN 14162b16cf32SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { 14172b16cf32SDong Aisheng tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); 14182b16cf32SDong Aisheng tmp |= ESDHC_STD_TUNING_EN | 14192b16cf32SDong Aisheng ESDHC_TUNING_START_TAP_DEFAULT; 14202b16cf32SDong Aisheng if (imx_data->boarddata.tuning_start_tap) { 14212b16cf32SDong Aisheng tmp &= ~ESDHC_TUNING_START_TAP_MASK; 14222b16cf32SDong Aisheng tmp |= imx_data->boarddata.tuning_start_tap; 14232b16cf32SDong Aisheng } 14242b16cf32SDong Aisheng 14252b16cf32SDong Aisheng if (imx_data->boarddata.tuning_step) { 14262b16cf32SDong Aisheng tmp &= ~ESDHC_TUNING_STEP_MASK; 14272b16cf32SDong Aisheng tmp |= imx_data->boarddata.tuning_step 14282b16cf32SDong Aisheng << ESDHC_TUNING_STEP_SHIFT; 14292b16cf32SDong Aisheng } 143016e40e5bSHaibo Chen 143116e40e5bSHaibo Chen /* Disable the CMD CRC check for tuning, if not, need to 143216e40e5bSHaibo Chen * add some delay after every tuning command, because 143316e40e5bSHaibo Chen * hardware standard tuning logic will directly go to next 143416e40e5bSHaibo Chen * step once it detect the CMD CRC error, will not wait for 143516e40e5bSHaibo Chen * the card side to finally send out the tuning data, trigger 143616e40e5bSHaibo Chen * the buffer read ready interrupt immediately. If usdhc send 143716e40e5bSHaibo Chen * the next tuning command some eMMC card will stuck, can't 143816e40e5bSHaibo Chen * response, block the tuning procedure or the first command 143916e40e5bSHaibo Chen * after the whole tuning procedure always can't get any response. 144016e40e5bSHaibo Chen */ 144116e40e5bSHaibo Chen tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; 14422b16cf32SDong Aisheng writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); 1443a98c557eSBOUGH CHEN } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { 1444a98c557eSBOUGH CHEN /* 1445a98c557eSBOUGH CHEN * ESDHC_STD_TUNING_EN may be configed in bootloader 1446a98c557eSBOUGH CHEN * or ROM code, so clear this bit here to make sure 1447a98c557eSBOUGH CHEN * the manual tuning can work. 1448a98c557eSBOUGH CHEN */ 1449a98c557eSBOUGH CHEN tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); 1450a98c557eSBOUGH CHEN tmp &= ~ESDHC_STD_TUNING_EN; 1451a98c557eSBOUGH CHEN writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); 14522b16cf32SDong Aisheng } 1453982cf37dSHaibo Chen 1454982cf37dSHaibo Chen /* 1455982cf37dSHaibo Chen * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card 1456982cf37dSHaibo Chen * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the 1457982cf37dSHaibo Chen * the 1st linux configure power/clock for the 2nd Linux. 1458982cf37dSHaibo Chen * 1459982cf37dSHaibo Chen * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux 1460982cf37dSHaibo Chen * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump. 1461982cf37dSHaibo Chen * After we clear the pending interrupt and halt CQCTL, issue gone. 1462982cf37dSHaibo Chen */ 1463982cf37dSHaibo Chen if (cq_host) { 1464982cf37dSHaibo Chen tmp = cqhci_readl(cq_host, CQHCI_IS); 1465982cf37dSHaibo Chen cqhci_writel(cq_host, tmp, CQHCI_IS); 1466982cf37dSHaibo Chen cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL); 1467982cf37dSHaibo Chen } 1468f3f5cf3dSDong Aisheng } 1469f3f5cf3dSDong Aisheng } 1470f3f5cf3dSDong Aisheng 1471bb6e3581SBOUGH CHEN static void esdhc_cqe_enable(struct mmc_host *mmc) 1472bb6e3581SBOUGH CHEN { 1473bb6e3581SBOUGH CHEN struct sdhci_host *host = mmc_priv(mmc); 147485236d2bSBOUGH CHEN struct cqhci_host *cq_host = mmc->cqe_private; 1475bb6e3581SBOUGH CHEN u32 reg; 1476bb6e3581SBOUGH CHEN u16 mode; 1477bb6e3581SBOUGH CHEN int count = 10; 1478bb6e3581SBOUGH CHEN 1479bb6e3581SBOUGH CHEN /* 1480bb6e3581SBOUGH CHEN * CQE gets stuck if it sees Buffer Read Enable bit set, which can be 1481bb6e3581SBOUGH CHEN * the case after tuning, so ensure the buffer is drained. 1482bb6e3581SBOUGH CHEN */ 1483bb6e3581SBOUGH CHEN reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 1484bb6e3581SBOUGH CHEN while (reg & SDHCI_DATA_AVAILABLE) { 1485bb6e3581SBOUGH CHEN sdhci_readl(host, SDHCI_BUFFER); 1486bb6e3581SBOUGH CHEN reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 1487bb6e3581SBOUGH CHEN if (count-- == 0) { 1488bb6e3581SBOUGH CHEN dev_warn(mmc_dev(host->mmc), 1489bb6e3581SBOUGH CHEN "CQE may get stuck because the Buffer Read Enable bit is set\n"); 1490bb6e3581SBOUGH CHEN break; 1491bb6e3581SBOUGH CHEN } 1492bb6e3581SBOUGH CHEN mdelay(1); 1493bb6e3581SBOUGH CHEN } 1494bb6e3581SBOUGH CHEN 1495bb6e3581SBOUGH CHEN /* 1496bb6e3581SBOUGH CHEN * Runtime resume will reset the entire host controller, which 1497bb6e3581SBOUGH CHEN * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL. 1498bb6e3581SBOUGH CHEN * Here set DMAEN and BCEN when enable CMDQ. 1499bb6e3581SBOUGH CHEN */ 1500bb6e3581SBOUGH CHEN mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); 1501bb6e3581SBOUGH CHEN if (host->flags & SDHCI_REQ_USE_DMA) 1502bb6e3581SBOUGH CHEN mode |= SDHCI_TRNS_DMA; 1503bb6e3581SBOUGH CHEN if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) 1504bb6e3581SBOUGH CHEN mode |= SDHCI_TRNS_BLK_CNT_EN; 1505bb6e3581SBOUGH CHEN sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); 1506bb6e3581SBOUGH CHEN 150785236d2bSBOUGH CHEN /* 150885236d2bSBOUGH CHEN * Though Runtime resume reset the entire host controller, 150985236d2bSBOUGH CHEN * but do not impact the CQHCI side, need to clear the 151085236d2bSBOUGH CHEN * HALT bit, avoid CQHCI stuck in the first request when 151185236d2bSBOUGH CHEN * system resume back. 151285236d2bSBOUGH CHEN */ 151385236d2bSBOUGH CHEN cqhci_writel(cq_host, 0, CQHCI_CTL); 151485236d2bSBOUGH CHEN if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT) 151585236d2bSBOUGH CHEN dev_err(mmc_dev(host->mmc), 151685236d2bSBOUGH CHEN "failed to exit halt state when enable CQE\n"); 151785236d2bSBOUGH CHEN 151885236d2bSBOUGH CHEN 1519bb6e3581SBOUGH CHEN sdhci_cqe_enable(mmc); 1520bb6e3581SBOUGH CHEN } 1521bb6e3581SBOUGH CHEN 1522bb6e3581SBOUGH CHEN static void esdhc_sdhci_dumpregs(struct mmc_host *mmc) 1523bb6e3581SBOUGH CHEN { 1524bb6e3581SBOUGH CHEN sdhci_dumpregs(mmc_priv(mmc)); 1525bb6e3581SBOUGH CHEN } 1526bb6e3581SBOUGH CHEN 1527bb6e3581SBOUGH CHEN static const struct cqhci_host_ops esdhc_cqhci_ops = { 1528bb6e3581SBOUGH CHEN .enable = esdhc_cqe_enable, 1529bb6e3581SBOUGH CHEN .disable = sdhci_cqe_disable, 1530bb6e3581SBOUGH CHEN .dumpregs = esdhc_sdhci_dumpregs, 1531bb6e3581SBOUGH CHEN }; 1532bb6e3581SBOUGH CHEN 1533c3be1efdSBill Pemberton static int 1534abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 153507bf2b54SSascha Hauer struct sdhci_host *host, 153691fa4252SDong Aisheng struct pltfm_imx_data *imx_data) 1537abfafc2dSShawn Guo { 1538abfafc2dSShawn Guo struct device_node *np = pdev->dev.of_node; 153991fa4252SDong Aisheng struct esdhc_platform_data *boarddata = &imx_data->boarddata; 15404800e87aSDong Aisheng int ret; 1541abfafc2dSShawn Guo 1542abfafc2dSShawn Guo if (of_get_property(np, "fsl,wp-controller", NULL)) 1543abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_CONTROLLER; 1544abfafc2dSShawn Guo 154574ff81e1SLinus Walleij /* 154674ff81e1SLinus Walleij * If we have this property, then activate WP check. 154774ff81e1SLinus Walleij * Retrieveing and requesting the actual WP GPIO will happen 154874ff81e1SLinus Walleij * in the call to mmc_of_parse(). 154974ff81e1SLinus Walleij */ 155074ff81e1SLinus Walleij if (of_property_read_bool(np, "wp-gpios")) 1551abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_GPIO; 1552abfafc2dSShawn Guo 1553d407e30bSHaibo Chen of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step); 1554d87fc966SDong Aisheng of_property_read_u32(np, "fsl,tuning-start-tap", 1555d87fc966SDong Aisheng &boarddata->tuning_start_tap); 1556d407e30bSHaibo Chen 15575bd2acdcSHaibo Chen of_property_read_u32(np, "fsl,strobe-dll-delay-target", 15585bd2acdcSHaibo Chen &boarddata->strobe_dll_delay_target); 1559ad93220dSDong Aisheng if (of_find_property(np, "no-1-8-v", NULL)) 156086f495c5SStefan Agner host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; 1561ad93220dSDong Aisheng 1562602519b2SDong Aisheng if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line)) 1563602519b2SDong Aisheng boarddata->delay_line = 0; 1564602519b2SDong Aisheng 15656dab809bSAndy Shevchenko mmc_of_parse_voltage(host->mmc, &host->ocr_mask); 156607bf2b54SSascha Hauer 1567f410ee0aSPeng Fan if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pinctrl)) { 156891fa4252SDong Aisheng imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl, 156991fa4252SDong Aisheng ESDHC_PINCTRL_STATE_100MHZ); 157091fa4252SDong Aisheng imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl, 157191fa4252SDong Aisheng ESDHC_PINCTRL_STATE_200MHZ); 157291fa4252SDong Aisheng } 157391fa4252SDong Aisheng 157415064119SFabio Estevam /* call to generic mmc_of_parse to support additional capabilities */ 15754800e87aSDong Aisheng ret = mmc_of_parse(host->mmc); 15764800e87aSDong Aisheng if (ret) 15774800e87aSDong Aisheng return ret; 15784800e87aSDong Aisheng 1579287980e4SArnd Bergmann if (mmc_gpio_get_cd(host->mmc) >= 0) 15804800e87aSDong Aisheng host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 15814800e87aSDong Aisheng 15824800e87aSDong Aisheng return 0; 1583abfafc2dSShawn Guo } 1584abfafc2dSShawn Guo 1585c3be1efdSBill Pemberton static int sdhci_esdhc_imx_probe(struct platform_device *pdev) 158695f25efeSWolfram Sang { 158785d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 158885d6509dSShawn Guo struct sdhci_host *host; 1589bb6e3581SBOUGH CHEN struct cqhci_host *cq_host; 15900c6d49ceSWolfram Sang int err; 1591e149860dSRichard Zhu struct pltfm_imx_data *imx_data; 159295f25efeSWolfram Sang 1593070e6d3fSJisheng Zhang host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 1594070e6d3fSJisheng Zhang sizeof(*imx_data)); 159585d6509dSShawn Guo if (IS_ERR(host)) 159685d6509dSShawn Guo return PTR_ERR(host); 159785d6509dSShawn Guo 159885d6509dSShawn Guo pltfm_host = sdhci_priv(host); 159985d6509dSShawn Guo 1600070e6d3fSJisheng Zhang imx_data = sdhci_pltfm_priv(pltfm_host); 160157ed3314SShawn Guo 160291b3d2e5SFabio Estevam imx_data->socdata = device_get_match_data(&pdev->dev); 160385d6509dSShawn Guo 16041c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1605d1b98305SRafael J. Wysocki cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 16061c4989b0SBOUGH CHEN 160752dac615SSascha Hauer imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 160852dac615SSascha Hauer if (IS_ERR(imx_data->clk_ipg)) { 160952dac615SSascha Hauer err = PTR_ERR(imx_data->clk_ipg); 1610e3af31c6SShawn Guo goto free_sdhci; 161195f25efeSWolfram Sang } 161252dac615SSascha Hauer 161352dac615SSascha Hauer imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); 161452dac615SSascha Hauer if (IS_ERR(imx_data->clk_ahb)) { 161552dac615SSascha Hauer err = PTR_ERR(imx_data->clk_ahb); 1616e3af31c6SShawn Guo goto free_sdhci; 161752dac615SSascha Hauer } 161852dac615SSascha Hauer 161952dac615SSascha Hauer imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); 162052dac615SSascha Hauer if (IS_ERR(imx_data->clk_per)) { 162152dac615SSascha Hauer err = PTR_ERR(imx_data->clk_per); 1622e3af31c6SShawn Guo goto free_sdhci; 162352dac615SSascha Hauer } 162452dac615SSascha Hauer 162552dac615SSascha Hauer pltfm_host->clk = imx_data->clk_per; 1626a974862fSDong Aisheng pltfm_host->clock = clk_get_rate(pltfm_host->clk); 162717b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_per); 162817b1eb7fSFabio Estevam if (err) 162917b1eb7fSFabio Estevam goto free_sdhci; 163017b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ipg); 163117b1eb7fSFabio Estevam if (err) 163217b1eb7fSFabio Estevam goto disable_per_clk; 163317b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ahb); 163417b1eb7fSFabio Estevam if (err) 163517b1eb7fSFabio Estevam goto disable_ipg_clk; 163695f25efeSWolfram Sang 1637ad93220dSDong Aisheng imx_data->pinctrl = devm_pinctrl_get(&pdev->dev); 16389e70ff99SHaibo Chen if (IS_ERR(imx_data->pinctrl)) 1639b62eee9fSHaibo Chen dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n"); 1640e62d8b8fSDong Aisheng 164169ed60e0SDong Aisheng if (esdhc_is_usdhc(imx_data)) { 164269ed60e0SDong Aisheng host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; 164309c8192bSStefan Agner host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR; 1644f6140462SHaibo Chen 1645f6140462SHaibo Chen /* GPIO CD can be set as a wakeup source */ 1646f6140462SHaibo Chen host->mmc->caps |= MMC_CAP_CD_WAKE; 1647f6140462SHaibo Chen 16484245afffSDong Aisheng if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) 16494245afffSDong Aisheng host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; 1650a75dcbf4SDong Aisheng 1651a75dcbf4SDong Aisheng /* clear tuning bits in case ROM has set it already */ 1652a75dcbf4SDong Aisheng writel(0x0, host->ioaddr + ESDHC_MIX_CTRL); 1653869f8a69SAdrian Hunter writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS); 1654a75dcbf4SDong Aisheng writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); 1655de3e1dd0SBOUGH CHEN 1656de3e1dd0SBOUGH CHEN /* 1657de3e1dd0SBOUGH CHEN * Link usdhc specific mmc_host_ops execute_tuning function, 1658de3e1dd0SBOUGH CHEN * to replace the standard one in sdhci_ops. 1659de3e1dd0SBOUGH CHEN */ 1660de3e1dd0SBOUGH CHEN host->mmc_host_ops.execute_tuning = usdhc_execute_tuning; 166169ed60e0SDong Aisheng } 1662f750ba9bSShawn Guo 1663*1ed5c3b2SSascha Hauer err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); 1664*1ed5c3b2SSascha Hauer if (err) 1665*1ed5c3b2SSascha Hauer goto disable_ahb_clk; 1666*1ed5c3b2SSascha Hauer 16676e9fd28eSDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) 16686e9fd28eSDong Aisheng sdhci_esdhc_ops.platform_execute_tuning = 16696e9fd28eSDong Aisheng esdhc_executing_tuning; 16708b2bb0adSDong Aisheng 167118094430SDong Aisheng if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) 167218094430SDong Aisheng host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; 167318094430SDong Aisheng 1674*1ed5c3b2SSascha Hauer if (host->caps & MMC_CAP_8_BIT_DATA && 1675*1ed5c3b2SSascha Hauer imx_data->socdata->flags & ESDHC_FLAG_HS400) 16762991ad76SLucas Stach host->mmc->caps2 |= MMC_CAP2_HS400; 167728b07674SHaibo Chen 167874898cbcSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23) 167974898cbcSHaibo Chen host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN; 168074898cbcSHaibo Chen 1681*1ed5c3b2SSascha Hauer if (host->caps & MMC_CAP_8_BIT_DATA && 1682*1ed5c3b2SSascha Hauer imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) { 1683029e2476SBOUGH CHEN host->mmc->caps2 |= MMC_CAP2_HS400_ES; 1684029e2476SBOUGH CHEN host->mmc_host_ops.hs400_enhanced_strobe = 1685029e2476SBOUGH CHEN esdhc_hs400_enhanced_strobe; 1686029e2476SBOUGH CHEN } 1687029e2476SBOUGH CHEN 1688bb6e3581SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { 1689bcdb5301SBOUGH CHEN host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; 1690bb6e3581SBOUGH CHEN cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL); 16919a633f3bSWei Yongjun if (!cq_host) { 16929a633f3bSWei Yongjun err = -ENOMEM; 1693bb6e3581SBOUGH CHEN goto disable_ahb_clk; 1694bb6e3581SBOUGH CHEN } 1695bb6e3581SBOUGH CHEN 1696bb6e3581SBOUGH CHEN cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET; 1697bb6e3581SBOUGH CHEN cq_host->ops = &esdhc_cqhci_ops; 1698bb6e3581SBOUGH CHEN 1699bb6e3581SBOUGH CHEN err = cqhci_init(cq_host, host->mmc, false); 1700bb6e3581SBOUGH CHEN if (err) 1701bb6e3581SBOUGH CHEN goto disable_ahb_clk; 1702bb6e3581SBOUGH CHEN } 1703bb6e3581SBOUGH CHEN 1704f3f5cf3dSDong Aisheng sdhci_esdhc_imx_hwinit(host); 1705f3f5cf3dSDong Aisheng 170685d6509dSShawn Guo err = sdhci_add_host(host); 170785d6509dSShawn Guo if (err) 170817b1eb7fSFabio Estevam goto disable_ahb_clk; 170985d6509dSShawn Guo 1710f62f7bccSHaibo Chen /* 1711f62f7bccSHaibo Chen * Setup the wakeup capability here, let user to decide 1712f62f7bccSHaibo Chen * whether need to enable this wakeup through sysfs interface. 1713f62f7bccSHaibo Chen */ 1714f62f7bccSHaibo Chen if ((host->mmc->pm_caps & MMC_PM_KEEP_POWER) && 1715f62f7bccSHaibo Chen (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ)) 1716f62f7bccSHaibo Chen device_set_wakeup_capable(&pdev->dev, true); 1717f62f7bccSHaibo Chen 171889d7e5c1SDong Aisheng pm_runtime_set_active(&pdev->dev); 171989d7e5c1SDong Aisheng pm_runtime_set_autosuspend_delay(&pdev->dev, 50); 172089d7e5c1SDong Aisheng pm_runtime_use_autosuspend(&pdev->dev); 172189d7e5c1SDong Aisheng pm_suspend_ignore_children(&pdev->dev, 1); 172277903c01SUlf Hansson pm_runtime_enable(&pdev->dev); 172389d7e5c1SDong Aisheng 17247e29c306SWolfram Sang return 0; 17257e29c306SWolfram Sang 172617b1eb7fSFabio Estevam disable_ahb_clk: 172752dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ahb); 172817b1eb7fSFabio Estevam disable_ipg_clk: 172917b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_ipg); 173017b1eb7fSFabio Estevam disable_per_clk: 173117b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_per); 1732e3af31c6SShawn Guo free_sdhci: 17331c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1734d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 173585d6509dSShawn Guo sdhci_pltfm_free(pdev); 173685d6509dSShawn Guo return err; 173795f25efeSWolfram Sang } 173895f25efeSWolfram Sang 17396e0ee714SBill Pemberton static int sdhci_esdhc_imx_remove(struct platform_device *pdev) 174095f25efeSWolfram Sang { 174185d6509dSShawn Guo struct sdhci_host *host = platform_get_drvdata(pdev); 174295f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1743070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1744a56f4413SFrank Li int dead; 174585d6509dSShawn Guo 17460b414368SUlf Hansson pm_runtime_get_sync(&pdev->dev); 1747a56f4413SFrank Li dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 17480b414368SUlf Hansson pm_runtime_disable(&pdev->dev); 17490b414368SUlf Hansson pm_runtime_put_noidle(&pdev->dev); 17500b414368SUlf Hansson 175185d6509dSShawn Guo sdhci_remove_host(host, dead); 17520c6d49ceSWolfram Sang 175352dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_per); 175452dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ipg); 175552dac615SSascha Hauer clk_disable_unprepare(imx_data->clk_ahb); 175652dac615SSascha Hauer 17571c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1758d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 17591c4989b0SBOUGH CHEN 176085d6509dSShawn Guo sdhci_pltfm_free(pdev); 176185d6509dSShawn Guo 176285d6509dSShawn Guo return 0; 176395f25efeSWolfram Sang } 176495f25efeSWolfram Sang 17652788ed42SUlf Hansson #ifdef CONFIG_PM_SLEEP 176604143fbaSDong Aisheng static int sdhci_esdhc_suspend(struct device *dev) 176704143fbaSDong Aisheng { 17683e3274abSUlf Hansson struct sdhci_host *host = dev_get_drvdata(dev); 1769a26a4f1bSHaibo Chen struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1770a26a4f1bSHaibo Chen struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 1771bb6e3581SBOUGH CHEN int ret; 1772bb6e3581SBOUGH CHEN 1773bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) { 1774bb6e3581SBOUGH CHEN ret = cqhci_suspend(host->mmc); 1775bb6e3581SBOUGH CHEN if (ret) 1776bb6e3581SBOUGH CHEN return ret; 1777bb6e3581SBOUGH CHEN } 17783e3274abSUlf Hansson 1779a26a4f1bSHaibo Chen if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) && 1780a26a4f1bSHaibo Chen (host->tuning_mode != SDHCI_TUNING_MODE_1)) { 1781a26a4f1bSHaibo Chen mmc_retune_timer_stop(host->mmc); 1782a26a4f1bSHaibo Chen mmc_retune_needed(host->mmc); 1783a26a4f1bSHaibo Chen } 1784a26a4f1bSHaibo Chen 1785d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 1786d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 1787d38dcad4SAdrian Hunter 1788af8fade4SHaibo Chen ret = sdhci_suspend_host(host); 1789f6140462SHaibo Chen if (ret) 1790f6140462SHaibo Chen return ret; 1791f6140462SHaibo Chen 1792f6140462SHaibo Chen ret = pinctrl_pm_select_sleep_state(dev); 1793f6140462SHaibo Chen if (ret) 1794f6140462SHaibo Chen return ret; 1795f6140462SHaibo Chen 1796f6140462SHaibo Chen ret = mmc_gpio_set_cd_wake(host->mmc, true); 1797af8fade4SHaibo Chen 1798af8fade4SHaibo Chen return ret; 179904143fbaSDong Aisheng } 180004143fbaSDong Aisheng 180104143fbaSDong Aisheng static int sdhci_esdhc_resume(struct device *dev) 180204143fbaSDong Aisheng { 1803cc17e129SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 1804bb6e3581SBOUGH CHEN int ret; 1805cc17e129SDong Aisheng 1806af8fade4SHaibo Chen ret = pinctrl_pm_select_default_state(dev); 1807af8fade4SHaibo Chen if (ret) 1808af8fade4SHaibo Chen return ret; 1809af8fade4SHaibo Chen 181019dbfdd3SDong Aisheng /* re-initialize hw state in case it's lost in low power mode */ 181119dbfdd3SDong Aisheng sdhci_esdhc_imx_hwinit(host); 1812cc17e129SDong Aisheng 1813bb6e3581SBOUGH CHEN ret = sdhci_resume_host(host); 1814bb6e3581SBOUGH CHEN if (ret) 1815bb6e3581SBOUGH CHEN return ret; 1816bb6e3581SBOUGH CHEN 1817bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) 1818bb6e3581SBOUGH CHEN ret = cqhci_resume(host->mmc); 1819bb6e3581SBOUGH CHEN 1820f6140462SHaibo Chen if (!ret) 1821f6140462SHaibo Chen ret = mmc_gpio_set_cd_wake(host->mmc, false); 1822f6140462SHaibo Chen 1823bb6e3581SBOUGH CHEN return ret; 182404143fbaSDong Aisheng } 18252788ed42SUlf Hansson #endif 182604143fbaSDong Aisheng 18272788ed42SUlf Hansson #ifdef CONFIG_PM 182889d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_suspend(struct device *dev) 182989d7e5c1SDong Aisheng { 183089d7e5c1SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 183189d7e5c1SDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1832070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 183389d7e5c1SDong Aisheng int ret; 183489d7e5c1SDong Aisheng 1835bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) { 1836bb6e3581SBOUGH CHEN ret = cqhci_suspend(host->mmc); 1837bb6e3581SBOUGH CHEN if (ret) 1838bb6e3581SBOUGH CHEN return ret; 1839bb6e3581SBOUGH CHEN } 1840bb6e3581SBOUGH CHEN 184189d7e5c1SDong Aisheng ret = sdhci_runtime_suspend_host(host); 1842371d39faSMichael Trimarchi if (ret) 1843371d39faSMichael Trimarchi return ret; 184489d7e5c1SDong Aisheng 1845d38dcad4SAdrian Hunter if (host->tuning_mode != SDHCI_TUNING_MODE_3) 1846d38dcad4SAdrian Hunter mmc_retune_needed(host->mmc); 1847d38dcad4SAdrian Hunter 18483602785bSMichael Trimarchi imx_data->actual_clock = host->mmc->actual_clock; 18493602785bSMichael Trimarchi esdhc_pltfm_set_clock(host, 0); 185089d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_per); 185189d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_ipg); 185289d7e5c1SDong Aisheng clk_disable_unprepare(imx_data->clk_ahb); 185389d7e5c1SDong Aisheng 18541c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1855d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 18561c4989b0SBOUGH CHEN 185789d7e5c1SDong Aisheng return ret; 185889d7e5c1SDong Aisheng } 185989d7e5c1SDong Aisheng 186089d7e5c1SDong Aisheng static int sdhci_esdhc_runtime_resume(struct device *dev) 186189d7e5c1SDong Aisheng { 186289d7e5c1SDong Aisheng struct sdhci_host *host = dev_get_drvdata(dev); 186389d7e5c1SDong Aisheng struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1864070e6d3fSJisheng Zhang struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); 186517b1eb7fSFabio Estevam int err; 186689d7e5c1SDong Aisheng 18671c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1868d1b98305SRafael J. Wysocki cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 18691c4989b0SBOUGH CHEN 18705c11f1ffSHaibo Chen if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME) 18715c11f1ffSHaibo Chen clk_set_rate(imx_data->clk_per, pltfm_host->clock); 18725c11f1ffSHaibo Chen 1873a0ad3087SMichael Trimarchi err = clk_prepare_enable(imx_data->clk_ahb); 1874a0ad3087SMichael Trimarchi if (err) 18751c4989b0SBOUGH CHEN goto remove_pm_qos_request; 1876a0ad3087SMichael Trimarchi 187717b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_per); 187817b1eb7fSFabio Estevam if (err) 1879a0ad3087SMichael Trimarchi goto disable_ahb_clk; 1880af5d2b7bSUlf Hansson 188117b1eb7fSFabio Estevam err = clk_prepare_enable(imx_data->clk_ipg); 188217b1eb7fSFabio Estevam if (err) 188317b1eb7fSFabio Estevam goto disable_per_clk; 1884af5d2b7bSUlf Hansson 18853602785bSMichael Trimarchi esdhc_pltfm_set_clock(host, imx_data->actual_clock); 1886a0ad3087SMichael Trimarchi 1887c6303c5dSBaolin Wang err = sdhci_runtime_resume_host(host, 0); 188817b1eb7fSFabio Estevam if (err) 1889a0ad3087SMichael Trimarchi goto disable_ipg_clk; 189089d7e5c1SDong Aisheng 1891bb6e3581SBOUGH CHEN if (host->mmc->caps2 & MMC_CAP2_CQE) 1892bb6e3581SBOUGH CHEN err = cqhci_resume(host->mmc); 1893bb6e3581SBOUGH CHEN 1894bb6e3581SBOUGH CHEN return err; 189517b1eb7fSFabio Estevam 189617b1eb7fSFabio Estevam disable_ipg_clk: 189717b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_ipg); 189817b1eb7fSFabio Estevam disable_per_clk: 189917b1eb7fSFabio Estevam clk_disable_unprepare(imx_data->clk_per); 1900a0ad3087SMichael Trimarchi disable_ahb_clk: 1901a0ad3087SMichael Trimarchi clk_disable_unprepare(imx_data->clk_ahb); 19021c4989b0SBOUGH CHEN remove_pm_qos_request: 19031c4989b0SBOUGH CHEN if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) 1904d1b98305SRafael J. Wysocki cpu_latency_qos_remove_request(&imx_data->pm_qos_req); 190517b1eb7fSFabio Estevam return err; 190689d7e5c1SDong Aisheng } 190789d7e5c1SDong Aisheng #endif 190889d7e5c1SDong Aisheng 190989d7e5c1SDong Aisheng static const struct dev_pm_ops sdhci_esdhc_pmops = { 191004143fbaSDong Aisheng SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume) 191189d7e5c1SDong Aisheng SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend, 191289d7e5c1SDong Aisheng sdhci_esdhc_runtime_resume, NULL) 191389d7e5c1SDong Aisheng }; 191489d7e5c1SDong Aisheng 191585d6509dSShawn Guo static struct platform_driver sdhci_esdhc_imx_driver = { 191685d6509dSShawn Guo .driver = { 191785d6509dSShawn Guo .name = "sdhci-esdhc-imx", 191821b2cec6SDouglas Anderson .probe_type = PROBE_PREFER_ASYNCHRONOUS, 1919abfafc2dSShawn Guo .of_match_table = imx_esdhc_dt_ids, 192089d7e5c1SDong Aisheng .pm = &sdhci_esdhc_pmops, 192185d6509dSShawn Guo }, 192285d6509dSShawn Guo .probe = sdhci_esdhc_imx_probe, 19230433c143SBill Pemberton .remove = sdhci_esdhc_imx_remove, 192495f25efeSWolfram Sang }; 192585d6509dSShawn Guo 1926d1f81a64SAxel Lin module_platform_driver(sdhci_esdhc_imx_driver); 192785d6509dSShawn Guo 192885d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); 1929035ff831SWolfram Sang MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>"); 193085d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 1931