| .. | .. |
|---|
| 8 | 8 | * Author: Wolfram Sang <kernel@pengutronix.de> |
|---|
| 9 | 9 | */ |
|---|
| 10 | 10 | |
|---|
| 11 | +#include <linux/bitfield.h> |
|---|
| 11 | 12 | #include <linux/io.h> |
|---|
| 13 | +#include <linux/iopoll.h> |
|---|
| 12 | 14 | #include <linux/delay.h> |
|---|
| 13 | 15 | #include <linux/err.h> |
|---|
| 14 | 16 | #include <linux/clk.h> |
|---|
| 15 | | -#include <linux/gpio.h> |
|---|
| 16 | 17 | #include <linux/module.h> |
|---|
| 17 | 18 | #include <linux/slab.h> |
|---|
| 19 | +#include <linux/pm_qos.h> |
|---|
| 18 | 20 | #include <linux/mmc/host.h> |
|---|
| 19 | 21 | #include <linux/mmc/mmc.h> |
|---|
| 20 | 22 | #include <linux/mmc/sdio.h> |
|---|
| 21 | 23 | #include <linux/mmc/slot-gpio.h> |
|---|
| 22 | 24 | #include <linux/of.h> |
|---|
| 23 | 25 | #include <linux/of_device.h> |
|---|
| 24 | | -#include <linux/of_gpio.h> |
|---|
| 25 | 26 | #include <linux/pinctrl/consumer.h> |
|---|
| 26 | 27 | #include <linux/platform_data/mmc-esdhc-imx.h> |
|---|
| 27 | 28 | #include <linux/pm_runtime.h> |
|---|
| 28 | | -#include <linux/iopoll.h> |
|---|
| 29 | +#include "sdhci-cqhci.h" |
|---|
| 29 | 30 | #include "sdhci-pltfm.h" |
|---|
| 30 | 31 | #include "sdhci-esdhc.h" |
|---|
| 32 | +#include "cqhci.h" |
|---|
| 31 | 33 | |
|---|
| 32 | 34 | #define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f |
|---|
| 33 | 35 | #define ESDHC_CTRL_D3CD 0x08 |
|---|
| .. | .. |
|---|
| 37 | 39 | #define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1) |
|---|
| 38 | 40 | #define ESDHC_VENDOR_SPEC_VSELECT (1 << 1) |
|---|
| 39 | 41 | #define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON (1 << 8) |
|---|
| 42 | +#define ESDHC_DEBUG_SEL_AND_STATUS_REG 0xc2 |
|---|
| 43 | +#define ESDHC_DEBUG_SEL_REG 0xc3 |
|---|
| 44 | +#define ESDHC_DEBUG_SEL_MASK 0xf |
|---|
| 45 | +#define ESDHC_DEBUG_SEL_CMD_STATE 1 |
|---|
| 46 | +#define ESDHC_DEBUG_SEL_DATA_STATE 2 |
|---|
| 47 | +#define ESDHC_DEBUG_SEL_TRANS_STATE 3 |
|---|
| 48 | +#define ESDHC_DEBUG_SEL_DMA_STATE 4 |
|---|
| 49 | +#define ESDHC_DEBUG_SEL_ADMA_STATE 5 |
|---|
| 50 | +#define ESDHC_DEBUG_SEL_FIFO_STATE 6 |
|---|
| 51 | +#define ESDHC_DEBUG_SEL_ASYNC_FIFO_STATE 7 |
|---|
| 40 | 52 | #define ESDHC_WTMK_LVL 0x44 |
|---|
| 41 | 53 | #define ESDHC_WTMK_DEFAULT_VAL 0x10401040 |
|---|
| 42 | 54 | #define ESDHC_WTMK_LVL_RD_WML_MASK 0x000000FF |
|---|
| .. | .. |
|---|
| 53 | 65 | #define ESDHC_MIX_CTRL_AUTO_TUNE_EN (1 << 24) |
|---|
| 54 | 66 | #define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25) |
|---|
| 55 | 67 | #define ESDHC_MIX_CTRL_HS400_EN (1 << 26) |
|---|
| 68 | +#define ESDHC_MIX_CTRL_HS400_ES_EN (1 << 27) |
|---|
| 56 | 69 | /* Bits 3 and 6 are not SDHCI standard definitions */ |
|---|
| 57 | 70 | #define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7 |
|---|
| 58 | 71 | /* Tuning bits */ |
|---|
| .. | .. |
|---|
| 73 | 86 | #define ESDHC_STROBE_DLL_CTRL 0x70 |
|---|
| 74 | 87 | #define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0) |
|---|
| 75 | 88 | #define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1) |
|---|
| 89 | +#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT 0x7 |
|---|
| 76 | 90 | #define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3 |
|---|
| 91 | +#define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT (4 << 20) |
|---|
| 77 | 92 | |
|---|
| 78 | 93 | #define ESDHC_STROBE_DLL_STATUS 0x74 |
|---|
| 79 | 94 | #define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1) |
|---|
| 80 | 95 | #define ESDHC_STROBE_DLL_STS_SLV_LOCK 0x1 |
|---|
| 96 | + |
|---|
| 97 | +#define ESDHC_VEND_SPEC2 0xc8 |
|---|
| 98 | +#define ESDHC_VEND_SPEC2_EN_BUSY_IRQ (1 << 8) |
|---|
| 81 | 99 | |
|---|
| 82 | 100 | #define ESDHC_TUNING_CTRL 0xcc |
|---|
| 83 | 101 | #define ESDHC_STD_TUNING_EN (1 << 24) |
|---|
| 84 | 102 | /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ |
|---|
| 85 | 103 | #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 |
|---|
| 86 | 104 | #define ESDHC_TUNING_START_TAP_MASK 0x7f |
|---|
| 105 | +#define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE (1 << 7) |
|---|
| 87 | 106 | #define ESDHC_TUNING_STEP_MASK 0x00070000 |
|---|
| 88 | 107 | #define ESDHC_TUNING_STEP_SHIFT 16 |
|---|
| 89 | 108 | |
|---|
| .. | .. |
|---|
| 105 | 124 | * Define this macro DMA error INT for fsl eSDHC |
|---|
| 106 | 125 | */ |
|---|
| 107 | 126 | #define ESDHC_INT_VENDOR_SPEC_DMA_ERR (1 << 28) |
|---|
| 127 | + |
|---|
| 128 | +/* the address offset of CQHCI */ |
|---|
| 129 | +#define ESDHC_CQHCI_ADDR_OFFSET 0x100 |
|---|
| 108 | 130 | |
|---|
| 109 | 131 | /* |
|---|
| 110 | 132 | * The CMDTYPE of the CMD register (offset 0xE) should be set to |
|---|
| .. | .. |
|---|
| 141 | 163 | #define ESDHC_FLAG_HS200 BIT(8) |
|---|
| 142 | 164 | /* The IP supports HS400 mode */ |
|---|
| 143 | 165 | #define ESDHC_FLAG_HS400 BIT(9) |
|---|
| 144 | | - |
|---|
| 145 | | -/* A clock frequency higher than this rate requires strobe dll control */ |
|---|
| 146 | | -#define ESDHC_STROBE_DLL_CLK_FREQ 100000000 |
|---|
| 166 | +/* |
|---|
| 167 | + * The IP has errata ERR010450 |
|---|
| 168 | + * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't |
|---|
| 169 | + * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz. |
|---|
| 170 | + */ |
|---|
| 171 | +#define ESDHC_FLAG_ERR010450 BIT(10) |
|---|
| 172 | +/* The IP supports HS400ES mode */ |
|---|
| 173 | +#define ESDHC_FLAG_HS400_ES BIT(11) |
|---|
| 174 | +/* The IP has Host Controller Interface for Command Queuing */ |
|---|
| 175 | +#define ESDHC_FLAG_CQHCI BIT(12) |
|---|
| 176 | +/* need request pmqos during low power */ |
|---|
| 177 | +#define ESDHC_FLAG_PMQOS BIT(13) |
|---|
| 178 | +/* The IP state got lost in low power mode */ |
|---|
| 179 | +#define ESDHC_FLAG_STATE_LOST_IN_LPMODE BIT(14) |
|---|
| 180 | +/* The IP lost clock rate in PM_RUNTIME */ |
|---|
| 181 | +#define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME BIT(15) |
|---|
| 182 | +/* |
|---|
| 183 | + * The IP do not support the ACMD23 feature completely when use ADMA mode. |
|---|
| 184 | + * In ADMA mode, it only use the 16 bit block count of the register 0x4 |
|---|
| 185 | + * (BLOCK_ATT) as the CMD23's argument for ACMD23 mode, which means it will |
|---|
| 186 | + * ignore the upper 16 bit of the CMD23's argument. This will block the reliable |
|---|
| 187 | + * write operation in RPMB, because RPMB reliable write need to set the bit31 |
|---|
| 188 | + * of the CMD23's argument. |
|---|
| 189 | + * imx6qpdl/imx6sx/imx6sl/imx7d has this limitation only for ADMA mode, SDMA |
|---|
| 190 | + * do not has this limitation. so when these SoC use ADMA mode, it need to |
|---|
| 191 | + * disable the ACMD23 feature. |
|---|
| 192 | + */ |
|---|
| 193 | +#define ESDHC_FLAG_BROKEN_AUTO_CMD23 BIT(16) |
|---|
| 147 | 194 | |
|---|
| 148 | 195 | struct esdhc_soc_data { |
|---|
| 149 | 196 | u32 flags; |
|---|
| 150 | 197 | }; |
|---|
| 151 | 198 | |
|---|
| 152 | | -static struct esdhc_soc_data esdhc_imx25_data = { |
|---|
| 199 | +static const struct esdhc_soc_data esdhc_imx25_data = { |
|---|
| 153 | 200 | .flags = ESDHC_FLAG_ERR004536, |
|---|
| 154 | 201 | }; |
|---|
| 155 | 202 | |
|---|
| 156 | | -static struct esdhc_soc_data esdhc_imx35_data = { |
|---|
| 203 | +static const struct esdhc_soc_data esdhc_imx35_data = { |
|---|
| 157 | 204 | .flags = ESDHC_FLAG_ERR004536, |
|---|
| 158 | 205 | }; |
|---|
| 159 | 206 | |
|---|
| 160 | | -static struct esdhc_soc_data esdhc_imx51_data = { |
|---|
| 207 | +static const struct esdhc_soc_data esdhc_imx51_data = { |
|---|
| 161 | 208 | .flags = 0, |
|---|
| 162 | 209 | }; |
|---|
| 163 | 210 | |
|---|
| 164 | | -static struct esdhc_soc_data esdhc_imx53_data = { |
|---|
| 211 | +static const struct esdhc_soc_data esdhc_imx53_data = { |
|---|
| 165 | 212 | .flags = ESDHC_FLAG_MULTIBLK_NO_INT, |
|---|
| 166 | 213 | }; |
|---|
| 167 | 214 | |
|---|
| 168 | | -static struct esdhc_soc_data usdhc_imx6q_data = { |
|---|
| 169 | | - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING, |
|---|
| 215 | +static const struct esdhc_soc_data usdhc_imx6q_data = { |
|---|
| 216 | + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING |
|---|
| 217 | + | ESDHC_FLAG_BROKEN_AUTO_CMD23, |
|---|
| 170 | 218 | }; |
|---|
| 171 | 219 | |
|---|
| 172 | | -static struct esdhc_soc_data usdhc_imx6sl_data = { |
|---|
| 220 | +static const struct esdhc_soc_data usdhc_imx6sl_data = { |
|---|
| 173 | 221 | .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 174 | 222 | | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 |
|---|
| 175 | | - | ESDHC_FLAG_HS200, |
|---|
| 223 | + | ESDHC_FLAG_HS200 |
|---|
| 224 | + | ESDHC_FLAG_BROKEN_AUTO_CMD23, |
|---|
| 176 | 225 | }; |
|---|
| 177 | 226 | |
|---|
| 178 | | -static struct esdhc_soc_data usdhc_imx6sx_data = { |
|---|
| 179 | | - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 180 | | - | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, |
|---|
| 181 | | -}; |
|---|
| 182 | | - |
|---|
| 183 | | -static struct esdhc_soc_data usdhc_imx7d_data = { |
|---|
| 227 | +static const struct esdhc_soc_data usdhc_imx6sll_data = { |
|---|
| 184 | 228 | .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 185 | 229 | | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
|---|
| 186 | | - | ESDHC_FLAG_HS400, |
|---|
| 230 | + | ESDHC_FLAG_HS400 |
|---|
| 231 | + | ESDHC_FLAG_STATE_LOST_IN_LPMODE, |
|---|
| 232 | +}; |
|---|
| 233 | + |
|---|
| 234 | +static const struct esdhc_soc_data usdhc_imx6sx_data = { |
|---|
| 235 | + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 236 | + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
|---|
| 237 | + | ESDHC_FLAG_STATE_LOST_IN_LPMODE |
|---|
| 238 | + | ESDHC_FLAG_BROKEN_AUTO_CMD23, |
|---|
| 239 | +}; |
|---|
| 240 | + |
|---|
| 241 | +static const struct esdhc_soc_data usdhc_imx6ull_data = { |
|---|
| 242 | + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 243 | + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
|---|
| 244 | + | ESDHC_FLAG_ERR010450 |
|---|
| 245 | + | ESDHC_FLAG_STATE_LOST_IN_LPMODE, |
|---|
| 246 | +}; |
|---|
| 247 | + |
|---|
| 248 | +static const struct esdhc_soc_data usdhc_imx7d_data = { |
|---|
| 249 | + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 250 | + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
|---|
| 251 | + | ESDHC_FLAG_HS400 |
|---|
| 252 | + | ESDHC_FLAG_STATE_LOST_IN_LPMODE |
|---|
| 253 | + | ESDHC_FLAG_BROKEN_AUTO_CMD23, |
|---|
| 254 | +}; |
|---|
| 255 | + |
|---|
| 256 | +static struct esdhc_soc_data usdhc_imx7ulp_data = { |
|---|
| 257 | + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 258 | + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
|---|
| 259 | + | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 |
|---|
| 260 | + | ESDHC_FLAG_STATE_LOST_IN_LPMODE, |
|---|
| 261 | +}; |
|---|
| 262 | + |
|---|
| 263 | +static struct esdhc_soc_data usdhc_imx8qxp_data = { |
|---|
| 264 | + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 265 | + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
|---|
| 266 | + | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES |
|---|
| 267 | + | ESDHC_FLAG_STATE_LOST_IN_LPMODE |
|---|
| 268 | + | ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME, |
|---|
| 269 | +}; |
|---|
| 270 | + |
|---|
| 271 | +static struct esdhc_soc_data usdhc_imx8mm_data = { |
|---|
| 272 | + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
|---|
| 273 | + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
|---|
| 274 | + | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES |
|---|
| 275 | + | ESDHC_FLAG_STATE_LOST_IN_LPMODE, |
|---|
| 187 | 276 | }; |
|---|
| 188 | 277 | |
|---|
| 189 | 278 | struct pltfm_imx_data { |
|---|
| 190 | 279 | u32 scratchpad; |
|---|
| 191 | 280 | struct pinctrl *pinctrl; |
|---|
| 192 | | - struct pinctrl_state *pins_default; |
|---|
| 193 | 281 | struct pinctrl_state *pins_100mhz; |
|---|
| 194 | 282 | struct pinctrl_state *pins_200mhz; |
|---|
| 195 | 283 | const struct esdhc_soc_data *socdata; |
|---|
| .. | .. |
|---|
| 204 | 292 | WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ |
|---|
| 205 | 293 | } multiblock_status; |
|---|
| 206 | 294 | u32 is_ddr; |
|---|
| 295 | + struct pm_qos_request pm_qos_req; |
|---|
| 207 | 296 | }; |
|---|
| 208 | | - |
|---|
| 209 | | -static const struct platform_device_id imx_esdhc_devtype[] = { |
|---|
| 210 | | - { |
|---|
| 211 | | - .name = "sdhci-esdhc-imx25", |
|---|
| 212 | | - .driver_data = (kernel_ulong_t) &esdhc_imx25_data, |
|---|
| 213 | | - }, { |
|---|
| 214 | | - .name = "sdhci-esdhc-imx35", |
|---|
| 215 | | - .driver_data = (kernel_ulong_t) &esdhc_imx35_data, |
|---|
| 216 | | - }, { |
|---|
| 217 | | - .name = "sdhci-esdhc-imx51", |
|---|
| 218 | | - .driver_data = (kernel_ulong_t) &esdhc_imx51_data, |
|---|
| 219 | | - }, { |
|---|
| 220 | | - /* sentinel */ |
|---|
| 221 | | - } |
|---|
| 222 | | -}; |
|---|
| 223 | | -MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); |
|---|
| 224 | 297 | |
|---|
| 225 | 298 | static const struct of_device_id imx_esdhc_dt_ids[] = { |
|---|
| 226 | 299 | { .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, }, |
|---|
| .. | .. |
|---|
| 229 | 302 | { .compatible = "fsl,imx53-esdhc", .data = &esdhc_imx53_data, }, |
|---|
| 230 | 303 | { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, }, |
|---|
| 231 | 304 | { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, |
|---|
| 305 | + { .compatible = "fsl,imx6sll-usdhc", .data = &usdhc_imx6sll_data, }, |
|---|
| 232 | 306 | { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, |
|---|
| 307 | + { .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, }, |
|---|
| 233 | 308 | { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, |
|---|
| 309 | + { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, |
|---|
| 310 | + { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, |
|---|
| 311 | + { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, |
|---|
| 234 | 312 | { /* sentinel */ } |
|---|
| 235 | 313 | }; |
|---|
| 236 | 314 | MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); |
|---|
| .. | .. |
|---|
| 261 | 339 | u32 shift = (reg & 0x3) * 8; |
|---|
| 262 | 340 | |
|---|
| 263 | 341 | writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); |
|---|
| 342 | +} |
|---|
| 343 | + |
|---|
| 344 | +#define DRIVER_NAME "sdhci-esdhc-imx" |
|---|
| 345 | +#define ESDHC_IMX_DUMP(f, x...) \ |
|---|
| 346 | + pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) |
|---|
| 347 | +static void esdhc_dump_debug_regs(struct sdhci_host *host) |
|---|
| 348 | +{ |
|---|
| 349 | + int i; |
|---|
| 350 | + char *debug_status[7] = { |
|---|
| 351 | + "cmd debug status", |
|---|
| 352 | + "data debug status", |
|---|
| 353 | + "trans debug status", |
|---|
| 354 | + "dma debug status", |
|---|
| 355 | + "adma debug status", |
|---|
| 356 | + "fifo debug status", |
|---|
| 357 | + "async fifo debug status" |
|---|
| 358 | + }; |
|---|
| 359 | + |
|---|
| 360 | + ESDHC_IMX_DUMP("========= ESDHC IMX DEBUG STATUS DUMP =========\n"); |
|---|
| 361 | + for (i = 0; i < 7; i++) { |
|---|
| 362 | + esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, |
|---|
| 363 | + ESDHC_DEBUG_SEL_CMD_STATE + i, ESDHC_DEBUG_SEL_REG); |
|---|
| 364 | + ESDHC_IMX_DUMP("%s: 0x%04x\n", debug_status[i], |
|---|
| 365 | + readw(host->ioaddr + ESDHC_DEBUG_SEL_AND_STATUS_REG)); |
|---|
| 366 | + } |
|---|
| 367 | + |
|---|
| 368 | + esdhc_clrset_le(host, ESDHC_DEBUG_SEL_MASK, 0, ESDHC_DEBUG_SEL_REG); |
|---|
| 369 | + |
|---|
| 370 | +} |
|---|
| 371 | + |
|---|
| 372 | +static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host) |
|---|
| 373 | +{ |
|---|
| 374 | + u32 present_state; |
|---|
| 375 | + int ret; |
|---|
| 376 | + |
|---|
| 377 | + ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state, |
|---|
| 378 | + (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100); |
|---|
| 379 | + if (ret == -ETIMEDOUT) |
|---|
| 380 | + dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__); |
|---|
| 264 | 381 | } |
|---|
| 265 | 382 | |
|---|
| 266 | 383 | static u32 esdhc_readl_le(struct sdhci_host *host, int reg) |
|---|
| .. | .. |
|---|
| 306 | 423 | val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 |
|---|
| 307 | 424 | | SDHCI_SUPPORT_SDR50 |
|---|
| 308 | 425 | | SDHCI_USE_SDR50_TUNING |
|---|
| 309 | | - | (SDHCI_TUNING_MODE_3 << SDHCI_RETUNING_MODE_SHIFT); |
|---|
| 426 | + | FIELD_PREP(SDHCI_RETUNING_MODE_MASK, |
|---|
| 427 | + SDHCI_TUNING_MODE_3); |
|---|
| 310 | 428 | |
|---|
| 311 | 429 | if (imx_data->socdata->flags & ESDHC_FLAG_HS400) |
|---|
| 312 | 430 | val |= SDHCI_SUPPORT_HS400; |
|---|
| .. | .. |
|---|
| 324 | 442 | |
|---|
| 325 | 443 | if (unlikely(reg == SDHCI_MAX_CURRENT) && esdhc_is_usdhc(imx_data)) { |
|---|
| 326 | 444 | val = 0; |
|---|
| 327 | | - val |= 0xFF << SDHCI_MAX_CURRENT_330_SHIFT; |
|---|
| 328 | | - val |= 0xFF << SDHCI_MAX_CURRENT_300_SHIFT; |
|---|
| 329 | | - val |= 0xFF << SDHCI_MAX_CURRENT_180_SHIFT; |
|---|
| 445 | + val |= FIELD_PREP(SDHCI_MAX_CURRENT_330_MASK, 0xFF); |
|---|
| 446 | + val |= FIELD_PREP(SDHCI_MAX_CURRENT_300_MASK, 0xFF); |
|---|
| 447 | + val |= FIELD_PREP(SDHCI_MAX_CURRENT_180_MASK, 0xFF); |
|---|
| 330 | 448 | } |
|---|
| 331 | 449 | |
|---|
| 332 | 450 | if (unlikely(reg == SDHCI_INT_STATUS)) { |
|---|
| .. | .. |
|---|
| 476 | 594 | else |
|---|
| 477 | 595 | new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; |
|---|
| 478 | 596 | writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); |
|---|
| 597 | + if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON)) |
|---|
| 598 | + esdhc_wait_for_card_clock_gate_off(host); |
|---|
| 479 | 599 | return; |
|---|
| 480 | 600 | case SDHCI_HOST_CONTROL2: |
|---|
| 481 | 601 | new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); |
|---|
| .. | .. |
|---|
| 544 | 664 | * For DMA access restore the levels to default value. |
|---|
| 545 | 665 | */ |
|---|
| 546 | 666 | m = readl(host->ioaddr + ESDHC_WTMK_LVL); |
|---|
| 547 | | - if (val & SDHCI_TRNS_DMA) |
|---|
| 667 | + if (val & SDHCI_TRNS_DMA) { |
|---|
| 548 | 668 | wml = ESDHC_WTMK_LVL_WML_VAL_DEF; |
|---|
| 549 | | - else |
|---|
| 669 | + } else { |
|---|
| 670 | + u8 ctrl; |
|---|
| 550 | 671 | wml = ESDHC_WTMK_LVL_WML_VAL_MAX; |
|---|
| 672 | + |
|---|
| 673 | + /* |
|---|
| 674 | + * Since already disable DMA mode, so also need |
|---|
| 675 | + * to clear the DMASEL. Otherwise, for standard |
|---|
| 676 | + * tuning, when send tuning command, usdhc will |
|---|
| 677 | + * still prefetch the ADMA script from wrong |
|---|
| 678 | + * DMA address, then we will see IOMMU report |
|---|
| 679 | + * some error which show lack of TLB mapping. |
|---|
| 680 | + */ |
|---|
| 681 | + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); |
|---|
| 682 | + ctrl &= ~SDHCI_CTRL_DMA_MASK; |
|---|
| 683 | + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); |
|---|
| 684 | + } |
|---|
| 551 | 685 | m &= ~(ESDHC_WTMK_LVL_RD_WML_MASK | |
|---|
| 552 | 686 | ESDHC_WTMK_LVL_WR_WML_MASK); |
|---|
| 553 | 687 | m |= (wml << ESDHC_WTMK_LVL_RD_WML_SHIFT) | |
|---|
| .. | .. |
|---|
| 704 | 838 | int ddr_pre_div = imx_data->is_ddr ? 2 : 1; |
|---|
| 705 | 839 | int pre_div = 1; |
|---|
| 706 | 840 | int div = 1; |
|---|
| 841 | + int ret; |
|---|
| 707 | 842 | u32 temp, val; |
|---|
| 708 | 843 | |
|---|
| 709 | 844 | if (esdhc_is_usdhc(imx_data)) { |
|---|
| 710 | 845 | val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); |
|---|
| 711 | 846 | writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, |
|---|
| 712 | 847 | host->ioaddr + ESDHC_VENDOR_SPEC); |
|---|
| 848 | + esdhc_wait_for_card_clock_gate_off(host); |
|---|
| 713 | 849 | } |
|---|
| 714 | 850 | |
|---|
| 715 | 851 | if (clock == 0) { |
|---|
| .. | .. |
|---|
| 736 | 872 | | ESDHC_CLOCK_MASK); |
|---|
| 737 | 873 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
|---|
| 738 | 874 | |
|---|
| 875 | + if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) { |
|---|
| 876 | + unsigned int max_clock; |
|---|
| 877 | + |
|---|
| 878 | + max_clock = imx_data->is_ddr ? 45000000 : 150000000; |
|---|
| 879 | + |
|---|
| 880 | + clock = min(clock, max_clock); |
|---|
| 881 | + } |
|---|
| 882 | + |
|---|
| 739 | 883 | while (host_clock / (16 * pre_div * ddr_pre_div) > clock && |
|---|
| 740 | 884 | pre_div < 256) |
|---|
| 741 | 885 | pre_div *= 2; |
|---|
| .. | .. |
|---|
| 756 | 900 | | (pre_div << ESDHC_PREDIV_SHIFT)); |
|---|
| 757 | 901 | sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); |
|---|
| 758 | 902 | |
|---|
| 903 | + /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */ |
|---|
| 904 | + ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp, |
|---|
| 905 | + (temp & ESDHC_CLOCK_STABLE), 2, 100); |
|---|
| 906 | + if (ret == -ETIMEDOUT) |
|---|
| 907 | + dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n"); |
|---|
| 908 | + |
|---|
| 759 | 909 | if (esdhc_is_usdhc(imx_data)) { |
|---|
| 760 | 910 | val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); |
|---|
| 761 | 911 | writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, |
|---|
| 762 | 912 | host->ioaddr + ESDHC_VENDOR_SPEC); |
|---|
| 763 | 913 | } |
|---|
| 764 | 914 | |
|---|
| 765 | | - mdelay(1); |
|---|
| 766 | 915 | } |
|---|
| 767 | 916 | |
|---|
| 768 | 917 | static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) |
|---|
| .. | .. |
|---|
| 804 | 953 | SDHCI_HOST_CONTROL); |
|---|
| 805 | 954 | } |
|---|
| 806 | 955 | |
|---|
| 956 | +static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) |
|---|
| 957 | +{ |
|---|
| 958 | + struct sdhci_host *host = mmc_priv(mmc); |
|---|
| 959 | + |
|---|
| 960 | + /* |
|---|
| 961 | + * i.MX uSDHC internally already uses a fixed optimized timing for |
|---|
| 962 | + * DDR50, normally does not require tuning for DDR50 mode. |
|---|
| 963 | + */ |
|---|
| 964 | + if (host->timing == MMC_TIMING_UHS_DDR50) |
|---|
| 965 | + return 0; |
|---|
| 966 | + |
|---|
| 967 | + return sdhci_execute_tuning(mmc, opcode); |
|---|
| 968 | +} |
|---|
| 969 | + |
|---|
| 807 | 970 | static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) |
|---|
| 808 | 971 | { |
|---|
| 809 | 972 | u32 reg; |
|---|
| 973 | + u8 sw_rst; |
|---|
| 974 | + int ret; |
|---|
| 810 | 975 | |
|---|
| 811 | 976 | /* FIXME: delay a bit for card to be ready for next tuning due to errors */ |
|---|
| 812 | 977 | mdelay(1); |
|---|
| 978 | + |
|---|
| 979 | + /* IC suggest to reset USDHC before every tuning command */ |
|---|
| 980 | + esdhc_clrset_le(host, 0xff, SDHCI_RESET_ALL, SDHCI_SOFTWARE_RESET); |
|---|
| 981 | + ret = readb_poll_timeout(host->ioaddr + SDHCI_SOFTWARE_RESET, sw_rst, |
|---|
| 982 | + !(sw_rst & SDHCI_RESET_ALL), 10, 100); |
|---|
| 983 | + if (ret == -ETIMEDOUT) |
|---|
| 984 | + dev_warn(mmc_dev(host->mmc), |
|---|
| 985 | + "warning! RESET_ALL never complete before sending tuning command\n"); |
|---|
| 813 | 986 | |
|---|
| 814 | 987 | reg = readl(host->ioaddr + ESDHC_MIX_CTRL); |
|---|
| 815 | 988 | reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | |
|---|
| .. | .. |
|---|
| 867 | 1040 | return ret; |
|---|
| 868 | 1041 | } |
|---|
| 869 | 1042 | |
|---|
| 1043 | +static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) |
|---|
| 1044 | +{ |
|---|
| 1045 | + struct sdhci_host *host = mmc_priv(mmc); |
|---|
| 1046 | + u32 m; |
|---|
| 1047 | + |
|---|
| 1048 | + m = readl(host->ioaddr + ESDHC_MIX_CTRL); |
|---|
| 1049 | + if (ios->enhanced_strobe) |
|---|
| 1050 | + m |= ESDHC_MIX_CTRL_HS400_ES_EN; |
|---|
| 1051 | + else |
|---|
| 1052 | + m &= ~ESDHC_MIX_CTRL_HS400_ES_EN; |
|---|
| 1053 | + writel(m, host->ioaddr + ESDHC_MIX_CTRL); |
|---|
| 1054 | +} |
|---|
| 1055 | + |
|---|
| 870 | 1056 | static int esdhc_change_pinstate(struct sdhci_host *host, |
|---|
| 871 | 1057 | unsigned int uhs) |
|---|
| 872 | 1058 | { |
|---|
| .. | .. |
|---|
| 877 | 1063 | dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs); |
|---|
| 878 | 1064 | |
|---|
| 879 | 1065 | if (IS_ERR(imx_data->pinctrl) || |
|---|
| 880 | | - IS_ERR(imx_data->pins_default) || |
|---|
| 881 | 1066 | IS_ERR(imx_data->pins_100mhz) || |
|---|
| 882 | 1067 | IS_ERR(imx_data->pins_200mhz)) |
|---|
| 883 | 1068 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 894 | 1079 | break; |
|---|
| 895 | 1080 | default: |
|---|
| 896 | 1081 | /* back to default state for other legacy timing */ |
|---|
| 897 | | - pinctrl = imx_data->pins_default; |
|---|
| 1082 | + return pinctrl_select_default_state(mmc_dev(host->mmc)); |
|---|
| 898 | 1083 | } |
|---|
| 899 | 1084 | |
|---|
| 900 | 1085 | return pinctrl_select_state(imx_data->pinctrl, pinctrl); |
|---|
| .. | .. |
|---|
| 908 | 1093 | * edge of data_strobe line. Due to the time delay between CLK line and |
|---|
| 909 | 1094 | * data_strobe line, if the delay time is larger than one clock cycle, |
|---|
| 910 | 1095 | * then CLK and data_strobe line will be misaligned, read error shows up. |
|---|
| 911 | | - * So when the CLK is higher than 100MHz, each clock cycle is short enough, |
|---|
| 912 | | - * host should configure the delay target. |
|---|
| 913 | 1096 | */ |
|---|
| 914 | 1097 | static void esdhc_set_strobe_dll(struct sdhci_host *host) |
|---|
| 915 | 1098 | { |
|---|
| 1099 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
|---|
| 1100 | + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); |
|---|
| 1101 | + u32 strobe_delay; |
|---|
| 916 | 1102 | u32 v; |
|---|
| 1103 | + int ret; |
|---|
| 917 | 1104 | |
|---|
| 918 | | - if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) { |
|---|
| 919 | | - /* disable clock before enabling strobe dll */ |
|---|
| 920 | | - writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & |
|---|
| 921 | | - ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, |
|---|
| 922 | | - host->ioaddr + ESDHC_VENDOR_SPEC); |
|---|
| 1105 | + /* disable clock before enabling strobe dll */ |
|---|
| 1106 | + writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) & |
|---|
| 1107 | + ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, |
|---|
| 1108 | + host->ioaddr + ESDHC_VENDOR_SPEC); |
|---|
| 1109 | + esdhc_wait_for_card_clock_gate_off(host); |
|---|
| 923 | 1110 | |
|---|
| 924 | | - /* force a reset on strobe dll */ |
|---|
| 925 | | - writel(ESDHC_STROBE_DLL_CTRL_RESET, |
|---|
| 926 | | - host->ioaddr + ESDHC_STROBE_DLL_CTRL); |
|---|
| 927 | | - /* |
|---|
| 928 | | - * enable strobe dll ctrl and adjust the delay target |
|---|
| 929 | | - * for the uSDHC loopback read clock |
|---|
| 930 | | - */ |
|---|
| 931 | | - v = ESDHC_STROBE_DLL_CTRL_ENABLE | |
|---|
| 932 | | - (7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); |
|---|
| 933 | | - writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); |
|---|
| 934 | | - /* wait 1us to make sure strobe dll status register stable */ |
|---|
| 935 | | - udelay(1); |
|---|
| 936 | | - v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS); |
|---|
| 937 | | - if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK)) |
|---|
| 938 | | - dev_warn(mmc_dev(host->mmc), |
|---|
| 939 | | - "warning! HS400 strobe DLL status REF not lock!\n"); |
|---|
| 940 | | - if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK)) |
|---|
| 941 | | - dev_warn(mmc_dev(host->mmc), |
|---|
| 942 | | - "warning! HS400 strobe DLL status SLV not lock!\n"); |
|---|
| 943 | | - } |
|---|
| 1111 | + /* force a reset on strobe dll */ |
|---|
| 1112 | + writel(ESDHC_STROBE_DLL_CTRL_RESET, |
|---|
| 1113 | + host->ioaddr + ESDHC_STROBE_DLL_CTRL); |
|---|
| 1114 | + /* clear the reset bit on strobe dll before any setting */ |
|---|
| 1115 | + writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL); |
|---|
| 1116 | + |
|---|
| 1117 | + /* |
|---|
| 1118 | + * enable strobe dll ctrl and adjust the delay target |
|---|
| 1119 | + * for the uSDHC loopback read clock |
|---|
| 1120 | + */ |
|---|
| 1121 | + if (imx_data->boarddata.strobe_dll_delay_target) |
|---|
| 1122 | + strobe_delay = imx_data->boarddata.strobe_dll_delay_target; |
|---|
| 1123 | + else |
|---|
| 1124 | + strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT; |
|---|
| 1125 | + v = ESDHC_STROBE_DLL_CTRL_ENABLE | |
|---|
| 1126 | + ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT | |
|---|
| 1127 | + (strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); |
|---|
| 1128 | + writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); |
|---|
| 1129 | + |
|---|
| 1130 | + /* wait max 50us to get the REF/SLV lock */ |
|---|
| 1131 | + ret = readl_poll_timeout(host->ioaddr + ESDHC_STROBE_DLL_STATUS, v, |
|---|
| 1132 | + ((v & ESDHC_STROBE_DLL_STS_REF_LOCK) && (v & ESDHC_STROBE_DLL_STS_SLV_LOCK)), 1, 50); |
|---|
| 1133 | + if (ret == -ETIMEDOUT) |
|---|
| 1134 | + dev_warn(mmc_dev(host->mmc), |
|---|
| 1135 | + "warning! HS400 strobe DLL status REF/SLV not lock in 50us, STROBE DLL status is %x!\n", v); |
|---|
| 944 | 1136 | } |
|---|
| 945 | 1137 | |
|---|
| 946 | 1138 | static void esdhc_reset_tuning(struct sdhci_host *host) |
|---|
| .. | .. |
|---|
| 1036 | 1228 | |
|---|
| 1037 | 1229 | static void esdhc_reset(struct sdhci_host *host, u8 mask) |
|---|
| 1038 | 1230 | { |
|---|
| 1039 | | - sdhci_reset(host, mask); |
|---|
| 1231 | + sdhci_and_cqhci_reset(host, mask); |
|---|
| 1040 | 1232 | |
|---|
| 1041 | 1233 | sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); |
|---|
| 1042 | 1234 | sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); |
|---|
| .. | .. |
|---|
| 1062 | 1254 | SDHCI_TIMEOUT_CONTROL); |
|---|
| 1063 | 1255 | } |
|---|
| 1064 | 1256 | |
|---|
| 1257 | +static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) |
|---|
| 1258 | +{ |
|---|
| 1259 | + int cmd_error = 0; |
|---|
| 1260 | + int data_error = 0; |
|---|
| 1261 | + |
|---|
| 1262 | + if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) |
|---|
| 1263 | + return intmask; |
|---|
| 1264 | + |
|---|
| 1265 | + cqhci_irq(host->mmc, intmask, cmd_error, data_error); |
|---|
| 1266 | + |
|---|
| 1267 | + return 0; |
|---|
| 1268 | +} |
|---|
| 1269 | + |
|---|
| 1065 | 1270 | static struct sdhci_ops sdhci_esdhc_ops = { |
|---|
| 1066 | 1271 | .read_l = esdhc_readl_le, |
|---|
| 1067 | 1272 | .read_w = esdhc_readw_le, |
|---|
| .. | .. |
|---|
| 1078 | 1283 | .set_bus_width = esdhc_pltfm_set_bus_width, |
|---|
| 1079 | 1284 | .set_uhs_signaling = esdhc_set_uhs_signaling, |
|---|
| 1080 | 1285 | .reset = esdhc_reset, |
|---|
| 1286 | + .irq = esdhc_cqhci_irq, |
|---|
| 1287 | + .dump_vendor_regs = esdhc_dump_debug_regs, |
|---|
| 1081 | 1288 | }; |
|---|
| 1082 | 1289 | |
|---|
| 1083 | 1290 | static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { |
|---|
| .. | .. |
|---|
| 1092 | 1299 | { |
|---|
| 1093 | 1300 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
|---|
| 1094 | 1301 | struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); |
|---|
| 1302 | + struct cqhci_host *cq_host = host->mmc->cqe_private; |
|---|
| 1095 | 1303 | int tmp; |
|---|
| 1096 | 1304 | |
|---|
| 1097 | 1305 | if (esdhc_is_usdhc(imx_data)) { |
|---|
| .. | .. |
|---|
| 1126 | 1334 | /* disable DLL_CTRL delay line settings */ |
|---|
| 1127 | 1335 | writel(0x0, host->ioaddr + ESDHC_DLL_CTRL); |
|---|
| 1128 | 1336 | |
|---|
| 1337 | + /* |
|---|
| 1338 | + * For the case of command with busy, if set the bit |
|---|
| 1339 | + * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a |
|---|
| 1340 | + * transfer complete interrupt when busy is deasserted. |
|---|
| 1341 | + * When CQHCI use DCMD to send a CMD need R1b respons, |
|---|
| 1342 | + * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ, |
|---|
| 1343 | + * otherwise DCMD will always meet timeout waiting for |
|---|
| 1344 | + * hardware interrupt issue. |
|---|
| 1345 | + */ |
|---|
| 1346 | + if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { |
|---|
| 1347 | + tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2); |
|---|
| 1348 | + tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ; |
|---|
| 1349 | + writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2); |
|---|
| 1350 | + |
|---|
| 1351 | + host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; |
|---|
| 1352 | + } |
|---|
| 1353 | + |
|---|
| 1129 | 1354 | if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { |
|---|
| 1130 | 1355 | tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); |
|---|
| 1131 | 1356 | tmp |= ESDHC_STD_TUNING_EN | |
|---|
| .. | .. |
|---|
| 1140 | 1365 | tmp |= imx_data->boarddata.tuning_step |
|---|
| 1141 | 1366 | << ESDHC_TUNING_STEP_SHIFT; |
|---|
| 1142 | 1367 | } |
|---|
| 1368 | + |
|---|
| 1369 | + /* Disable the CMD CRC check for tuning, if not, need to |
|---|
| 1370 | + * add some delay after every tuning command, because |
|---|
| 1371 | + * hardware standard tuning logic will directly go to next |
|---|
| 1372 | + * step once it detect the CMD CRC error, will not wait for |
|---|
| 1373 | + * the card side to finally send out the tuning data, trigger |
|---|
| 1374 | + * the buffer read ready interrupt immediately. If usdhc send |
|---|
| 1375 | + * the next tuning command some eMMC card will stuck, can't |
|---|
| 1376 | + * response, block the tuning procedure or the first command |
|---|
| 1377 | + * after the whole tuning procedure always can't get any response. |
|---|
| 1378 | + */ |
|---|
| 1379 | + tmp |= ESDHC_TUNING_CMD_CRC_CHECK_DISABLE; |
|---|
| 1143 | 1380 | writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); |
|---|
| 1381 | + } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { |
|---|
| 1382 | + /* |
|---|
| 1383 | + * ESDHC_STD_TUNING_EN may be configed in bootloader |
|---|
| 1384 | + * or ROM code, so clear this bit here to make sure |
|---|
| 1385 | + * the manual tuning can work. |
|---|
| 1386 | + */ |
|---|
| 1387 | + tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL); |
|---|
| 1388 | + tmp &= ~ESDHC_STD_TUNING_EN; |
|---|
| 1389 | + writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); |
|---|
| 1390 | + } |
|---|
| 1391 | + |
|---|
| 1392 | + /* |
|---|
| 1393 | + * On i.MX8MM, we are running Dual Linux OS, with 1st Linux using SD Card |
|---|
| 1394 | + * as rootfs storage, 2nd Linux using eMMC as rootfs storage. We let the |
|---|
| 1395 | + * the 1st linux configure power/clock for the 2nd Linux. |
|---|
| 1396 | + * |
|---|
| 1397 | + * When the 2nd Linux is booting into rootfs stage, we let the 1st Linux |
|---|
| 1398 | + * to destroy the 2nd linux, then restart the 2nd linux, we met SDHCI dump. |
|---|
| 1399 | + * After we clear the pending interrupt and halt CQCTL, issue gone. |
|---|
| 1400 | + */ |
|---|
| 1401 | + if (cq_host) { |
|---|
| 1402 | + tmp = cqhci_readl(cq_host, CQHCI_IS); |
|---|
| 1403 | + cqhci_writel(cq_host, tmp, CQHCI_IS); |
|---|
| 1404 | + cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL); |
|---|
| 1144 | 1405 | } |
|---|
| 1145 | 1406 | } |
|---|
| 1146 | 1407 | } |
|---|
| 1408 | + |
|---|
| 1409 | +static void esdhc_cqe_enable(struct mmc_host *mmc) |
|---|
| 1410 | +{ |
|---|
| 1411 | + struct sdhci_host *host = mmc_priv(mmc); |
|---|
| 1412 | + struct cqhci_host *cq_host = mmc->cqe_private; |
|---|
| 1413 | + u32 reg; |
|---|
| 1414 | + u16 mode; |
|---|
| 1415 | + int count = 10; |
|---|
| 1416 | + |
|---|
| 1417 | + /* |
|---|
| 1418 | + * CQE gets stuck if it sees Buffer Read Enable bit set, which can be |
|---|
| 1419 | + * the case after tuning, so ensure the buffer is drained. |
|---|
| 1420 | + */ |
|---|
| 1421 | + reg = sdhci_readl(host, SDHCI_PRESENT_STATE); |
|---|
| 1422 | + while (reg & SDHCI_DATA_AVAILABLE) { |
|---|
| 1423 | + sdhci_readl(host, SDHCI_BUFFER); |
|---|
| 1424 | + reg = sdhci_readl(host, SDHCI_PRESENT_STATE); |
|---|
| 1425 | + if (count-- == 0) { |
|---|
| 1426 | + dev_warn(mmc_dev(host->mmc), |
|---|
| 1427 | + "CQE may get stuck because the Buffer Read Enable bit is set\n"); |
|---|
| 1428 | + break; |
|---|
| 1429 | + } |
|---|
| 1430 | + mdelay(1); |
|---|
| 1431 | + } |
|---|
| 1432 | + |
|---|
| 1433 | + /* |
|---|
| 1434 | + * Runtime resume will reset the entire host controller, which |
|---|
| 1435 | + * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL. |
|---|
| 1436 | + * Here set DMAEN and BCEN when enable CMDQ. |
|---|
| 1437 | + */ |
|---|
| 1438 | + mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); |
|---|
| 1439 | + if (host->flags & SDHCI_REQ_USE_DMA) |
|---|
| 1440 | + mode |= SDHCI_TRNS_DMA; |
|---|
| 1441 | + if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE)) |
|---|
| 1442 | + mode |= SDHCI_TRNS_BLK_CNT_EN; |
|---|
| 1443 | + sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); |
|---|
| 1444 | + |
|---|
| 1445 | + /* |
|---|
| 1446 | + * Though Runtime resume reset the entire host controller, |
|---|
| 1447 | + * but do not impact the CQHCI side, need to clear the |
|---|
| 1448 | + * HALT bit, avoid CQHCI stuck in the first request when |
|---|
| 1449 | + * system resume back. |
|---|
| 1450 | + */ |
|---|
| 1451 | + cqhci_writel(cq_host, 0, CQHCI_CTL); |
|---|
| 1452 | + if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) |
|---|
| 1453 | + dev_err(mmc_dev(host->mmc), |
|---|
| 1454 | + "failed to exit halt state when enable CQE\n"); |
|---|
| 1455 | + |
|---|
| 1456 | + |
|---|
| 1457 | + sdhci_cqe_enable(mmc); |
|---|
| 1458 | +} |
|---|
| 1459 | + |
|---|
| 1460 | +static void esdhc_sdhci_dumpregs(struct mmc_host *mmc) |
|---|
| 1461 | +{ |
|---|
| 1462 | + sdhci_dumpregs(mmc_priv(mmc)); |
|---|
| 1463 | +} |
|---|
| 1464 | + |
|---|
| 1465 | +static const struct cqhci_host_ops esdhc_cqhci_ops = { |
|---|
| 1466 | + .enable = esdhc_cqe_enable, |
|---|
| 1467 | + .disable = sdhci_cqe_disable, |
|---|
| 1468 | + .dumpregs = esdhc_sdhci_dumpregs, |
|---|
| 1469 | +}; |
|---|
| 1147 | 1470 | |
|---|
| 1148 | 1471 | #ifdef CONFIG_OF |
|---|
| 1149 | 1472 | static int |
|---|
| .. | .. |
|---|
| 1158 | 1481 | if (of_get_property(np, "fsl,wp-controller", NULL)) |
|---|
| 1159 | 1482 | boarddata->wp_type = ESDHC_WP_CONTROLLER; |
|---|
| 1160 | 1483 | |
|---|
| 1161 | | - boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); |
|---|
| 1162 | | - if (gpio_is_valid(boarddata->wp_gpio)) |
|---|
| 1484 | + /* |
|---|
| 1485 | + * If we have this property, then activate WP check. |
|---|
| 1486 | + * Retrieveing and requesting the actual WP GPIO will happen |
|---|
| 1487 | + * in the call to mmc_of_parse(). |
|---|
| 1488 | + */ |
|---|
| 1489 | + if (of_property_read_bool(np, "wp-gpios")) |
|---|
| 1163 | 1490 | boarddata->wp_type = ESDHC_WP_GPIO; |
|---|
| 1164 | 1491 | |
|---|
| 1165 | 1492 | of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step); |
|---|
| 1166 | 1493 | of_property_read_u32(np, "fsl,tuning-start-tap", |
|---|
| 1167 | 1494 | &boarddata->tuning_start_tap); |
|---|
| 1168 | 1495 | |
|---|
| 1496 | + of_property_read_u32(np, "fsl,strobe-dll-delay-target", |
|---|
| 1497 | + &boarddata->strobe_dll_delay_target); |
|---|
| 1169 | 1498 | if (of_find_property(np, "no-1-8-v", NULL)) |
|---|
| 1170 | 1499 | host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; |
|---|
| 1171 | 1500 | |
|---|
| .. | .. |
|---|
| 1174 | 1503 | |
|---|
| 1175 | 1504 | mmc_of_parse_voltage(np, &host->ocr_mask); |
|---|
| 1176 | 1505 | |
|---|
| 1177 | | - if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pins_default)) { |
|---|
| 1506 | + if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pinctrl)) { |
|---|
| 1178 | 1507 | imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl, |
|---|
| 1179 | 1508 | ESDHC_PINCTRL_STATE_100MHZ); |
|---|
| 1180 | 1509 | imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl, |
|---|
| .. | .. |
|---|
| 1201 | 1530 | } |
|---|
| 1202 | 1531 | #endif |
|---|
| 1203 | 1532 | |
|---|
| 1204 | | -static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev, |
|---|
| 1205 | | - struct sdhci_host *host, |
|---|
| 1206 | | - struct pltfm_imx_data *imx_data) |
|---|
| 1207 | | -{ |
|---|
| 1208 | | - struct esdhc_platform_data *boarddata = &imx_data->boarddata; |
|---|
| 1209 | | - int err; |
|---|
| 1210 | | - |
|---|
| 1211 | | - if (!host->mmc->parent->platform_data) { |
|---|
| 1212 | | - dev_err(mmc_dev(host->mmc), "no board data!\n"); |
|---|
| 1213 | | - return -EINVAL; |
|---|
| 1214 | | - } |
|---|
| 1215 | | - |
|---|
| 1216 | | - imx_data->boarddata = *((struct esdhc_platform_data *) |
|---|
| 1217 | | - host->mmc->parent->platform_data); |
|---|
| 1218 | | - /* write_protect */ |
|---|
| 1219 | | - if (boarddata->wp_type == ESDHC_WP_GPIO) { |
|---|
| 1220 | | - err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio); |
|---|
| 1221 | | - if (err) { |
|---|
| 1222 | | - dev_err(mmc_dev(host->mmc), |
|---|
| 1223 | | - "failed to request write-protect gpio!\n"); |
|---|
| 1224 | | - return err; |
|---|
| 1225 | | - } |
|---|
| 1226 | | - host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; |
|---|
| 1227 | | - } |
|---|
| 1228 | | - |
|---|
| 1229 | | - /* card_detect */ |
|---|
| 1230 | | - switch (boarddata->cd_type) { |
|---|
| 1231 | | - case ESDHC_CD_GPIO: |
|---|
| 1232 | | - err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0); |
|---|
| 1233 | | - if (err) { |
|---|
| 1234 | | - dev_err(mmc_dev(host->mmc), |
|---|
| 1235 | | - "failed to request card-detect gpio!\n"); |
|---|
| 1236 | | - return err; |
|---|
| 1237 | | - } |
|---|
| 1238 | | - /* fall through */ |
|---|
| 1239 | | - |
|---|
| 1240 | | - case ESDHC_CD_CONTROLLER: |
|---|
| 1241 | | - /* we have a working card_detect back */ |
|---|
| 1242 | | - host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; |
|---|
| 1243 | | - break; |
|---|
| 1244 | | - |
|---|
| 1245 | | - case ESDHC_CD_PERMANENT: |
|---|
| 1246 | | - host->mmc->caps |= MMC_CAP_NONREMOVABLE; |
|---|
| 1247 | | - break; |
|---|
| 1248 | | - |
|---|
| 1249 | | - case ESDHC_CD_NONE: |
|---|
| 1250 | | - break; |
|---|
| 1251 | | - } |
|---|
| 1252 | | - |
|---|
| 1253 | | - switch (boarddata->max_bus_width) { |
|---|
| 1254 | | - case 8: |
|---|
| 1255 | | - host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA; |
|---|
| 1256 | | - break; |
|---|
| 1257 | | - case 4: |
|---|
| 1258 | | - host->mmc->caps |= MMC_CAP_4_BIT_DATA; |
|---|
| 1259 | | - break; |
|---|
| 1260 | | - case 1: |
|---|
| 1261 | | - default: |
|---|
| 1262 | | - host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; |
|---|
| 1263 | | - break; |
|---|
| 1264 | | - } |
|---|
| 1265 | | - |
|---|
| 1266 | | - return 0; |
|---|
| 1267 | | -} |
|---|
| 1268 | | - |
|---|
| 1269 | 1533 | static int sdhci_esdhc_imx_probe(struct platform_device *pdev) |
|---|
| 1270 | 1534 | { |
|---|
| 1271 | 1535 | const struct of_device_id *of_id = |
|---|
| 1272 | 1536 | of_match_device(imx_esdhc_dt_ids, &pdev->dev); |
|---|
| 1273 | 1537 | struct sdhci_pltfm_host *pltfm_host; |
|---|
| 1274 | 1538 | struct sdhci_host *host; |
|---|
| 1539 | + struct cqhci_host *cq_host; |
|---|
| 1275 | 1540 | int err; |
|---|
| 1276 | 1541 | struct pltfm_imx_data *imx_data; |
|---|
| 1277 | 1542 | |
|---|
| .. | .. |
|---|
| 1284 | 1549 | |
|---|
| 1285 | 1550 | imx_data = sdhci_pltfm_priv(pltfm_host); |
|---|
| 1286 | 1551 | |
|---|
| 1287 | | - imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *) |
|---|
| 1288 | | - pdev->id_entry->driver_data; |
|---|
| 1552 | + imx_data->socdata = of_id->data; |
|---|
| 1553 | + |
|---|
| 1554 | + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) |
|---|
| 1555 | + cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); |
|---|
| 1289 | 1556 | |
|---|
| 1290 | 1557 | imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); |
|---|
| 1291 | 1558 | if (IS_ERR(imx_data->clk_ipg)) { |
|---|
| .. | .. |
|---|
| 1318 | 1585 | goto disable_ipg_clk; |
|---|
| 1319 | 1586 | |
|---|
| 1320 | 1587 | imx_data->pinctrl = devm_pinctrl_get(&pdev->dev); |
|---|
| 1321 | | - if (IS_ERR(imx_data->pinctrl)) { |
|---|
| 1322 | | - err = PTR_ERR(imx_data->pinctrl); |
|---|
| 1323 | | - goto disable_ahb_clk; |
|---|
| 1324 | | - } |
|---|
| 1325 | | - |
|---|
| 1326 | | - imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl, |
|---|
| 1327 | | - PINCTRL_STATE_DEFAULT); |
|---|
| 1328 | | - if (IS_ERR(imx_data->pins_default)) |
|---|
| 1329 | | - dev_warn(mmc_dev(host->mmc), "could not get default state\n"); |
|---|
| 1588 | + if (IS_ERR(imx_data->pinctrl)) |
|---|
| 1589 | + dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n"); |
|---|
| 1330 | 1590 | |
|---|
| 1331 | 1591 | if (esdhc_is_usdhc(imx_data)) { |
|---|
| 1332 | 1592 | host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; |
|---|
| 1333 | 1593 | host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR; |
|---|
| 1594 | + |
|---|
| 1595 | + /* GPIO CD can be set as a wakeup source */ |
|---|
| 1596 | + host->mmc->caps |= MMC_CAP_CD_WAKE; |
|---|
| 1597 | + |
|---|
| 1334 | 1598 | if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) |
|---|
| 1335 | 1599 | host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; |
|---|
| 1336 | 1600 | |
|---|
| .. | .. |
|---|
| 1338 | 1602 | writel(0x0, host->ioaddr + ESDHC_MIX_CTRL); |
|---|
| 1339 | 1603 | writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS); |
|---|
| 1340 | 1604 | writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); |
|---|
| 1605 | + |
|---|
| 1606 | + /* |
|---|
| 1607 | + * Link usdhc specific mmc_host_ops execute_tuning function, |
|---|
| 1608 | + * to replace the standard one in sdhci_ops. |
|---|
| 1609 | + */ |
|---|
| 1610 | + host->mmc_host_ops.execute_tuning = usdhc_execute_tuning; |
|---|
| 1341 | 1611 | } |
|---|
| 1612 | + |
|---|
| 1613 | + err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); |
|---|
| 1614 | + if (err) |
|---|
| 1615 | + goto disable_ahb_clk; |
|---|
| 1342 | 1616 | |
|---|
| 1343 | 1617 | if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) |
|---|
| 1344 | 1618 | sdhci_esdhc_ops.platform_execute_tuning = |
|---|
| .. | .. |
|---|
| 1347 | 1621 | if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) |
|---|
| 1348 | 1622 | host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; |
|---|
| 1349 | 1623 | |
|---|
| 1350 | | - if (imx_data->socdata->flags & ESDHC_FLAG_HS400) |
|---|
| 1624 | + if (host->mmc->caps & MMC_CAP_8_BIT_DATA && |
|---|
| 1625 | + imx_data->socdata->flags & ESDHC_FLAG_HS400) |
|---|
| 1351 | 1626 | host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; |
|---|
| 1352 | 1627 | |
|---|
| 1353 | | - if (of_id) |
|---|
| 1354 | | - err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); |
|---|
| 1355 | | - else |
|---|
| 1356 | | - err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data); |
|---|
| 1357 | | - if (err) |
|---|
| 1358 | | - goto disable_ahb_clk; |
|---|
| 1628 | + if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23) |
|---|
| 1629 | + host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN; |
|---|
| 1630 | + |
|---|
| 1631 | + if (host->mmc->caps & MMC_CAP_8_BIT_DATA && |
|---|
| 1632 | + imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) { |
|---|
| 1633 | + host->mmc->caps2 |= MMC_CAP2_HS400_ES; |
|---|
| 1634 | + host->mmc_host_ops.hs400_enhanced_strobe = |
|---|
| 1635 | + esdhc_hs400_enhanced_strobe; |
|---|
| 1636 | + } |
|---|
| 1637 | + |
|---|
| 1638 | + if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) { |
|---|
| 1639 | + host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD; |
|---|
| 1640 | + cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL); |
|---|
| 1641 | + if (!cq_host) { |
|---|
| 1642 | + err = -ENOMEM; |
|---|
| 1643 | + goto disable_ahb_clk; |
|---|
| 1644 | + } |
|---|
| 1645 | + |
|---|
| 1646 | + cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET; |
|---|
| 1647 | + cq_host->ops = &esdhc_cqhci_ops; |
|---|
| 1648 | + |
|---|
| 1649 | + err = cqhci_init(cq_host, host->mmc, false); |
|---|
| 1650 | + if (err) |
|---|
| 1651 | + goto disable_ahb_clk; |
|---|
| 1652 | + } |
|---|
| 1359 | 1653 | |
|---|
| 1360 | 1654 | sdhci_esdhc_imx_hwinit(host); |
|---|
| 1361 | 1655 | |
|---|
| .. | .. |
|---|
| 1378 | 1672 | disable_per_clk: |
|---|
| 1379 | 1673 | clk_disable_unprepare(imx_data->clk_per); |
|---|
| 1380 | 1674 | free_sdhci: |
|---|
| 1675 | + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) |
|---|
| 1676 | + cpu_latency_qos_remove_request(&imx_data->pm_qos_req); |
|---|
| 1381 | 1677 | sdhci_pltfm_free(pdev); |
|---|
| 1382 | 1678 | return err; |
|---|
| 1383 | 1679 | } |
|---|
| .. | .. |
|---|
| 1400 | 1696 | clk_disable_unprepare(imx_data->clk_ipg); |
|---|
| 1401 | 1697 | clk_disable_unprepare(imx_data->clk_ahb); |
|---|
| 1402 | 1698 | |
|---|
| 1699 | + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) |
|---|
| 1700 | + cpu_latency_qos_remove_request(&imx_data->pm_qos_req); |
|---|
| 1701 | + |
|---|
| 1403 | 1702 | sdhci_pltfm_free(pdev); |
|---|
| 1404 | 1703 | |
|---|
| 1405 | 1704 | return 0; |
|---|
| .. | .. |
|---|
| 1409 | 1708 | static int sdhci_esdhc_suspend(struct device *dev) |
|---|
| 1410 | 1709 | { |
|---|
| 1411 | 1710 | struct sdhci_host *host = dev_get_drvdata(dev); |
|---|
| 1711 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
|---|
| 1712 | + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); |
|---|
| 1713 | + int ret; |
|---|
| 1714 | + |
|---|
| 1715 | + if (host->mmc->caps2 & MMC_CAP2_CQE) { |
|---|
| 1716 | + ret = cqhci_suspend(host->mmc); |
|---|
| 1717 | + if (ret) |
|---|
| 1718 | + return ret; |
|---|
| 1719 | + } |
|---|
| 1720 | + |
|---|
| 1721 | + if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) && |
|---|
| 1722 | + (host->tuning_mode != SDHCI_TUNING_MODE_1)) { |
|---|
| 1723 | + mmc_retune_timer_stop(host->mmc); |
|---|
| 1724 | + mmc_retune_needed(host->mmc); |
|---|
| 1725 | + } |
|---|
| 1412 | 1726 | |
|---|
| 1413 | 1727 | if (host->tuning_mode != SDHCI_TUNING_MODE_3) |
|---|
| 1414 | 1728 | mmc_retune_needed(host->mmc); |
|---|
| 1415 | 1729 | |
|---|
| 1416 | | - return sdhci_suspend_host(host); |
|---|
| 1730 | + ret = sdhci_suspend_host(host); |
|---|
| 1731 | + if (ret) |
|---|
| 1732 | + return ret; |
|---|
| 1733 | + |
|---|
| 1734 | + ret = pinctrl_pm_select_sleep_state(dev); |
|---|
| 1735 | + if (ret) |
|---|
| 1736 | + return ret; |
|---|
| 1737 | + |
|---|
| 1738 | + ret = mmc_gpio_set_cd_wake(host->mmc, true); |
|---|
| 1739 | + |
|---|
| 1740 | + return ret; |
|---|
| 1417 | 1741 | } |
|---|
| 1418 | 1742 | |
|---|
| 1419 | 1743 | static int sdhci_esdhc_resume(struct device *dev) |
|---|
| 1420 | 1744 | { |
|---|
| 1421 | 1745 | struct sdhci_host *host = dev_get_drvdata(dev); |
|---|
| 1746 | + int ret; |
|---|
| 1747 | + |
|---|
| 1748 | + ret = pinctrl_pm_select_default_state(dev); |
|---|
| 1749 | + if (ret) |
|---|
| 1750 | + return ret; |
|---|
| 1422 | 1751 | |
|---|
| 1423 | 1752 | /* re-initialize hw state in case it's lost in low power mode */ |
|---|
| 1424 | 1753 | sdhci_esdhc_imx_hwinit(host); |
|---|
| 1425 | 1754 | |
|---|
| 1426 | | - return sdhci_resume_host(host); |
|---|
| 1755 | + ret = sdhci_resume_host(host); |
|---|
| 1756 | + if (ret) |
|---|
| 1757 | + return ret; |
|---|
| 1758 | + |
|---|
| 1759 | + if (host->mmc->caps2 & MMC_CAP2_CQE) |
|---|
| 1760 | + ret = cqhci_resume(host->mmc); |
|---|
| 1761 | + |
|---|
| 1762 | + if (!ret) |
|---|
| 1763 | + ret = mmc_gpio_set_cd_wake(host->mmc, false); |
|---|
| 1764 | + |
|---|
| 1765 | + return ret; |
|---|
| 1427 | 1766 | } |
|---|
| 1428 | 1767 | #endif |
|---|
| 1429 | 1768 | |
|---|
| .. | .. |
|---|
| 1435 | 1774 | struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); |
|---|
| 1436 | 1775 | int ret; |
|---|
| 1437 | 1776 | |
|---|
| 1777 | + if (host->mmc->caps2 & MMC_CAP2_CQE) { |
|---|
| 1778 | + ret = cqhci_suspend(host->mmc); |
|---|
| 1779 | + if (ret) |
|---|
| 1780 | + return ret; |
|---|
| 1781 | + } |
|---|
| 1782 | + |
|---|
| 1438 | 1783 | ret = sdhci_runtime_suspend_host(host); |
|---|
| 1439 | 1784 | if (ret) |
|---|
| 1440 | 1785 | return ret; |
|---|
| .. | .. |
|---|
| 1442 | 1787 | if (host->tuning_mode != SDHCI_TUNING_MODE_3) |
|---|
| 1443 | 1788 | mmc_retune_needed(host->mmc); |
|---|
| 1444 | 1789 | |
|---|
| 1445 | | - if (!sdhci_sdio_irq_enabled(host)) { |
|---|
| 1446 | | - imx_data->actual_clock = host->mmc->actual_clock; |
|---|
| 1447 | | - esdhc_pltfm_set_clock(host, 0); |
|---|
| 1448 | | - clk_disable_unprepare(imx_data->clk_per); |
|---|
| 1449 | | - clk_disable_unprepare(imx_data->clk_ipg); |
|---|
| 1450 | | - } |
|---|
| 1790 | + imx_data->actual_clock = host->mmc->actual_clock; |
|---|
| 1791 | + esdhc_pltfm_set_clock(host, 0); |
|---|
| 1792 | + clk_disable_unprepare(imx_data->clk_per); |
|---|
| 1793 | + clk_disable_unprepare(imx_data->clk_ipg); |
|---|
| 1451 | 1794 | clk_disable_unprepare(imx_data->clk_ahb); |
|---|
| 1795 | + |
|---|
| 1796 | + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) |
|---|
| 1797 | + cpu_latency_qos_remove_request(&imx_data->pm_qos_req); |
|---|
| 1452 | 1798 | |
|---|
| 1453 | 1799 | return ret; |
|---|
| 1454 | 1800 | } |
|---|
| .. | .. |
|---|
| 1460 | 1806 | struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); |
|---|
| 1461 | 1807 | int err; |
|---|
| 1462 | 1808 | |
|---|
| 1809 | + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) |
|---|
| 1810 | + cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); |
|---|
| 1811 | + |
|---|
| 1812 | + if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME) |
|---|
| 1813 | + clk_set_rate(imx_data->clk_per, pltfm_host->clock); |
|---|
| 1814 | + |
|---|
| 1463 | 1815 | err = clk_prepare_enable(imx_data->clk_ahb); |
|---|
| 1464 | 1816 | if (err) |
|---|
| 1465 | | - return err; |
|---|
| 1817 | + goto remove_pm_qos_request; |
|---|
| 1466 | 1818 | |
|---|
| 1467 | | - if (!sdhci_sdio_irq_enabled(host)) { |
|---|
| 1468 | | - err = clk_prepare_enable(imx_data->clk_per); |
|---|
| 1469 | | - if (err) |
|---|
| 1470 | | - goto disable_ahb_clk; |
|---|
| 1471 | | - err = clk_prepare_enable(imx_data->clk_ipg); |
|---|
| 1472 | | - if (err) |
|---|
| 1473 | | - goto disable_per_clk; |
|---|
| 1474 | | - esdhc_pltfm_set_clock(host, imx_data->actual_clock); |
|---|
| 1475 | | - } |
|---|
| 1819 | + err = clk_prepare_enable(imx_data->clk_per); |
|---|
| 1820 | + if (err) |
|---|
| 1821 | + goto disable_ahb_clk; |
|---|
| 1476 | 1822 | |
|---|
| 1477 | | - err = sdhci_runtime_resume_host(host); |
|---|
| 1823 | + err = clk_prepare_enable(imx_data->clk_ipg); |
|---|
| 1824 | + if (err) |
|---|
| 1825 | + goto disable_per_clk; |
|---|
| 1826 | + |
|---|
| 1827 | + esdhc_pltfm_set_clock(host, imx_data->actual_clock); |
|---|
| 1828 | + |
|---|
| 1829 | + err = sdhci_runtime_resume_host(host, 0); |
|---|
| 1478 | 1830 | if (err) |
|---|
| 1479 | 1831 | goto disable_ipg_clk; |
|---|
| 1480 | 1832 | |
|---|
| 1481 | | - return 0; |
|---|
| 1833 | + if (host->mmc->caps2 & MMC_CAP2_CQE) |
|---|
| 1834 | + err = cqhci_resume(host->mmc); |
|---|
| 1835 | + |
|---|
| 1836 | + return err; |
|---|
| 1482 | 1837 | |
|---|
| 1483 | 1838 | disable_ipg_clk: |
|---|
| 1484 | | - if (!sdhci_sdio_irq_enabled(host)) |
|---|
| 1485 | | - clk_disable_unprepare(imx_data->clk_ipg); |
|---|
| 1839 | + clk_disable_unprepare(imx_data->clk_ipg); |
|---|
| 1486 | 1840 | disable_per_clk: |
|---|
| 1487 | | - if (!sdhci_sdio_irq_enabled(host)) |
|---|
| 1488 | | - clk_disable_unprepare(imx_data->clk_per); |
|---|
| 1841 | + clk_disable_unprepare(imx_data->clk_per); |
|---|
| 1489 | 1842 | disable_ahb_clk: |
|---|
| 1490 | 1843 | clk_disable_unprepare(imx_data->clk_ahb); |
|---|
| 1844 | +remove_pm_qos_request: |
|---|
| 1845 | + if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) |
|---|
| 1846 | + cpu_latency_qos_remove_request(&imx_data->pm_qos_req); |
|---|
| 1491 | 1847 | return err; |
|---|
| 1492 | 1848 | } |
|---|
| 1493 | 1849 | #endif |
|---|
| .. | .. |
|---|
| 1501 | 1857 | static struct platform_driver sdhci_esdhc_imx_driver = { |
|---|
| 1502 | 1858 | .driver = { |
|---|
| 1503 | 1859 | .name = "sdhci-esdhc-imx", |
|---|
| 1860 | + .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
|---|
| 1504 | 1861 | .of_match_table = imx_esdhc_dt_ids, |
|---|
| 1505 | 1862 | .pm = &sdhci_esdhc_pmops, |
|---|
| 1506 | 1863 | }, |
|---|
| 1507 | | - .id_table = imx_esdhc_devtype, |
|---|
| 1508 | 1864 | .probe = sdhci_esdhc_imx_probe, |
|---|
| 1509 | 1865 | .remove = sdhci_esdhc_imx_remove, |
|---|
| 1510 | 1866 | }; |
|---|