.. | .. |
---|
7 | 7 | * Author: Jisheng Zhang <jszhang@kernel.org> |
---|
8 | 8 | */ |
---|
9 | 9 | |
---|
| 10 | +#include <linux/acpi.h> |
---|
10 | 11 | #include <linux/clk.h> |
---|
11 | 12 | #include <linux/dma-mapping.h> |
---|
12 | 13 | #include <linux/iopoll.h> |
---|
.. | .. |
---|
26 | 27 | /* DWCMSHC specific Mode Select value */ |
---|
27 | 28 | #define DWCMSHC_CTRL_HS400 0x7 |
---|
28 | 29 | |
---|
29 | | -#define DWCMSHC_VER_ID 0x500 |
---|
30 | | -#define DWCMSHC_VER_TYPE 0x504 |
---|
31 | | -#define DWCMSHC_HOST_CTRL3 0x508 |
---|
32 | | -#define DWCMSHC_EMMC_CONTROL 0x52c |
---|
33 | | -#define DWCMSHC_EMMC_ATCTRL 0x540 |
---|
| 30 | +/* DWC IP vendor area 1 pointer */ |
---|
| 31 | +#define DWCMSHC_P_VENDOR_AREA1 0xe8 |
---|
| 32 | +#define DWCMSHC_AREA1_MASK GENMASK(11, 0) |
---|
| 33 | +/* Offset inside the vendor area 1 */ |
---|
| 34 | +#define DWCMSHC_HOST_CTRL3 0x8 |
---|
| 35 | +#define DWCMSHC_EMMC_CONTROL 0x2c |
---|
| 36 | +#define DWCMSHC_CARD_IS_EMMC BIT(0) |
---|
| 37 | +#define DWCMSHC_ENHANCED_STROBE BIT(8) |
---|
| 38 | +#define DWCMSHC_EMMC_ATCTRL 0x40 |
---|
34 | 39 | |
---|
35 | 40 | /* Rockchip specific Registers */ |
---|
36 | 41 | #define DWCMSHC_EMMC_DLL_CTRL 0x800 |
---|
.. | .. |
---|
39 | 44 | #define DWCMSHC_EMMC_DLL_STRBIN 0x80c |
---|
40 | 45 | #define DECMSHC_EMMC_DLL_CMDOUT 0x810 |
---|
41 | 46 | #define DWCMSHC_EMMC_DLL_STATUS0 0x840 |
---|
42 | | - |
---|
| 47 | +#define DWCMSHC_EMMC_DLL_STATUS1 0x844 |
---|
43 | 48 | #define DWCMSHC_EMMC_DLL_START BIT(0) |
---|
44 | 49 | #define DWCMSHC_EMMC_DLL_LOCKED BIT(8) |
---|
45 | 50 | #define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9) |
---|
| 51 | +#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29 |
---|
46 | 52 | #define DWCMSHC_EMMC_DLL_START_POINT 16 |
---|
47 | 53 | #define DWCMSHC_EMMC_DLL_INC 8 |
---|
48 | 54 | #define DWCMSHC_EMMC_DLL_BYPASS BIT(24) |
---|
49 | 55 | #define DWCMSHC_EMMC_DLL_DLYENA BIT(27) |
---|
50 | | - |
---|
| 56 | +#define DLL_TAP_VALUE_SEL BIT(25) |
---|
| 57 | +#define DLL_TAP_VALUE_OFFSET 8 |
---|
51 | 58 | #define DLL_TXCLK_TAPNUM_DEFAULT 0x10 |
---|
52 | | -#define DLL_TXCLK_TAPNUM_90_DEGREES 0x9 |
---|
| 59 | +#define DLL_TXCLK_TAPNUM_90_DEGREES 0xA |
---|
53 | 60 | #define DLL_TXCLK_TAPNUM_FROM_SW BIT(24) |
---|
54 | | -#define DLL_TXCLK_NO_INVERTER BIT(29) |
---|
55 | | - |
---|
56 | | -#define DLL_STRBIN_TAPNUM_DEFAULT 0x4 |
---|
| 61 | +#define DLL_STRBIN_TAPNUM_DEFAULT 0x8 |
---|
57 | 62 | #define DLL_STRBIN_TAPNUM_FROM_SW BIT(24) |
---|
58 | 63 | #define DLL_STRBIN_DELAY_NUM_SEL BIT(26) |
---|
59 | 64 | #define DLL_STRBIN_DELAY_NUM_OFFSET 16 |
---|
60 | | -#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x10 |
---|
61 | | - |
---|
62 | | -#define DLL_RXCLK_NO_INVERTER BIT(29) |
---|
63 | | - |
---|
64 | | -#define DWCMSHC_CARD_IS_EMMC BIT(0) |
---|
65 | | -#define DWCMSHC_ENHANCED_STROBE BIT(8) |
---|
66 | | - |
---|
| 65 | +#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x16 |
---|
| 66 | +#define DLL_RXCLK_NO_INVERTER 1 |
---|
| 67 | +#define DLL_RXCLK_INVERTER 0 |
---|
67 | 68 | #define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8 |
---|
| 69 | +#define DLL_RXCLK_TAPNUM_FROM_SW BIT(24) |
---|
| 70 | +#define DLL_RXCLK_ORI_GATE BIT(31) |
---|
| 71 | +#define DLL_RXCLK_MAX_TAP 32 |
---|
68 | 72 | #define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24) |
---|
69 | 73 | #define DLL_CMDOUT_SRC_CLK_NEG BIT(28) |
---|
70 | 74 | #define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29) |
---|
| 75 | +#define DLL_CMDOUT_BOTH_CLK_EDGE BIT(30) |
---|
71 | 76 | |
---|
72 | 77 | #define DLL_LOCK_WO_TMOUT(x) \ |
---|
73 | 78 | ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ |
---|
74 | 79 | (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0)) |
---|
75 | | -#define ROCKCHIP_MAX_CLKS 3 |
---|
| 80 | +#define RK35xx_MAX_CLKS 3 |
---|
76 | 81 | |
---|
77 | 82 | #define BOUNDARY_OK(addr, len) \ |
---|
78 | 83 | ((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1))) |
---|
79 | 84 | |
---|
80 | | -struct dwcmshc_priv { |
---|
81 | | - struct clk *bus_clk; |
---|
82 | | - u32 cclk_rate; |
---|
83 | | - |
---|
84 | | - /* Rockchip specified optional clocks */ |
---|
85 | | - struct clk_bulk_data rockchip_clks[ROCKCHIP_MAX_CLKS]; |
---|
86 | | - struct reset_control *reset; |
---|
87 | | - int txclk_tapnum; |
---|
88 | | - unsigned int actual_clk; |
---|
89 | | - u32 flags; |
---|
| 85 | +enum dwcmshc_rk_type { |
---|
| 86 | + DWCMSHC_RK3568, |
---|
| 87 | + DWCMSHC_RK3588, |
---|
90 | 88 | }; |
---|
91 | 89 | |
---|
92 | 90 | struct dwcmshc_driver_data { |
---|
.. | .. |
---|
95 | 93 | #define RK_PLATFROM BIT(0) |
---|
96 | 94 | #define RK_DLL_CMD_OUT BIT(1) |
---|
97 | 95 | #define RK_RXCLK_NO_INVERTER BIT(2) |
---|
| 96 | +#define RK_TAP_VALUE_SEL BIT(3) |
---|
| 97 | + |
---|
| 98 | + u8 hs200_tx_tap; |
---|
| 99 | + u8 hs400_tx_tap; |
---|
| 100 | + u8 hs400_cmd_tap; |
---|
| 101 | + u8 ddr50_strbin_delay_num; |
---|
| 102 | + u8 hs400_strbin_tap; |
---|
| 103 | +}; |
---|
| 104 | + |
---|
| 105 | +struct rk35xx_priv { |
---|
| 106 | + /* Rockchip specified optional clocks */ |
---|
| 107 | + struct clk_bulk_data rockchip_clks[RK35xx_MAX_CLKS]; |
---|
| 108 | + struct reset_control *reset; |
---|
| 109 | + enum dwcmshc_rk_type devtype; |
---|
| 110 | + u8 txclk_tapnum; |
---|
| 111 | + u32 cclk_rate; |
---|
| 112 | + unsigned int actual_clk; |
---|
| 113 | + const struct dwcmshc_driver_data *drv_data; |
---|
| 114 | + u32 acpi_en; |
---|
| 115 | +}; |
---|
| 116 | + |
---|
| 117 | +struct dwcmshc_priv { |
---|
| 118 | + struct clk *bus_clk; |
---|
| 119 | + int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */ |
---|
| 120 | + void *priv; /* pointer to SoC private stuff */ |
---|
98 | 121 | }; |
---|
99 | 122 | |
---|
100 | 123 | /* |
---|
.. | .. |
---|
118 | 141 | addr += tmplen; |
---|
119 | 142 | len -= tmplen; |
---|
120 | 143 | sdhci_adma_write_desc(host, desc, addr, len, cmd); |
---|
| 144 | +} |
---|
| 145 | + |
---|
| 146 | +static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host) |
---|
| 147 | +{ |
---|
| 148 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 149 | + |
---|
| 150 | + if (pltfm_host->clk) |
---|
| 151 | + return sdhci_pltfm_clk_get_max_clock(host); |
---|
| 152 | + else |
---|
| 153 | + return pltfm_host->clock; |
---|
121 | 154 | } |
---|
122 | 155 | |
---|
123 | 156 | static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc, |
---|
.. | .. |
---|
146 | 179 | static void dwcmshc_set_uhs_signaling(struct sdhci_host *host, |
---|
147 | 180 | unsigned int timing) |
---|
148 | 181 | { |
---|
149 | | - u16 ctrl_2, ctrl; |
---|
| 182 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 183 | + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
---|
| 184 | + u16 ctrl, ctrl_2; |
---|
150 | 185 | |
---|
151 | 186 | ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); |
---|
152 | 187 | /* Select Bus Speed Mode for host */ |
---|
.. | .. |
---|
166 | 201 | ctrl_2 |= SDHCI_CTRL_UHS_DDR50; |
---|
167 | 202 | else if (timing == MMC_TIMING_MMC_HS400) { |
---|
168 | 203 | /* set CARD_IS_EMMC bit to enable Data Strobe for HS400 */ |
---|
169 | | - ctrl = sdhci_readw(host, DWCMSHC_EMMC_CONTROL); |
---|
| 204 | + ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); |
---|
170 | 205 | ctrl |= DWCMSHC_CARD_IS_EMMC; |
---|
171 | | - sdhci_writew(host, ctrl, DWCMSHC_EMMC_CONTROL); |
---|
| 206 | + sdhci_writew(host, ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL); |
---|
172 | 207 | |
---|
173 | 208 | ctrl_2 |= DWCMSHC_CTRL_HS400; |
---|
174 | 209 | } |
---|
.. | .. |
---|
181 | 216 | { |
---|
182 | 217 | u32 vendor; |
---|
183 | 218 | struct sdhci_host *host = mmc_priv(mmc); |
---|
| 219 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 220 | + struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
---|
| 221 | + int reg = priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL; |
---|
184 | 222 | |
---|
185 | | - vendor = sdhci_readl(host, DWCMSHC_EMMC_CONTROL); |
---|
| 223 | + vendor = sdhci_readl(host, reg); |
---|
186 | 224 | if (ios->enhanced_strobe) |
---|
187 | 225 | vendor |= DWCMSHC_ENHANCED_STROBE; |
---|
188 | 226 | else |
---|
189 | 227 | vendor &= ~DWCMSHC_ENHANCED_STROBE; |
---|
190 | 228 | |
---|
191 | | - sdhci_writel(host, vendor, DWCMSHC_EMMC_CONTROL); |
---|
| 229 | + sdhci_writel(host, vendor, reg); |
---|
192 | 230 | } |
---|
193 | 231 | |
---|
194 | | -static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock) |
---|
| 232 | +static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock) |
---|
195 | 233 | { |
---|
196 | 234 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
197 | | - struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
---|
198 | | - u32 txclk_tapnum, extra; |
---|
| 235 | + struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); |
---|
| 236 | + struct rk35xx_priv *priv = dwc_priv->priv; |
---|
| 237 | + const struct dwcmshc_driver_data *drv_data = priv->drv_data; |
---|
| 238 | + u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; |
---|
| 239 | + u32 extra, reg, dll_lock_value; |
---|
199 | 240 | int err; |
---|
200 | 241 | |
---|
201 | 242 | host->mmc->actual_clock = 0; |
---|
.. | .. |
---|
210 | 251 | if (clock <= 400000) |
---|
211 | 252 | clock = 375000; |
---|
212 | 253 | |
---|
213 | | - err = clk_set_rate(pltfm_host->clk, clock); |
---|
214 | | - if (err) |
---|
215 | | - dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock); |
---|
| 254 | + if (priv->acpi_en) { |
---|
| 255 | + union acpi_object params[1]; |
---|
| 256 | + struct acpi_object_list param_objects; |
---|
| 257 | + |
---|
| 258 | + params[0].type = ACPI_TYPE_INTEGER; |
---|
| 259 | + params[0].integer.value = clock; |
---|
| 260 | + param_objects.count = 1; |
---|
| 261 | + param_objects.pointer = params; |
---|
| 262 | + acpi_evaluate_object(ACPI_HANDLE(mmc_dev(host->mmc)), "SCLK", ¶m_objects, NULL); |
---|
| 263 | + } else { |
---|
| 264 | + err = clk_set_rate(pltfm_host->clk, clock); |
---|
| 265 | + if (err) |
---|
| 266 | + dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock); |
---|
| 267 | + } |
---|
216 | 268 | |
---|
217 | 269 | sdhci_set_clock(host, clock); |
---|
218 | 270 | |
---|
219 | 271 | /* Disable cmd conflict check */ |
---|
220 | | - extra = sdhci_readl(host, DWCMSHC_HOST_CTRL3); |
---|
| 272 | + reg = dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3; |
---|
| 273 | + extra = sdhci_readl(host, reg); |
---|
221 | 274 | extra &= ~BIT(0); |
---|
222 | | - sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3); |
---|
| 275 | + sdhci_writel(host, extra, reg); |
---|
| 276 | + |
---|
| 277 | + /* Disable output clock while config DLL */ |
---|
| 278 | + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); |
---|
223 | 279 | |
---|
224 | 280 | if (clock <= 52000000) { |
---|
| 281 | + /* Disable DLL */ |
---|
| 282 | + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); |
---|
225 | 283 | /* |
---|
226 | | - * Disable DLL and reset both of sample and drive clock. |
---|
| 284 | + * Config DLL BYPASS and Reset both of sample and drive clock. |
---|
227 | 285 | * The bypass bit and start bit need to set if DLL is not locked. |
---|
228 | 286 | */ |
---|
229 | 287 | sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL); |
---|
230 | | - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_RXCLK); |
---|
| 288 | + sdhci_writel(host, DLL_RXCLK_ORI_GATE, DWCMSHC_EMMC_DLL_RXCLK); |
---|
231 | 289 | sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); |
---|
232 | 290 | sdhci_writel(host, 0, DECMSHC_EMMC_DLL_CMDOUT); |
---|
233 | 291 | /* |
---|
.. | .. |
---|
237 | 295 | */ |
---|
238 | 296 | extra = DWCMSHC_EMMC_DLL_DLYENA | |
---|
239 | 297 | DLL_STRBIN_DELAY_NUM_SEL | |
---|
240 | | - DLL_STRBIN_DELAY_NUM_DEFAULT << DLL_STRBIN_DELAY_NUM_OFFSET; |
---|
| 298 | + drv_data->ddr50_strbin_delay_num << DLL_STRBIN_DELAY_NUM_OFFSET; |
---|
241 | 299 | sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); |
---|
242 | | - return; |
---|
| 300 | + goto exit; |
---|
243 | 301 | } |
---|
244 | 302 | |
---|
245 | 303 | /* Reset DLL */ |
---|
.. | .. |
---|
247 | 305 | udelay(1); |
---|
248 | 306 | sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL); |
---|
249 | 307 | |
---|
250 | | - /* |
---|
251 | | - * We shouldn't set DLL_RXCLK_NO_INVERTER for identify mode but |
---|
252 | | - * we must set it in higher speed mode. |
---|
253 | | - */ |
---|
254 | | - extra = DWCMSHC_EMMC_DLL_DLYENA; |
---|
255 | | - if (priv->flags & RK_RXCLK_NO_INVERTER) |
---|
256 | | - extra |= DLL_RXCLK_NO_INVERTER; |
---|
257 | | - sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); |
---|
258 | | - |
---|
259 | 308 | /* Init DLL settings, clean start bit before resetting */ |
---|
260 | 309 | sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); |
---|
| 310 | + /* Init DLL settings */ |
---|
261 | 311 | extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT | |
---|
262 | 312 | 0x2 << DWCMSHC_EMMC_DLL_INC | |
---|
263 | 313 | DWCMSHC_EMMC_DLL_START; |
---|
.. | .. |
---|
267 | 317 | 500 * USEC_PER_MSEC); |
---|
268 | 318 | if (err) { |
---|
269 | 319 | dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n"); |
---|
270 | | - return; |
---|
| 320 | + goto exit; |
---|
271 | 321 | } |
---|
| 322 | + |
---|
| 323 | + dll_lock_value = ((sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0) & 0xFF) * 2) & 0xFF; |
---|
272 | 324 | |
---|
273 | 325 | extra = 0x1 << 16 | /* tune clock stop en */ |
---|
274 | | - 0x2 << 17 | /* pre-change delay */ |
---|
| 326 | + 0x3 << 17 | /* pre-change delay */ |
---|
275 | 327 | 0x3 << 19; /* post-change delay */ |
---|
276 | | - sdhci_writel(host, extra, DWCMSHC_EMMC_ATCTRL); |
---|
| 328 | + sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL); |
---|
277 | 329 | |
---|
278 | | - txclk_tapnum = priv->txclk_tapnum; |
---|
| 330 | + extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE; |
---|
| 331 | + if (drv_data->flags & RK_RXCLK_NO_INVERTER) |
---|
| 332 | + extra |= DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL; |
---|
| 333 | + if (drv_data->flags & RK_TAP_VALUE_SEL) |
---|
| 334 | + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; |
---|
| 335 | + sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); |
---|
279 | 336 | |
---|
280 | | - if ((priv->flags & RK_DLL_CMD_OUT) && |
---|
281 | | - host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { |
---|
282 | | - txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES; |
---|
| 337 | + txclk_tapnum = drv_data->hs200_tx_tap; |
---|
| 338 | + if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { |
---|
| 339 | + txclk_tapnum = drv_data->hs400_tx_tap; |
---|
283 | 340 | |
---|
284 | | - extra = DLL_CMDOUT_SRC_CLK_NEG | |
---|
285 | | - DLL_CMDOUT_EN_SRC_CLK_NEG | |
---|
286 | | - DWCMSHC_EMMC_DLL_DLYENA | |
---|
287 | | - DLL_CMDOUT_TAPNUM_90_DEGREES | |
---|
288 | | - DLL_CMDOUT_TAPNUM_FROM_SW; |
---|
289 | | - sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT); |
---|
| 341 | + if (drv_data->flags & RK_DLL_CMD_OUT) { |
---|
| 342 | + extra = DLL_CMDOUT_SRC_CLK_NEG | |
---|
| 343 | + DLL_CMDOUT_BOTH_CLK_EDGE | |
---|
| 344 | + DWCMSHC_EMMC_DLL_DLYENA | |
---|
| 345 | + drv_data->hs400_cmd_tap | |
---|
| 346 | + DLL_CMDOUT_TAPNUM_FROM_SW; |
---|
| 347 | + if (drv_data->flags & RK_TAP_VALUE_SEL) |
---|
| 348 | + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; |
---|
| 349 | + sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT); |
---|
| 350 | + } |
---|
290 | 351 | } |
---|
291 | | - |
---|
292 | 352 | extra = DWCMSHC_EMMC_DLL_DLYENA | |
---|
293 | 353 | DLL_TXCLK_TAPNUM_FROM_SW | |
---|
294 | | - DLL_RXCLK_NO_INVERTER | |
---|
| 354 | + DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL | |
---|
295 | 355 | txclk_tapnum; |
---|
| 356 | + if (drv_data->flags & RK_TAP_VALUE_SEL) |
---|
| 357 | + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; |
---|
296 | 358 | sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); |
---|
297 | 359 | |
---|
298 | 360 | extra = DWCMSHC_EMMC_DLL_DLYENA | |
---|
299 | | - DLL_STRBIN_TAPNUM_DEFAULT | |
---|
| 361 | + drv_data->hs400_strbin_tap | |
---|
300 | 362 | DLL_STRBIN_TAPNUM_FROM_SW; |
---|
| 363 | + if (drv_data->flags & RK_TAP_VALUE_SEL) |
---|
| 364 | + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; |
---|
301 | 365 | sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); |
---|
| 366 | + |
---|
| 367 | +exit: |
---|
| 368 | + /* enable output clock */ |
---|
| 369 | + sdhci_enable_clk(host, 0); |
---|
302 | 370 | } |
---|
303 | 371 | |
---|
304 | | -static void rockchip_sdhci_reset(struct sdhci_host *host, u8 mask) |
---|
| 372 | +static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) |
---|
305 | 373 | { |
---|
306 | | - struct sdhci_pltfm_host *pltfm_host; |
---|
307 | | - struct dwcmshc_priv *priv; |
---|
| 374 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
| 375 | + struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); |
---|
| 376 | + struct rk35xx_priv *priv = dwc_priv->priv; |
---|
308 | 377 | |
---|
309 | | - if (mask & SDHCI_RESET_ALL) { |
---|
310 | | - pltfm_host = sdhci_priv(host); |
---|
311 | | - priv = sdhci_pltfm_priv(pltfm_host); |
---|
312 | | - if (!IS_ERR_OR_NULL(priv->reset)) { |
---|
313 | | - reset_control_assert(priv->reset); |
---|
314 | | - udelay(1); |
---|
315 | | - reset_control_deassert(priv->reset); |
---|
316 | | - } |
---|
| 378 | + if (mask & SDHCI_RESET_ALL && priv->reset) { |
---|
| 379 | + reset_control_assert(priv->reset); |
---|
| 380 | + udelay(1); |
---|
| 381 | + reset_control_deassert(priv->reset); |
---|
317 | 382 | } |
---|
318 | 383 | |
---|
319 | 384 | sdhci_reset(host, mask); |
---|
.. | .. |
---|
331 | 396 | .set_clock = sdhci_set_clock, |
---|
332 | 397 | .set_bus_width = sdhci_set_bus_width, |
---|
333 | 398 | .set_uhs_signaling = dwcmshc_set_uhs_signaling, |
---|
334 | | - .get_max_clock = sdhci_pltfm_clk_get_max_clock, |
---|
| 399 | + .get_max_clock = dwcmshc_get_max_clock, |
---|
335 | 400 | .reset = sdhci_reset, |
---|
336 | 401 | .adma_write_desc = dwcmshc_adma_write_desc, |
---|
337 | 402 | }; |
---|
338 | 403 | |
---|
339 | | -static const struct sdhci_ops sdhci_dwcmshc_rk_ops = { |
---|
340 | | - .set_clock = dwcmshc_rk_set_clock, |
---|
| 404 | +static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { |
---|
| 405 | + .set_clock = dwcmshc_rk3568_set_clock, |
---|
341 | 406 | .set_bus_width = sdhci_set_bus_width, |
---|
342 | 407 | .set_uhs_signaling = dwcmshc_set_uhs_signaling, |
---|
343 | 408 | .get_max_clock = sdhci_pltfm_clk_get_max_clock, |
---|
344 | | - .reset = rockchip_sdhci_reset, |
---|
| 409 | + .reset = rk35xx_sdhci_reset, |
---|
345 | 410 | .adma_write_desc = dwcmshc_adma_write_desc, |
---|
346 | 411 | .request_done = sdhci_dwcmshc_request_done, |
---|
347 | 412 | }; |
---|
.. | .. |
---|
352 | 417 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, |
---|
353 | 418 | }; |
---|
354 | 419 | |
---|
355 | | -static const struct sdhci_pltfm_data sdhci_dwcmshc_rk_pdata = { |
---|
356 | | - .ops = &sdhci_dwcmshc_rk_ops, |
---|
| 420 | +#ifdef CONFIG_ACPI |
---|
| 421 | +static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = { |
---|
| 422 | + .ops = &sdhci_dwcmshc_ops, |
---|
| 423 | + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, |
---|
| 424 | + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | |
---|
| 425 | + SDHCI_QUIRK2_ACMD23_BROKEN, |
---|
| 426 | +}; |
---|
| 427 | +#endif |
---|
| 428 | + |
---|
| 429 | +static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { |
---|
| 430 | + .ops = &sdhci_dwcmshc_rk35xx_ops, |
---|
357 | 431 | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, |
---|
358 | 432 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | |
---|
359 | 433 | SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, |
---|
360 | 434 | }; |
---|
| 435 | + |
---|
| 436 | +static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) |
---|
| 437 | +{ |
---|
| 438 | + int err; |
---|
| 439 | + struct rk35xx_priv *priv = dwc_priv->priv; |
---|
| 440 | + |
---|
| 441 | + priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc)); |
---|
| 442 | + if (IS_ERR(priv->reset)) { |
---|
| 443 | + err = PTR_ERR(priv->reset); |
---|
| 444 | + dev_err(mmc_dev(host->mmc), "failed to get reset control %d\n", err); |
---|
| 445 | + return err; |
---|
| 446 | + } |
---|
| 447 | + |
---|
| 448 | + priv->rockchip_clks[0].id = "axi"; |
---|
| 449 | + priv->rockchip_clks[1].id = "block"; |
---|
| 450 | + priv->rockchip_clks[2].id = "timer"; |
---|
| 451 | + err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK35xx_MAX_CLKS, |
---|
| 452 | + priv->rockchip_clks); |
---|
| 453 | + if (err) { |
---|
| 454 | + dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err); |
---|
| 455 | + return err; |
---|
| 456 | + } |
---|
| 457 | + |
---|
| 458 | + err = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, priv->rockchip_clks); |
---|
| 459 | + if (err) { |
---|
| 460 | + dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err); |
---|
| 461 | + return err; |
---|
| 462 | + } |
---|
| 463 | + |
---|
| 464 | + if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum", |
---|
| 465 | + &priv->txclk_tapnum)) |
---|
| 466 | + priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; |
---|
| 467 | + |
---|
| 468 | + /* Disable cmd conflict check */ |
---|
| 469 | + sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3); |
---|
| 470 | + /* Reset previous settings */ |
---|
| 471 | + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); |
---|
| 472 | + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); |
---|
| 473 | + |
---|
| 474 | + return 0; |
---|
| 475 | +} |
---|
| 476 | + |
---|
| 477 | +static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) |
---|
| 478 | +{ |
---|
| 479 | + /* |
---|
| 480 | + * Don't support highspeed bus mode with low clk speed as we |
---|
| 481 | + * cannot use DLL for this condition. |
---|
| 482 | + */ |
---|
| 483 | + if (host->mmc->f_max <= 52000000) { |
---|
| 484 | + dev_info(mmc_dev(host->mmc), "Disabling HS200/HS400, frequency too low (%d)\n", |
---|
| 485 | + host->mmc->f_max); |
---|
| 486 | + host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400); |
---|
| 487 | + host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR); |
---|
| 488 | + } |
---|
| 489 | +} |
---|
361 | 490 | |
---|
362 | 491 | static const struct dwcmshc_driver_data dwcmshc_drvdata = { |
---|
363 | 492 | .pdata = &sdhci_dwcmshc_pdata, |
---|
.. | .. |
---|
365 | 494 | }; |
---|
366 | 495 | |
---|
367 | 496 | static const struct dwcmshc_driver_data rk3568_drvdata = { |
---|
368 | | - .pdata = &sdhci_dwcmshc_rk_pdata, |
---|
| 497 | + .pdata = &sdhci_dwcmshc_rk35xx_pdata, |
---|
369 | 498 | .flags = RK_PLATFROM | RK_RXCLK_NO_INVERTER, |
---|
| 499 | + .hs200_tx_tap = 16, |
---|
| 500 | + .hs400_tx_tap = 8, |
---|
| 501 | + .hs400_cmd_tap = 8, |
---|
| 502 | + .hs400_strbin_tap = 4, |
---|
| 503 | + .ddr50_strbin_delay_num = 16, |
---|
370 | 504 | }; |
---|
371 | 505 | |
---|
372 | 506 | static const struct dwcmshc_driver_data rk3588_drvdata = { |
---|
373 | | - .pdata = &sdhci_dwcmshc_rk_pdata, |
---|
| 507 | + .pdata = &sdhci_dwcmshc_rk35xx_pdata, |
---|
374 | 508 | .flags = RK_PLATFROM | RK_DLL_CMD_OUT, |
---|
| 509 | + .hs200_tx_tap = 16, |
---|
| 510 | + .hs400_tx_tap = 9, |
---|
| 511 | + .hs400_cmd_tap = 8, |
---|
| 512 | + .hs400_strbin_tap = 4, |
---|
| 513 | + .ddr50_strbin_delay_num = 16, |
---|
375 | 514 | }; |
---|
376 | 515 | |
---|
377 | | -static int rockchip_pltf_init(struct sdhci_host *host, struct dwcmshc_priv *priv) |
---|
378 | | -{ |
---|
379 | | - int err; |
---|
| 516 | +static const struct dwcmshc_driver_data rk3528_drvdata = { |
---|
| 517 | + .pdata = &sdhci_dwcmshc_rk35xx_pdata, |
---|
| 518 | + .flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, |
---|
| 519 | + .hs200_tx_tap = 12, |
---|
| 520 | + .hs400_tx_tap = 6, |
---|
| 521 | + .hs400_cmd_tap = 6, |
---|
| 522 | + .hs400_strbin_tap = 3, |
---|
| 523 | + .ddr50_strbin_delay_num = 10, |
---|
| 524 | +}; |
---|
380 | 525 | |
---|
381 | | - priv->rockchip_clks[0].id = "axi"; |
---|
382 | | - priv->rockchip_clks[1].id = "block"; |
---|
383 | | - priv->rockchip_clks[2].id = "timer"; |
---|
384 | | - err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), ROCKCHIP_MAX_CLKS, |
---|
385 | | - priv->rockchip_clks); |
---|
386 | | - if (err) { |
---|
387 | | - dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err); |
---|
388 | | - return err; |
---|
389 | | - } |
---|
390 | | - |
---|
391 | | - err = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
---|
392 | | - if (err) { |
---|
393 | | - dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err); |
---|
394 | | - return err; |
---|
395 | | - } |
---|
396 | | - |
---|
397 | | - if (of_property_read_u32(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum", |
---|
398 | | - &priv->txclk_tapnum)) |
---|
399 | | - priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; |
---|
400 | | - |
---|
401 | | - /* Disable cmd conflict check */ |
---|
402 | | - sdhci_writel(host, 0x0, DWCMSHC_HOST_CTRL3); |
---|
403 | | - /* Reset previous settings */ |
---|
404 | | - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); |
---|
405 | | - sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); |
---|
406 | | - |
---|
407 | | - /* |
---|
408 | | - * Don't support highspeed bus mode with low clk speed as we |
---|
409 | | - * cannot use DLL for this condition. |
---|
410 | | - */ |
---|
411 | | - if (host->mmc->f_max <= 52000000) { |
---|
412 | | - host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400); |
---|
413 | | - host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR); |
---|
414 | | - } |
---|
415 | | - |
---|
416 | | - return 0; |
---|
417 | | -} |
---|
| 526 | +static const struct dwcmshc_driver_data rk3562_drvdata = { |
---|
| 527 | + .pdata = &sdhci_dwcmshc_rk35xx_pdata, |
---|
| 528 | + .flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, |
---|
| 529 | + .hs200_tx_tap = 12, |
---|
| 530 | + .hs400_tx_tap = 6, |
---|
| 531 | + .hs400_cmd_tap = 6, |
---|
| 532 | + .hs400_strbin_tap = 3, |
---|
| 533 | + .ddr50_strbin_delay_num = 10, |
---|
| 534 | +}; |
---|
418 | 535 | |
---|
419 | 536 | static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { |
---|
420 | | - { |
---|
421 | | - .compatible = "snps,dwcmshc-sdhci", |
---|
422 | | - .data = &dwcmshc_drvdata, |
---|
423 | | - }, |
---|
424 | | - { |
---|
425 | | - .compatible = "rockchip,dwcmshc-sdhci", |
---|
426 | | - .data = &rk3568_drvdata, |
---|
427 | | - }, |
---|
428 | 537 | { |
---|
429 | 538 | .compatible = "rockchip,rk3588-dwcmshc", |
---|
430 | 539 | .data = &rk3588_drvdata, |
---|
431 | 540 | }, |
---|
| 541 | + { |
---|
| 542 | + .compatible = "rockchip,rk3568-dwcmshc", |
---|
| 543 | + .data = &rk3568_drvdata, |
---|
| 544 | + }, |
---|
| 545 | + { |
---|
| 546 | + .compatible = "rockchip,rk3528-dwcmshc", |
---|
| 547 | + .data = &rk3528_drvdata, |
---|
| 548 | + }, |
---|
| 549 | + { |
---|
| 550 | + .compatible = "rockchip,rk3562-dwcmshc", |
---|
| 551 | + .data = &rk3562_drvdata, |
---|
| 552 | + }, |
---|
| 553 | + { |
---|
| 554 | + .compatible = "snps,dwcmshc-sdhci", |
---|
| 555 | + .data = &dwcmshc_drvdata, |
---|
| 556 | + }, |
---|
432 | 557 | {}, |
---|
433 | 558 | }; |
---|
| 559 | +MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); |
---|
| 560 | + |
---|
| 561 | +#ifdef CONFIG_ACPI |
---|
| 562 | +static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = { |
---|
| 563 | + { |
---|
| 564 | + .id = "MLNXBF30", |
---|
| 565 | + .driver_data = (kernel_ulong_t)&sdhci_dwcmshc_bf3_pdata, |
---|
| 566 | + }, |
---|
| 567 | + {} |
---|
| 568 | +}; |
---|
| 569 | +#endif |
---|
434 | 570 | |
---|
435 | 571 | static int dwcmshc_probe(struct platform_device *pdev) |
---|
436 | 572 | { |
---|
| 573 | + struct device *dev = &pdev->dev; |
---|
437 | 574 | struct sdhci_pltfm_host *pltfm_host; |
---|
438 | 575 | struct sdhci_host *host; |
---|
439 | 576 | struct dwcmshc_priv *priv; |
---|
| 577 | + struct rk35xx_priv *rk_priv = NULL; |
---|
| 578 | + const struct sdhci_pltfm_data *pltfm_data; |
---|
440 | 579 | const struct dwcmshc_driver_data *drv_data; |
---|
441 | 580 | struct mmc_hsq *hsq; |
---|
442 | 581 | int err; |
---|
.. | .. |
---|
447 | 586 | dev_err(&pdev->dev, "Error: No device match data found\n"); |
---|
448 | 587 | return -ENODEV; |
---|
449 | 588 | } |
---|
| 589 | + pltfm_data = drv_data->pdata; |
---|
450 | 590 | |
---|
451 | | - host = sdhci_pltfm_init(pdev, drv_data->pdata, |
---|
| 591 | + host = sdhci_pltfm_init(pdev, pltfm_data, |
---|
452 | 592 | sizeof(struct dwcmshc_priv)); |
---|
453 | 593 | if (IS_ERR(host)) |
---|
454 | 594 | return PTR_ERR(host); |
---|
.. | .. |
---|
456 | 596 | /* |
---|
457 | 597 | * extra adma table cnt for cross 128M boundary handling. |
---|
458 | 598 | */ |
---|
459 | | - extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); |
---|
| 599 | + extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M); |
---|
460 | 600 | if (extra > SDHCI_MAX_SEGS) |
---|
461 | 601 | extra = SDHCI_MAX_SEGS; |
---|
462 | 602 | host->adma_table_cnt += extra; |
---|
.. | .. |
---|
464 | 604 | pltfm_host = sdhci_priv(host); |
---|
465 | 605 | priv = sdhci_pltfm_priv(pltfm_host); |
---|
466 | 606 | |
---|
467 | | - priv->reset = devm_reset_control_array_get_exclusive(&pdev->dev); |
---|
468 | | - pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); |
---|
469 | | - if (IS_ERR(pltfm_host->clk)) { |
---|
470 | | - err = PTR_ERR(pltfm_host->clk); |
---|
471 | | - dev_err(&pdev->dev, "failed to get core clk: %d\n", err); |
---|
472 | | - goto free_pltfm; |
---|
473 | | - } |
---|
474 | | - err = clk_prepare_enable(pltfm_host->clk); |
---|
475 | | - if (err) |
---|
476 | | - goto free_pltfm; |
---|
| 607 | + if (dev->of_node) { |
---|
| 608 | + pltfm_host->clk = devm_clk_get(dev, "core"); |
---|
| 609 | + if (IS_ERR(pltfm_host->clk)) { |
---|
| 610 | + err = PTR_ERR(pltfm_host->clk); |
---|
| 611 | + dev_err(dev, "failed to get core clk: %d\n", err); |
---|
| 612 | + goto free_pltfm; |
---|
| 613 | + } |
---|
| 614 | + err = clk_prepare_enable(pltfm_host->clk); |
---|
| 615 | + if (err) |
---|
| 616 | + goto free_pltfm; |
---|
477 | 617 | |
---|
478 | | - priv->bus_clk = devm_clk_get(&pdev->dev, "bus"); |
---|
479 | | - if (!IS_ERR(priv->bus_clk)) |
---|
480 | | - clk_prepare_enable(priv->bus_clk); |
---|
| 618 | + priv->bus_clk = devm_clk_get(dev, "bus"); |
---|
| 619 | + if (!IS_ERR(priv->bus_clk)) |
---|
| 620 | + clk_prepare_enable(priv->bus_clk); |
---|
| 621 | + } |
---|
481 | 622 | |
---|
482 | 623 | err = mmc_of_parse(host->mmc); |
---|
483 | 624 | if (err) |
---|
484 | 625 | goto err_clk; |
---|
485 | 626 | |
---|
486 | 627 | sdhci_get_of_property(pdev); |
---|
| 628 | + |
---|
| 629 | + priv->vendor_specific_area1 = |
---|
| 630 | + sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK; |
---|
487 | 631 | |
---|
488 | 632 | host->mmc_host_ops.request = dwcmshc_request; |
---|
489 | 633 | host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; |
---|
.. | .. |
---|
498 | 642 | if (err) |
---|
499 | 643 | goto err_clk; |
---|
500 | 644 | |
---|
501 | | - err = sdhci_add_host(host); |
---|
502 | | - if (err) |
---|
503 | | - goto err_clk; |
---|
504 | | - |
---|
505 | | - priv->flags = drv_data->flags; |
---|
506 | 645 | if (drv_data->flags & RK_PLATFROM) { |
---|
507 | | - err = rockchip_pltf_init(host, priv); |
---|
| 646 | + rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL); |
---|
| 647 | + if (!rk_priv) { |
---|
| 648 | + err = -ENOMEM; |
---|
| 649 | + goto err_clk; |
---|
| 650 | + } |
---|
| 651 | + |
---|
| 652 | + rk_priv->drv_data = drv_data; |
---|
| 653 | + rk_priv->acpi_en = has_acpi_companion(&pdev->dev); |
---|
| 654 | + |
---|
| 655 | + if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3588-dwcmshc")) |
---|
| 656 | + rk_priv->devtype = DWCMSHC_RK3588; |
---|
| 657 | + else |
---|
| 658 | + rk_priv->devtype = DWCMSHC_RK3568; |
---|
| 659 | + |
---|
| 660 | + priv->priv = rk_priv; |
---|
| 661 | + |
---|
| 662 | + err = dwcmshc_rk35xx_init(host, priv); |
---|
508 | 663 | if (err) |
---|
509 | 664 | goto err_clk; |
---|
510 | 665 | } |
---|
511 | 666 | |
---|
512 | | - pm_runtime_get_noresume(&pdev->dev); |
---|
513 | | - pm_runtime_set_active(&pdev->dev); |
---|
514 | | - pm_runtime_enable(&pdev->dev); |
---|
515 | | - pm_runtime_set_autosuspend_delay(&pdev->dev, 50); |
---|
516 | | - pm_runtime_use_autosuspend(&pdev->dev); |
---|
517 | | - pm_runtime_put_autosuspend(&pdev->dev); |
---|
| 667 | + host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; |
---|
| 668 | + |
---|
| 669 | + err = sdhci_setup_host(host); |
---|
| 670 | + if (err) |
---|
| 671 | + goto err_clk; |
---|
| 672 | + |
---|
| 673 | + if (rk_priv) |
---|
| 674 | + dwcmshc_rk35xx_postinit(host, priv); |
---|
| 675 | + |
---|
| 676 | + err = __sdhci_add_host(host); |
---|
| 677 | + if (err) |
---|
| 678 | + goto err_setup_host; |
---|
| 679 | + |
---|
| 680 | + if (rk_priv && !rk_priv->acpi_en) { |
---|
| 681 | + pm_runtime_get_noresume(&pdev->dev); |
---|
| 682 | + pm_runtime_set_active(&pdev->dev); |
---|
| 683 | + pm_runtime_enable(&pdev->dev); |
---|
| 684 | + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); |
---|
| 685 | + pm_runtime_use_autosuspend(&pdev->dev); |
---|
| 686 | + pm_runtime_put_autosuspend(&pdev->dev); |
---|
| 687 | + } |
---|
518 | 688 | |
---|
519 | 689 | return 0; |
---|
520 | 690 | |
---|
| 691 | +err_setup_host: |
---|
| 692 | + sdhci_cleanup_host(host); |
---|
521 | 693 | err_clk: |
---|
522 | 694 | clk_disable_unprepare(pltfm_host->clk); |
---|
523 | 695 | clk_disable_unprepare(priv->bus_clk); |
---|
524 | | - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
---|
| 696 | + if (rk_priv) |
---|
| 697 | + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, |
---|
| 698 | + rk_priv->rockchip_clks); |
---|
525 | 699 | free_pltfm: |
---|
526 | 700 | sdhci_pltfm_free(pdev); |
---|
527 | 701 | return err; |
---|
.. | .. |
---|
532 | 706 | struct sdhci_host *host = platform_get_drvdata(pdev); |
---|
533 | 707 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
534 | 708 | struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
---|
| 709 | + struct rk35xx_priv *rk_priv = priv->priv; |
---|
535 | 710 | |
---|
536 | 711 | sdhci_remove_host(host, 0); |
---|
537 | 712 | |
---|
538 | 713 | clk_disable_unprepare(pltfm_host->clk); |
---|
539 | 714 | clk_disable_unprepare(priv->bus_clk); |
---|
540 | | - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
---|
541 | | - |
---|
| 715 | + if (rk_priv) |
---|
| 716 | + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, |
---|
| 717 | + rk_priv->rockchip_clks); |
---|
542 | 718 | sdhci_pltfm_free(pdev); |
---|
543 | 719 | |
---|
544 | 720 | return 0; |
---|
.. | .. |
---|
550 | 726 | struct sdhci_host *host = dev_get_drvdata(dev); |
---|
551 | 727 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
552 | 728 | struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
---|
| 729 | + struct rk35xx_priv *rk_priv = priv->priv; |
---|
553 | 730 | int ret; |
---|
554 | 731 | |
---|
555 | 732 | mmc_hsq_suspend(host->mmc); |
---|
.. | .. |
---|
562 | 739 | if (!IS_ERR(priv->bus_clk)) |
---|
563 | 740 | clk_disable_unprepare(priv->bus_clk); |
---|
564 | 741 | |
---|
565 | | - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
---|
| 742 | + if (rk_priv) |
---|
| 743 | + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, |
---|
| 744 | + rk_priv->rockchip_clks); |
---|
| 745 | + |
---|
566 | 746 | return ret; |
---|
567 | 747 | } |
---|
568 | 748 | |
---|
.. | .. |
---|
571 | 751 | struct sdhci_host *host = dev_get_drvdata(dev); |
---|
572 | 752 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
---|
573 | 753 | struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
---|
| 754 | + struct rk35xx_priv *rk_priv = priv->priv; |
---|
574 | 755 | int ret; |
---|
575 | 756 | |
---|
576 | 757 | ret = clk_prepare_enable(pltfm_host->clk); |
---|
.. | .. |
---|
583 | 764 | return ret; |
---|
584 | 765 | } |
---|
585 | 766 | |
---|
586 | | - ret = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
---|
587 | | - if (ret) |
---|
588 | | - return ret; |
---|
| 767 | + if (rk_priv) { |
---|
| 768 | + ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, |
---|
| 769 | + rk_priv->rockchip_clks); |
---|
| 770 | + if (ret) |
---|
| 771 | + return ret; |
---|
| 772 | + } |
---|
589 | 773 | |
---|
590 | 774 | ret = sdhci_resume_host(host); |
---|
591 | 775 | if (ret) |
---|
.. | .. |
---|
623 | 807 | SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume) |
---|
624 | 808 | SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend, dwcmshc_runtime_resume, NULL) |
---|
625 | 809 | }; |
---|
626 | | -MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); |
---|
627 | 810 | |
---|
628 | 811 | static struct platform_driver sdhci_dwcmshc_driver = { |
---|
629 | 812 | .driver = { |
---|
630 | 813 | .name = "sdhci-dwcmshc", |
---|
631 | 814 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
---|
632 | 815 | .of_match_table = sdhci_dwcmshc_dt_ids, |
---|
| 816 | + .acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids), |
---|
633 | 817 | .pm = &dwcmshc_pmops, |
---|
634 | 818 | }, |
---|
635 | 819 | .probe = dwcmshc_probe, |
---|