| .. | .. |
|---|
| 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) && |
|---|
| 337 | + txclk_tapnum = drv_data->hs200_tx_tap; |
|---|
| 338 | + if ((drv_data->flags & RK_DLL_CMD_OUT) && |
|---|
| 281 | 339 | host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { |
|---|
| 282 | | - txclk_tapnum = DLL_TXCLK_TAPNUM_90_DEGREES; |
|---|
| 283 | | - |
|---|
| 340 | + txclk_tapnum = drv_data->hs400_tx_tap; |
|---|
| 284 | 341 | extra = DLL_CMDOUT_SRC_CLK_NEG | |
|---|
| 285 | | - DLL_CMDOUT_EN_SRC_CLK_NEG | |
|---|
| 342 | + DLL_CMDOUT_BOTH_CLK_EDGE | |
|---|
| 286 | 343 | DWCMSHC_EMMC_DLL_DLYENA | |
|---|
| 287 | | - DLL_CMDOUT_TAPNUM_90_DEGREES | |
|---|
| 344 | + drv_data->hs400_cmd_tap | |
|---|
| 288 | 345 | DLL_CMDOUT_TAPNUM_FROM_SW; |
|---|
| 346 | + if (drv_data->flags & RK_TAP_VALUE_SEL) |
|---|
| 347 | + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; |
|---|
| 289 | 348 | sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT); |
|---|
| 290 | 349 | } |
|---|
| 291 | | - |
|---|
| 292 | 350 | extra = DWCMSHC_EMMC_DLL_DLYENA | |
|---|
| 293 | 351 | DLL_TXCLK_TAPNUM_FROM_SW | |
|---|
| 294 | | - DLL_RXCLK_NO_INVERTER | |
|---|
| 352 | + DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL | |
|---|
| 295 | 353 | txclk_tapnum; |
|---|
| 354 | + if (drv_data->flags & RK_TAP_VALUE_SEL) |
|---|
| 355 | + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; |
|---|
| 296 | 356 | sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); |
|---|
| 297 | 357 | |
|---|
| 298 | 358 | extra = DWCMSHC_EMMC_DLL_DLYENA | |
|---|
| 299 | | - DLL_STRBIN_TAPNUM_DEFAULT | |
|---|
| 359 | + drv_data->hs400_strbin_tap | |
|---|
| 300 | 360 | DLL_STRBIN_TAPNUM_FROM_SW; |
|---|
| 361 | + if (drv_data->flags & RK_TAP_VALUE_SEL) |
|---|
| 362 | + extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET; |
|---|
| 301 | 363 | sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); |
|---|
| 364 | + |
|---|
| 365 | +exit: |
|---|
| 366 | + /* enable output clock */ |
|---|
| 367 | + sdhci_enable_clk(host, 0); |
|---|
| 302 | 368 | } |
|---|
| 303 | 369 | |
|---|
| 304 | | -static void rockchip_sdhci_reset(struct sdhci_host *host, u8 mask) |
|---|
| 370 | +static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) |
|---|
| 305 | 371 | { |
|---|
| 306 | | - struct sdhci_pltfm_host *pltfm_host; |
|---|
| 307 | | - struct dwcmshc_priv *priv; |
|---|
| 372 | + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
|---|
| 373 | + struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host); |
|---|
| 374 | + struct rk35xx_priv *priv = dwc_priv->priv; |
|---|
| 308 | 375 | |
|---|
| 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 | | - } |
|---|
| 376 | + if (mask & SDHCI_RESET_ALL && priv->reset) { |
|---|
| 377 | + reset_control_assert(priv->reset); |
|---|
| 378 | + udelay(1); |
|---|
| 379 | + reset_control_deassert(priv->reset); |
|---|
| 317 | 380 | } |
|---|
| 318 | 381 | |
|---|
| 319 | 382 | sdhci_reset(host, mask); |
|---|
| .. | .. |
|---|
| 331 | 394 | .set_clock = sdhci_set_clock, |
|---|
| 332 | 395 | .set_bus_width = sdhci_set_bus_width, |
|---|
| 333 | 396 | .set_uhs_signaling = dwcmshc_set_uhs_signaling, |
|---|
| 334 | | - .get_max_clock = sdhci_pltfm_clk_get_max_clock, |
|---|
| 397 | + .get_max_clock = dwcmshc_get_max_clock, |
|---|
| 335 | 398 | .reset = sdhci_reset, |
|---|
| 336 | 399 | .adma_write_desc = dwcmshc_adma_write_desc, |
|---|
| 337 | 400 | }; |
|---|
| 338 | 401 | |
|---|
| 339 | | -static const struct sdhci_ops sdhci_dwcmshc_rk_ops = { |
|---|
| 340 | | - .set_clock = dwcmshc_rk_set_clock, |
|---|
| 402 | +static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { |
|---|
| 403 | + .set_clock = dwcmshc_rk3568_set_clock, |
|---|
| 341 | 404 | .set_bus_width = sdhci_set_bus_width, |
|---|
| 342 | 405 | .set_uhs_signaling = dwcmshc_set_uhs_signaling, |
|---|
| 343 | 406 | .get_max_clock = sdhci_pltfm_clk_get_max_clock, |
|---|
| 344 | | - .reset = rockchip_sdhci_reset, |
|---|
| 407 | + .reset = rk35xx_sdhci_reset, |
|---|
| 345 | 408 | .adma_write_desc = dwcmshc_adma_write_desc, |
|---|
| 346 | 409 | .request_done = sdhci_dwcmshc_request_done, |
|---|
| 347 | 410 | }; |
|---|
| .. | .. |
|---|
| 352 | 415 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, |
|---|
| 353 | 416 | }; |
|---|
| 354 | 417 | |
|---|
| 355 | | -static const struct sdhci_pltfm_data sdhci_dwcmshc_rk_pdata = { |
|---|
| 356 | | - .ops = &sdhci_dwcmshc_rk_ops, |
|---|
| 418 | +#ifdef CONFIG_ACPI |
|---|
| 419 | +static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = { |
|---|
| 420 | + .ops = &sdhci_dwcmshc_ops, |
|---|
| 421 | + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, |
|---|
| 422 | + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | |
|---|
| 423 | + SDHCI_QUIRK2_ACMD23_BROKEN, |
|---|
| 424 | +}; |
|---|
| 425 | +#endif |
|---|
| 426 | + |
|---|
| 427 | +static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { |
|---|
| 428 | + .ops = &sdhci_dwcmshc_rk35xx_ops, |
|---|
| 357 | 429 | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, |
|---|
| 358 | 430 | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | |
|---|
| 359 | 431 | SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, |
|---|
| 360 | 432 | }; |
|---|
| 433 | + |
|---|
| 434 | +static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) |
|---|
| 435 | +{ |
|---|
| 436 | + int err; |
|---|
| 437 | + struct rk35xx_priv *priv = dwc_priv->priv; |
|---|
| 438 | + |
|---|
| 439 | + priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc)); |
|---|
| 440 | + if (IS_ERR(priv->reset)) { |
|---|
| 441 | + err = PTR_ERR(priv->reset); |
|---|
| 442 | + dev_err(mmc_dev(host->mmc), "failed to get reset control %d\n", err); |
|---|
| 443 | + return err; |
|---|
| 444 | + } |
|---|
| 445 | + |
|---|
| 446 | + priv->rockchip_clks[0].id = "axi"; |
|---|
| 447 | + priv->rockchip_clks[1].id = "block"; |
|---|
| 448 | + priv->rockchip_clks[2].id = "timer"; |
|---|
| 449 | + err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK35xx_MAX_CLKS, |
|---|
| 450 | + priv->rockchip_clks); |
|---|
| 451 | + if (err) { |
|---|
| 452 | + dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err); |
|---|
| 453 | + return err; |
|---|
| 454 | + } |
|---|
| 455 | + |
|---|
| 456 | + err = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, priv->rockchip_clks); |
|---|
| 457 | + if (err) { |
|---|
| 458 | + dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err); |
|---|
| 459 | + return err; |
|---|
| 460 | + } |
|---|
| 461 | + |
|---|
| 462 | + if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum", |
|---|
| 463 | + &priv->txclk_tapnum)) |
|---|
| 464 | + priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT; |
|---|
| 465 | + |
|---|
| 466 | + /* Disable cmd conflict check */ |
|---|
| 467 | + sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3); |
|---|
| 468 | + /* Reset previous settings */ |
|---|
| 469 | + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK); |
|---|
| 470 | + sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN); |
|---|
| 471 | + |
|---|
| 472 | + return 0; |
|---|
| 473 | +} |
|---|
| 474 | + |
|---|
| 475 | +static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) |
|---|
| 476 | +{ |
|---|
| 477 | + /* |
|---|
| 478 | + * Don't support highspeed bus mode with low clk speed as we |
|---|
| 479 | + * cannot use DLL for this condition. |
|---|
| 480 | + */ |
|---|
| 481 | + if (host->mmc->f_max <= 52000000) { |
|---|
| 482 | + dev_info(mmc_dev(host->mmc), "Disabling HS200/HS400, frequency too low (%d)\n", |
|---|
| 483 | + host->mmc->f_max); |
|---|
| 484 | + host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400); |
|---|
| 485 | + host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR); |
|---|
| 486 | + } |
|---|
| 487 | +} |
|---|
| 361 | 488 | |
|---|
| 362 | 489 | static const struct dwcmshc_driver_data dwcmshc_drvdata = { |
|---|
| 363 | 490 | .pdata = &sdhci_dwcmshc_pdata, |
|---|
| .. | .. |
|---|
| 365 | 492 | }; |
|---|
| 366 | 493 | |
|---|
| 367 | 494 | static const struct dwcmshc_driver_data rk3568_drvdata = { |
|---|
| 368 | | - .pdata = &sdhci_dwcmshc_rk_pdata, |
|---|
| 495 | + .pdata = &sdhci_dwcmshc_rk35xx_pdata, |
|---|
| 369 | 496 | .flags = RK_PLATFROM | RK_RXCLK_NO_INVERTER, |
|---|
| 497 | + .hs200_tx_tap = 16, |
|---|
| 498 | + .hs400_tx_tap = 8, |
|---|
| 499 | + .hs400_cmd_tap = 8, |
|---|
| 500 | + .hs400_strbin_tap = 4, |
|---|
| 501 | + .ddr50_strbin_delay_num = 16, |
|---|
| 370 | 502 | }; |
|---|
| 371 | 503 | |
|---|
| 372 | 504 | static const struct dwcmshc_driver_data rk3588_drvdata = { |
|---|
| 373 | | - .pdata = &sdhci_dwcmshc_rk_pdata, |
|---|
| 505 | + .pdata = &sdhci_dwcmshc_rk35xx_pdata, |
|---|
| 374 | 506 | .flags = RK_PLATFROM | RK_DLL_CMD_OUT, |
|---|
| 507 | + .hs200_tx_tap = 16, |
|---|
| 508 | + .hs400_tx_tap = 9, |
|---|
| 509 | + .hs400_cmd_tap = 8, |
|---|
| 510 | + .hs400_strbin_tap = 4, |
|---|
| 511 | + .ddr50_strbin_delay_num = 16, |
|---|
| 375 | 512 | }; |
|---|
| 376 | 513 | |
|---|
| 377 | | -static int rockchip_pltf_init(struct sdhci_host *host, struct dwcmshc_priv *priv) |
|---|
| 378 | | -{ |
|---|
| 379 | | - int err; |
|---|
| 514 | +static const struct dwcmshc_driver_data rk3528_drvdata = { |
|---|
| 515 | + .pdata = &sdhci_dwcmshc_rk35xx_pdata, |
|---|
| 516 | + .flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, |
|---|
| 517 | + .hs200_tx_tap = 12, |
|---|
| 518 | + .hs400_tx_tap = 6, |
|---|
| 519 | + .hs400_cmd_tap = 6, |
|---|
| 520 | + .hs400_strbin_tap = 3, |
|---|
| 521 | + .ddr50_strbin_delay_num = 10, |
|---|
| 522 | +}; |
|---|
| 380 | 523 | |
|---|
| 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 | | -} |
|---|
| 524 | +static const struct dwcmshc_driver_data rk3562_drvdata = { |
|---|
| 525 | + .pdata = &sdhci_dwcmshc_rk35xx_pdata, |
|---|
| 526 | + .flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL, |
|---|
| 527 | + .hs200_tx_tap = 12, |
|---|
| 528 | + .hs400_tx_tap = 6, |
|---|
| 529 | + .hs400_cmd_tap = 6, |
|---|
| 530 | + .hs400_strbin_tap = 3, |
|---|
| 531 | + .ddr50_strbin_delay_num = 10, |
|---|
| 532 | +}; |
|---|
| 418 | 533 | |
|---|
| 419 | 534 | 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 | 535 | { |
|---|
| 429 | 536 | .compatible = "rockchip,rk3588-dwcmshc", |
|---|
| 430 | 537 | .data = &rk3588_drvdata, |
|---|
| 431 | 538 | }, |
|---|
| 539 | + { |
|---|
| 540 | + .compatible = "rockchip,rk3568-dwcmshc", |
|---|
| 541 | + .data = &rk3568_drvdata, |
|---|
| 542 | + }, |
|---|
| 543 | + { |
|---|
| 544 | + .compatible = "rockchip,rk3528-dwcmshc", |
|---|
| 545 | + .data = &rk3528_drvdata, |
|---|
| 546 | + }, |
|---|
| 547 | + { |
|---|
| 548 | + .compatible = "rockchip,rk3562-dwcmshc", |
|---|
| 549 | + .data = &rk3562_drvdata, |
|---|
| 550 | + }, |
|---|
| 551 | + { |
|---|
| 552 | + .compatible = "snps,dwcmshc-sdhci", |
|---|
| 553 | + .data = &dwcmshc_drvdata, |
|---|
| 554 | + }, |
|---|
| 432 | 555 | {}, |
|---|
| 433 | 556 | }; |
|---|
| 557 | +MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); |
|---|
| 558 | + |
|---|
| 559 | +#ifdef CONFIG_ACPI |
|---|
| 560 | +static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = { |
|---|
| 561 | + { |
|---|
| 562 | + .id = "MLNXBF30", |
|---|
| 563 | + .driver_data = (kernel_ulong_t)&sdhci_dwcmshc_bf3_pdata, |
|---|
| 564 | + }, |
|---|
| 565 | + {} |
|---|
| 566 | +}; |
|---|
| 567 | +#endif |
|---|
| 434 | 568 | |
|---|
| 435 | 569 | static int dwcmshc_probe(struct platform_device *pdev) |
|---|
| 436 | 570 | { |
|---|
| 571 | + struct device *dev = &pdev->dev; |
|---|
| 437 | 572 | struct sdhci_pltfm_host *pltfm_host; |
|---|
| 438 | 573 | struct sdhci_host *host; |
|---|
| 439 | 574 | struct dwcmshc_priv *priv; |
|---|
| 575 | + struct rk35xx_priv *rk_priv = NULL; |
|---|
| 576 | + const struct sdhci_pltfm_data *pltfm_data; |
|---|
| 440 | 577 | const struct dwcmshc_driver_data *drv_data; |
|---|
| 441 | 578 | struct mmc_hsq *hsq; |
|---|
| 442 | 579 | int err; |
|---|
| .. | .. |
|---|
| 447 | 584 | dev_err(&pdev->dev, "Error: No device match data found\n"); |
|---|
| 448 | 585 | return -ENODEV; |
|---|
| 449 | 586 | } |
|---|
| 587 | + pltfm_data = drv_data->pdata; |
|---|
| 450 | 588 | |
|---|
| 451 | | - host = sdhci_pltfm_init(pdev, drv_data->pdata, |
|---|
| 589 | + host = sdhci_pltfm_init(pdev, pltfm_data, |
|---|
| 452 | 590 | sizeof(struct dwcmshc_priv)); |
|---|
| 453 | 591 | if (IS_ERR(host)) |
|---|
| 454 | 592 | return PTR_ERR(host); |
|---|
| .. | .. |
|---|
| 456 | 594 | /* |
|---|
| 457 | 595 | * extra adma table cnt for cross 128M boundary handling. |
|---|
| 458 | 596 | */ |
|---|
| 459 | | - extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M); |
|---|
| 597 | + extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M); |
|---|
| 460 | 598 | if (extra > SDHCI_MAX_SEGS) |
|---|
| 461 | 599 | extra = SDHCI_MAX_SEGS; |
|---|
| 462 | 600 | host->adma_table_cnt += extra; |
|---|
| .. | .. |
|---|
| 464 | 602 | pltfm_host = sdhci_priv(host); |
|---|
| 465 | 603 | priv = sdhci_pltfm_priv(pltfm_host); |
|---|
| 466 | 604 | |
|---|
| 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; |
|---|
| 605 | + if (dev->of_node) { |
|---|
| 606 | + pltfm_host->clk = devm_clk_get(dev, "core"); |
|---|
| 607 | + if (IS_ERR(pltfm_host->clk)) { |
|---|
| 608 | + err = PTR_ERR(pltfm_host->clk); |
|---|
| 609 | + dev_err(dev, "failed to get core clk: %d\n", err); |
|---|
| 610 | + goto free_pltfm; |
|---|
| 611 | + } |
|---|
| 612 | + err = clk_prepare_enable(pltfm_host->clk); |
|---|
| 613 | + if (err) |
|---|
| 614 | + goto free_pltfm; |
|---|
| 477 | 615 | |
|---|
| 478 | | - priv->bus_clk = devm_clk_get(&pdev->dev, "bus"); |
|---|
| 479 | | - if (!IS_ERR(priv->bus_clk)) |
|---|
| 480 | | - clk_prepare_enable(priv->bus_clk); |
|---|
| 616 | + priv->bus_clk = devm_clk_get(dev, "bus"); |
|---|
| 617 | + if (!IS_ERR(priv->bus_clk)) |
|---|
| 618 | + clk_prepare_enable(priv->bus_clk); |
|---|
| 619 | + } |
|---|
| 481 | 620 | |
|---|
| 482 | 621 | err = mmc_of_parse(host->mmc); |
|---|
| 483 | 622 | if (err) |
|---|
| 484 | 623 | goto err_clk; |
|---|
| 485 | 624 | |
|---|
| 486 | 625 | sdhci_get_of_property(pdev); |
|---|
| 626 | + |
|---|
| 627 | + priv->vendor_specific_area1 = |
|---|
| 628 | + sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK; |
|---|
| 487 | 629 | |
|---|
| 488 | 630 | host->mmc_host_ops.request = dwcmshc_request; |
|---|
| 489 | 631 | host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe; |
|---|
| .. | .. |
|---|
| 498 | 640 | if (err) |
|---|
| 499 | 641 | goto err_clk; |
|---|
| 500 | 642 | |
|---|
| 501 | | - err = sdhci_add_host(host); |
|---|
| 502 | | - if (err) |
|---|
| 503 | | - goto err_clk; |
|---|
| 504 | | - |
|---|
| 505 | | - priv->flags = drv_data->flags; |
|---|
| 506 | 643 | if (drv_data->flags & RK_PLATFROM) { |
|---|
| 507 | | - err = rockchip_pltf_init(host, priv); |
|---|
| 644 | + rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL); |
|---|
| 645 | + if (!rk_priv) { |
|---|
| 646 | + err = -ENOMEM; |
|---|
| 647 | + goto err_clk; |
|---|
| 648 | + } |
|---|
| 649 | + |
|---|
| 650 | + rk_priv->drv_data = drv_data; |
|---|
| 651 | + rk_priv->acpi_en = has_acpi_companion(&pdev->dev); |
|---|
| 652 | + |
|---|
| 653 | + if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3588-dwcmshc")) |
|---|
| 654 | + rk_priv->devtype = DWCMSHC_RK3588; |
|---|
| 655 | + else |
|---|
| 656 | + rk_priv->devtype = DWCMSHC_RK3568; |
|---|
| 657 | + |
|---|
| 658 | + priv->priv = rk_priv; |
|---|
| 659 | + |
|---|
| 660 | + err = dwcmshc_rk35xx_init(host, priv); |
|---|
| 508 | 661 | if (err) |
|---|
| 509 | 662 | goto err_clk; |
|---|
| 510 | 663 | } |
|---|
| 511 | 664 | |
|---|
| 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); |
|---|
| 665 | + host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; |
|---|
| 666 | + |
|---|
| 667 | + err = sdhci_setup_host(host); |
|---|
| 668 | + if (err) |
|---|
| 669 | + goto err_clk; |
|---|
| 670 | + |
|---|
| 671 | + if (rk_priv) |
|---|
| 672 | + dwcmshc_rk35xx_postinit(host, priv); |
|---|
| 673 | + |
|---|
| 674 | + err = __sdhci_add_host(host); |
|---|
| 675 | + if (err) |
|---|
| 676 | + goto err_setup_host; |
|---|
| 677 | + |
|---|
| 678 | + if (rk_priv && !rk_priv->acpi_en) { |
|---|
| 679 | + pm_runtime_get_noresume(&pdev->dev); |
|---|
| 680 | + pm_runtime_set_active(&pdev->dev); |
|---|
| 681 | + pm_runtime_enable(&pdev->dev); |
|---|
| 682 | + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); |
|---|
| 683 | + pm_runtime_use_autosuspend(&pdev->dev); |
|---|
| 684 | + pm_runtime_put_autosuspend(&pdev->dev); |
|---|
| 685 | + } |
|---|
| 518 | 686 | |
|---|
| 519 | 687 | return 0; |
|---|
| 520 | 688 | |
|---|
| 689 | +err_setup_host: |
|---|
| 690 | + sdhci_cleanup_host(host); |
|---|
| 521 | 691 | err_clk: |
|---|
| 522 | 692 | clk_disable_unprepare(pltfm_host->clk); |
|---|
| 523 | 693 | clk_disable_unprepare(priv->bus_clk); |
|---|
| 524 | | - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
|---|
| 694 | + if (rk_priv) |
|---|
| 695 | + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, |
|---|
| 696 | + rk_priv->rockchip_clks); |
|---|
| 525 | 697 | free_pltfm: |
|---|
| 526 | 698 | sdhci_pltfm_free(pdev); |
|---|
| 527 | 699 | return err; |
|---|
| .. | .. |
|---|
| 532 | 704 | struct sdhci_host *host = platform_get_drvdata(pdev); |
|---|
| 533 | 705 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
|---|
| 534 | 706 | struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
|---|
| 707 | + struct rk35xx_priv *rk_priv = priv->priv; |
|---|
| 535 | 708 | |
|---|
| 536 | 709 | sdhci_remove_host(host, 0); |
|---|
| 537 | 710 | |
|---|
| 538 | 711 | clk_disable_unprepare(pltfm_host->clk); |
|---|
| 539 | 712 | clk_disable_unprepare(priv->bus_clk); |
|---|
| 540 | | - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
|---|
| 541 | | - |
|---|
| 713 | + if (rk_priv) |
|---|
| 714 | + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, |
|---|
| 715 | + rk_priv->rockchip_clks); |
|---|
| 542 | 716 | sdhci_pltfm_free(pdev); |
|---|
| 543 | 717 | |
|---|
| 544 | 718 | return 0; |
|---|
| .. | .. |
|---|
| 550 | 724 | struct sdhci_host *host = dev_get_drvdata(dev); |
|---|
| 551 | 725 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
|---|
| 552 | 726 | struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
|---|
| 727 | + struct rk35xx_priv *rk_priv = priv->priv; |
|---|
| 553 | 728 | int ret; |
|---|
| 554 | 729 | |
|---|
| 555 | 730 | mmc_hsq_suspend(host->mmc); |
|---|
| .. | .. |
|---|
| 562 | 737 | if (!IS_ERR(priv->bus_clk)) |
|---|
| 563 | 738 | clk_disable_unprepare(priv->bus_clk); |
|---|
| 564 | 739 | |
|---|
| 565 | | - clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
|---|
| 740 | + if (rk_priv) |
|---|
| 741 | + clk_bulk_disable_unprepare(RK35xx_MAX_CLKS, |
|---|
| 742 | + rk_priv->rockchip_clks); |
|---|
| 743 | + |
|---|
| 566 | 744 | return ret; |
|---|
| 567 | 745 | } |
|---|
| 568 | 746 | |
|---|
| .. | .. |
|---|
| 571 | 749 | struct sdhci_host *host = dev_get_drvdata(dev); |
|---|
| 572 | 750 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
|---|
| 573 | 751 | struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); |
|---|
| 752 | + struct rk35xx_priv *rk_priv = priv->priv; |
|---|
| 574 | 753 | int ret; |
|---|
| 575 | 754 | |
|---|
| 576 | 755 | ret = clk_prepare_enable(pltfm_host->clk); |
|---|
| .. | .. |
|---|
| 583 | 762 | return ret; |
|---|
| 584 | 763 | } |
|---|
| 585 | 764 | |
|---|
| 586 | | - ret = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks); |
|---|
| 587 | | - if (ret) |
|---|
| 588 | | - return ret; |
|---|
| 765 | + if (rk_priv) { |
|---|
| 766 | + ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, |
|---|
| 767 | + rk_priv->rockchip_clks); |
|---|
| 768 | + if (ret) |
|---|
| 769 | + return ret; |
|---|
| 770 | + } |
|---|
| 589 | 771 | |
|---|
| 590 | 772 | ret = sdhci_resume_host(host); |
|---|
| 591 | 773 | if (ret) |
|---|
| .. | .. |
|---|
| 623 | 805 | SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume) |
|---|
| 624 | 806 | SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend, dwcmshc_runtime_resume, NULL) |
|---|
| 625 | 807 | }; |
|---|
| 626 | | -MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids); |
|---|
| 627 | 808 | |
|---|
| 628 | 809 | static struct platform_driver sdhci_dwcmshc_driver = { |
|---|
| 629 | 810 | .driver = { |
|---|
| 630 | 811 | .name = "sdhci-dwcmshc", |
|---|
| 631 | 812 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
|---|
| 632 | 813 | .of_match_table = sdhci_dwcmshc_dt_ids, |
|---|
| 814 | + .acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids), |
|---|
| 633 | 815 | .pm = &dwcmshc_pmops, |
|---|
| 634 | 816 | }, |
|---|
| 635 | 817 | .probe = dwcmshc_probe, |
|---|