1 /* $OpenBSD: dwmshc.c,v 1.8 2024/07/15 09:56:30 patrick Exp $ */ 2 3 /* 4 * Copyright (c) 2023 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/malloc.h> 21 #include <sys/systm.h> 22 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 #include <machine/intr.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/ofw_clock.h> 29 #include <dev/ofw/ofw_gpio.h> 30 #include <dev/ofw/ofw_misc.h> 31 #include <dev/ofw/ofw_pinctrl.h> 32 #include <dev/ofw/ofw_regulator.h> 33 #include <dev/ofw/fdt.h> 34 35 #include <dev/sdmmc/sdhcreg.h> 36 #include <dev/sdmmc/sdhcvar.h> 37 #include <dev/sdmmc/sdmmcvar.h> 38 39 #define EMMC_VER_ID 0x500 40 #define EMMC_VER_TYPE 0x504 41 #define EMMC_HOST_CTRL3 0x508 /* B */ 42 #define EMMC_HOST_CTRL3_CMD_CONFLICT_CHECK (1U << 0) 43 #define EMMC_HOST_CTRL3_SW_CG_DIS (1U << 4) 44 #define EMMC_EMMC_CTRL 0x52c /* HW */ 45 #define EMMC_EMMC_CTRL_CARD_IS_EMMC (1U << 0) 46 #define EMMC_EMMC_CTRL_DISABLE_DATA_CRC_CHK (1U << 1) 47 #define EMMC_EMMC_CTRL_EMMC_RST_N (1U << 2) 48 #define EMMC_EMMC_CTRL_EMMC_RST_N_OE (1U << 3) 49 #define EMMC_EMMC_CTRL_ENH_STROBE_ENABLE (1U << 8) 50 #define EMMC_EMMC_CTRL_CQE_ALGO_SEL (1U << 9) 51 #define EMMC_EMMC_CTRL_CQE_PREFETCH_DISABLE (1U << 10) 52 #define EMMC_BOOT_CTRL 0x52e /* HW */ 53 #define EMMC_BOOT_CTRL_MAN_BOOT_EN (1U << 0) 54 #define EMMC_BOOT_CTRL_VALIDATE_BOOT (1U << 1) 55 #define EMMC_BOOT_CTRL_BOOT_ACK_ENABLE (1U << 8) 56 #define EMMC_BOOT_CTRL_BOOT_TOUT_CNT_SHIFT 12 57 #define EMMC_BOOT_CTRL_BOOT_TOUT_CNT_MASK 0xf 58 #define EMMC_AT_CTRL 0x540 59 #define EMMC_AT_CTRL_SWIN_TH_EN (1U << 2) 60 #define EMMC_AT_CTRL_RPT_TUNE_ERR (1U << 3) 61 #define EMMC_AT_CTRL_SW_TUNE_EN (1U << 4) 62 #define EMMC_AT_CTRL_TUNE_CLK_STOP_EN (1U << 16) 63 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_MASK (0x3 << 17) 64 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_LT1 (0x0 << 17) 65 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_LT2 (0x1 << 17) 66 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_LT3 (0x2 << 17) 67 #define EMMC_AT_CTRL_PRE_CHANGE_DLY_LT4 (0x3 << 17) 68 #define EMMC_AT_CTRL_POST_CHANGE_DLY_MASK (0x3 << 19) 69 #define EMMC_AT_CTRL_POST_CHANGE_DLY_LT1 (0x0 << 19) 70 #define EMMC_AT_CTRL_POST_CHANGE_DLY_LT2 (0x1 << 19) 71 #define EMMC_AT_CTRL_POST_CHANGE_DLY_LT3 (0x2 << 19) 72 #define EMMC_AT_CTRL_POST_CHANGE_DLY_LT4 (0x3 << 19) 73 #define EMMC_AT_STAT 0x544 74 #define EMMC_AT_STAT_CENTER_PH_CODE_SHIFT 0 75 #define EMMC_AT_STAT_CENTER_PH_CODE_MASK 0xff 76 #define EMMC_AT_STAT_R_EDGE_PH_CODE_SHIFT 8 77 #define EMMC_AT_STAT_R_EDGE_PH_CODE_MASK 0xff 78 #define EMMC_AT_STAT_L_EDGE_PH_CODE_SHIFT 16 79 #define EMMC_AT_STAT_L_EDGE_PH_CODE_MASK 0xff 80 #define EMMC_DLL_CTRL 0x800 81 #define EMMC_DLL_CTRL_DLL_START (1U << 0) 82 #define EMMC_DLL_CTRL_DLL_SRST (1U << 1) 83 #define EMMC_DLL_CTRL_DLL_INCREMENT_SHIFT 8 84 #define EMMC_DLL_CTRL_DLL_INCREMENT_MASK 0xff 85 #define EMMC_DLL_CTRL_DLL_START_POINT_SHIFT 16 86 #define EMMC_DLL_CTRL_DLL_START_POINT_MASK 0xff 87 #define EMMC_DLL_CTRL_DLL_BYPASS_MODE (1U << 24) 88 #define EMMC_DLL_RXCLK 0x804 89 #define EMMC_DLL_RXCLK_RX_TAP_NUM_SHIFT 0 90 #define EMMC_DLL_RXCLK_RX_TAP_NUM_MASK 0x1f 91 #define EMMC_DLL_RXCLK_RX_TAP_VALUE_SHIFT 8 92 #define EMMC_DLL_RXCLK_RX_TAP_VALUE_MASK 0xff 93 #define EMMC_DLL_RXCLK_RX_DELAY_NUM_SHIFT 16 94 #define EMMC_DLL_RXCLK_RX_DELAY_NUM_MASK 0xff 95 #define EMMC_DLL_RXCLK_RX_TAP_NUM_SEL (1U << 24) 96 #define EMMC_DLL_RXCLK_RX_TAP_VALUE_SEL (1U << 25) 97 #define EMMC_DLL_RXCLK_RX_DELAY_NUM_SEL (1U << 26) 98 #define EMMC_DLL_RXCLK_RX_CLK_OUT_SEL (1U << 27) 99 #define EMMC_DLL_RXCLK_RX_CLK_CHANGE_WINDOW (1U << 28) 100 #define EMMC_DLL_RXCLK_RX_CLK_SRC_SEL (1U << 29) 101 #define EMMC_DLL_TXCLK 0x808 102 #define EMMC_DLL_TXCLK_TX_TAP_NUM_SHIFT 0 103 #define EMMC_DLL_TXCLK_TX_TAP_NUM_MASK 0x1f 104 #define EMMC_DLL_TXCLK_TX_TAP_NUM_90_DEG 0x8 105 #define EMMC_DLL_TXCLK_TX_TAP_NUM_DEFAULT 0x10 106 #define EMMC_DLL_TXCLK_TX_TAP_VALUE_SHIFT 8 107 #define EMMC_DLL_TXCLK_TX_TAP_VALUE_MASK 0xff 108 #define EMMC_DLL_TXCLK_TX_DELAY_SHIFT 16 109 #define EMMC_DLL_TXCLK_TX_DELAY_MASK 0xff 110 #define EMMC_DLL_TXCLK_TX_TAP_NUM_SEL (1U << 24) 111 #define EMMC_DLL_TXCLK_TX_TAP_VALUE_SEL (1U << 25) 112 #define EMMC_DLL_TXCLK_TX_DELAY_SEL (1U << 26) 113 #define EMMC_DLL_TXCLK_TX_CLK_OUT_SEL (1U << 27) 114 #define EMMC_DLL_STRBIN 0x80c 115 #define EMMC_DLL_STRBIN_TAP_NUM_SHIFT 0 116 #define EMMC_DLL_STRBIN_TAP_NUM_MASK 0x1f 117 #define EMMC_DLL_STRBIN_TAP_NUM_90_DEG 0x8 118 #define EMMC_DLL_STRBIN_TAP_VALUE_SHIFT 8 119 #define EMMC_DLL_STRBIN_TAP_VALUE_MASK 0xff 120 #define EMMC_DLL_STRBIN_DELAY_NUM_SHIFT 16 121 #define EMMC_DLL_STRBIN_DELAY_NUM_MASK 0xff 122 #define EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT 0x16 123 #define EMMC_DLL_STRBIN_TAP_NUM_SEL (1U << 24) 124 #define EMMC_DLL_STRBIN_TAP_VALUE_SEL (1U << 25) 125 #define EMMC_DLL_STRBIN_DELAY_NUM_SEL (1U << 26) 126 #define EMMC_DLL_STRBIN_DELAY_ENA (1U << 27) 127 #define EMMC_DLL_CMDOUT 0x810 128 #define EMMC_DLL_CMDOUT_TAP_NUM_SHIFT 0 129 #define EMMC_DLL_CMDOUT_TAP_NUM_MASK 0x1f 130 #define EMMC_DLL_CMDOUT_TAP_NUM_90_DEG 0x8 131 #define EMMC_DLL_CMDOUT_TAP_VALUE_SHIFT 8 132 #define EMMC_DLL_CMDOUT_TAP_VALUE_MASK 0xff 133 #define EMMC_DLL_CMDOUT_DELAY_NUM_SHIFT 16 134 #define EMMC_DLL_CMDOUT_DELAY_NUM_MASK 0xff 135 #define EMMC_DLL_CMDOUT_TAP_NUM_SEL (1U << 24) 136 #define EMMC_DLL_CMDOUT_TAP_VALUE_SEL (1U << 25) 137 #define EMMC_DLL_CMDOUT_DELAY_NUM_SEL (1U << 26) 138 #define EMMC_DLL_CMDOUT_DELAY_ENA (1U << 27) 139 #define EMMC_DLL_CMDOUT_SRC_SEL (1U << 28) 140 #define EMMC_DLL_CMDOUT_EN_SRC_SEL (1U << 29) 141 #define EMMC_DLL_STATUS0 0x840 142 #define EMMC_DLL_STATUS0_DLL_LOCK_VALUE_SHIFT 0 143 #define EMMC_DLL_STATUS0_DLL_LOCK_VALUE_MASK 0xff 144 #define EMMC_DLL_STATUS0_DLL_LOCK (1U << 8) 145 #define EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT (1U << 9) 146 #define EMMC_DLL_STATUS1 0x844 147 #define EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_SHIFT \ 148 0 149 #define EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_MASK \ 150 0xff 151 #define EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_SHIFT \ 152 8 153 #define EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_MASK \ 154 0xff 155 #define EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_SHIFT \ 156 16 157 #define EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_MASK \ 158 0xff 159 160 struct dwmshc_softc { 161 struct sdhc_softc sc_sdhc; 162 163 int sc_node; 164 165 bus_space_tag_t sc_iot; 166 bus_space_handle_t sc_ioh; 167 bus_size_t sc_ios; 168 bus_dma_tag_t sc_dmat; 169 void *sc_ih; 170 171 struct sdhc_host *sc_host; 172 }; 173 174 static int dwmshc_match(struct device *, void *, void *); 175 static void dwmshc_attach(struct device *, struct device *, 176 void *); 177 178 static inline void dwmshc_wr1(struct dwmshc_softc *, 179 bus_size_t, uint8_t); 180 static inline void dwmshc_wr4(struct dwmshc_softc *, 181 bus_size_t, uint32_t); 182 static inline uint32_t dwmshc_rd4(struct dwmshc_softc *, bus_size_t); 183 184 static void dwmshc_clock_pre(struct sdhc_softc *, int, int); 185 static void dwmshc_clock_post(struct sdhc_softc *, int, int); 186 static int dwmshc_non_removable(struct sdhc_softc *); 187 188 const struct cfattach dwmshc_ca = { 189 sizeof(struct dwmshc_softc), dwmshc_match, dwmshc_attach 190 }; 191 192 struct cfdriver dwmshc_cd = { 193 NULL, "dwmshc", DV_DULL 194 }; 195 196 int 197 dwmshc_match(struct device *parent, void *match, void *aux) 198 { 199 struct fdt_attach_args *faa = aux; 200 201 return (OF_is_compatible(faa->fa_node, "rockchip,rk3568-dwcmshc") || 202 OF_is_compatible(faa->fa_node, "rockchip,rk3588-dwcmshc")); 203 } 204 static void 205 dwmshc_attach(struct device *parent, struct device *self, void *aux) 206 { 207 struct dwmshc_softc *sc = (struct dwmshc_softc *)self; 208 struct sdhc_softc *sdhc = &sc->sc_sdhc; 209 struct fdt_attach_args *faa = aux; 210 uint64_t capmask = 0; 211 uint16_t capset = 0; 212 int bus_width; 213 uint32_t freq; 214 215 sc->sc_node = faa->fa_node; 216 sc->sc_iot = faa->fa_iot; 217 sc->sc_ios = faa->fa_reg[0].size; 218 sc->sc_dmat = faa->fa_dmat; 219 220 if (faa->fa_nreg < 1) { 221 printf(": no registers\n"); 222 return; 223 } 224 225 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 226 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 227 printf(": can't map registers\n"); 228 return; 229 } 230 231 pinctrl_byname(sc->sc_node, "default"); 232 233 clock_set_assigned(sc->sc_node); 234 clock_enable_all(sc->sc_node); 235 reset_deassert_all(sc->sc_node); 236 237 sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, 238 sdhc_intr, sdhc, DEVNAME(sdhc)); 239 if (sc->sc_ih == NULL) { 240 printf(": can't establish interrupt\n"); 241 return; 242 } 243 244 printf("\n"); 245 246 /* Disable Command Conflict Check */ 247 dwmshc_wr1(sc, EMMC_HOST_CTRL3, 0); 248 249 sdhc->sc_host = &sc->sc_host; 250 sdhc->sc_dmat = faa->fa_dmat; 251 sdhc->sc_dma_boundary = 128 * 1024 * 1024; 252 253 sdhc->sc_bus_clock_pre = dwmshc_clock_pre; 254 sdhc->sc_bus_clock_post = dwmshc_clock_post; 255 256 if (OF_getpropbool(sc->sc_node, "non-removable")) { 257 SET(sdhc->sc_flags, SDHC_F_NONREMOVABLE); 258 sdhc->sc_card_detect = dwmshc_non_removable; 259 } 260 261 bus_width = OF_getpropint(faa->fa_node, "bus-width", 1); 262 if (bus_width < 8) 263 SET(capmask, SDHC_8BIT_MODE_SUPP); 264 265 freq = clock_get_frequency(faa->fa_node, "block"); 266 sdhc->sc_clkbase = freq / 1000; 267 268 SET(sdhc->sc_flags, SDHC_F_NOPWR0); 269 SET(capmask, (uint64_t)SDHC_DDR50_SUPP << 32); 270 271 sdhc_host_found(sdhc, sc->sc_iot, sc->sc_ioh, sc->sc_ios, 1, 272 capmask, capset); 273 } 274 275 static void 276 dwmshc_clock_pre(struct sdhc_softc *sdhc, int freq, int timing) 277 { 278 #if 0 279 struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc; 280 281 /* 282 * before switching to hs400es the driver needs to enable 283 * enhanced strobe. i think this is the right place to do 284 * that. 285 */ 286 if (timing == hs400es) { 287 dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA | 288 EMMC_DLL_STRBIN_DELAY_NUM_SEL | 289 (EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT << 290 EMMC_DLL_STRBIN_DELAY_NUM_SHIFT)); 291 } 292 #endif 293 } 294 295 static int 296 dwmshc_dll_wait(struct dwmshc_softc *sc) 297 { 298 uint32_t status0; 299 int i; 300 301 for (i = 0; i < 500 * 1000; i++) { 302 delay(1); 303 304 status0 = dwmshc_rd4(sc, EMMC_DLL_STATUS0); 305 if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK)) { 306 if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT)) { 307 printf("%s: lock timeout\n", 308 DEVNAME(&sc->sc_sdhc)); 309 return (EIO); 310 } 311 return (0); 312 } 313 } 314 315 printf("%s: poll timeout\n", DEVNAME(&sc->sc_sdhc)); 316 return (ETIMEDOUT); 317 } 318 319 static void 320 dwmshc_clock_post(struct sdhc_softc *sdhc, int freq, int timing) 321 { 322 struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc; 323 uint32_t txclk_tapnum = EMMC_DLL_TXCLK_TX_TAP_NUM_DEFAULT; 324 325 clock_set_frequency(sc->sc_node, 0, freq * 1000); 326 327 if (timing == SDMMC_TIMING_LEGACY) { /* disable dll */ 328 /* 329 * the bypass and start bits need to be set if dll 330 * is not locked. 331 */ 332 dwmshc_wr4(sc, EMMC_DLL_CTRL, 333 EMMC_DLL_CTRL_DLL_START | EMMC_DLL_CTRL_DLL_BYPASS_MODE); 334 dwmshc_wr4(sc, EMMC_DLL_RXCLK, 0); 335 dwmshc_wr4(sc, EMMC_DLL_TXCLK, 0); 336 dwmshc_wr4(sc, EMMC_DLL_STRBIN, 0); 337 return; 338 } 339 340 dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_SRST); 341 delay(1); 342 dwmshc_wr4(sc, EMMC_DLL_CTRL, 0); 343 344 if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-dwcmshc")) 345 dwmshc_wr4(sc, EMMC_DLL_RXCLK, EMMC_DLL_RXCLK_RX_CLK_OUT_SEL | 346 EMMC_DLL_RXCLK_RX_CLK_SRC_SEL); 347 else 348 dwmshc_wr4(sc, EMMC_DLL_RXCLK, EMMC_DLL_RXCLK_RX_CLK_OUT_SEL); 349 dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_START | 350 0x5 << EMMC_DLL_CTRL_DLL_START_POINT_SHIFT | 351 0x2 << EMMC_DLL_CTRL_DLL_INCREMENT_SHIFT); 352 353 if (dwmshc_dll_wait(sc) != 0) 354 return; 355 356 dwmshc_wr4(sc, EMMC_AT_CTRL, EMMC_AT_CTRL_TUNE_CLK_STOP_EN | 357 EMMC_AT_CTRL_PRE_CHANGE_DLY_LT4 | 358 EMMC_AT_CTRL_POST_CHANGE_DLY_LT4); 359 360 if (timing >= SDMMC_TIMING_MMC_HS200) { 361 txclk_tapnum = OF_getpropint(sc->sc_node, 362 "rockchip,txclk-tapnum", txclk_tapnum); 363 364 #ifdef notyet 365 if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-dwcmshc") && 366 timing == SDMMC_TIMING_MMC_HS400) { 367 txclk_tapnum = EMMC_DLL_TXCLK_TX_TAP_NUM_90_DEG; 368 dwmshc_wr4(sc, EMMC_DLL_CMDOUT, 369 EMMC_DLL_CMDOUT_TAP_NUM_90_DEG | 370 EMMC_DLL_CMDOUT_TAP_NUM_SEL | 371 EMMC_DLL_CMDOUT_DELAY_ENA | 372 EMMC_DLL_CMDOUT_SRC_SEL | 373 EMMC_DLL_CMDOUT_EN_SRC_SEL); 374 } 375 #endif 376 } 377 378 dwmshc_wr4(sc, EMMC_DLL_TXCLK, EMMC_DLL_TXCLK_TX_CLK_OUT_SEL | 379 EMMC_DLL_TXCLK_TX_TAP_NUM_SEL | 380 txclk_tapnum << EMMC_DLL_TXCLK_TX_TAP_NUM_SHIFT); 381 dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA | 382 EMMC_DLL_STRBIN_TAP_NUM_SEL | 383 (EMMC_DLL_STRBIN_TAP_NUM_90_DEG << 384 EMMC_DLL_STRBIN_TAP_NUM_SHIFT)); 385 } 386 387 static int 388 dwmshc_non_removable(struct sdhc_softc *sdhc) 389 { 390 return (1); 391 } 392 393 static inline void 394 dwmshc_wr1(struct dwmshc_softc *sc, bus_size_t off, uint8_t v) 395 { 396 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, v); 397 } 398 399 static inline void 400 dwmshc_wr4(struct dwmshc_softc *sc, bus_size_t off, uint32_t v) 401 { 402 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, v); 403 } 404 405 static inline uint32_t 406 dwmshc_rd4(struct dwmshc_softc *sc, bus_size_t off) 407 { 408 return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off)); 409 } 410