1 /* $OpenBSD: dwmshc.c,v 1.4 2023/04/19 02:01:02 dlg 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 0x804 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_VALUE_SHIFT 8 105 #define EMMC_DLL_TXCLK_TX_TAP_VALUE_MASK 0xff 106 #define EMMC_DLL_TXCLK_TX_DELAY_SHIFT 16 107 #define EMMC_DLL_TXCLK_TX_DELAY_MASK 0xff 108 #define EMMC_DLL_TXCLK_TX_TAP_NUM_SEL (1U << 24) 109 #define EMMC_DLL_TXCLK_TX_TAP_VALUE_SEL (1U << 25) 110 #define EMMC_DLL_TXCLK_TX_DELAY_SEL (1U << 26) 111 #define EMMC_DLL_TXCLK_TX_CLK_OUT_SEL (1U << 27) 112 #define EMMC_DLL_STRBIN 0x80c 113 #define EMMC_DLL_STRBIN_TAP_NUM_SHIFT 0 114 #define EMMC_DLL_STRBIN_TAP_NUM_MASK 0x1f 115 #define EMMC_DLL_STRBIN_TAP_NUM_DEFAULT 0x8 116 #define EMMC_DLL_STRBIN_TAP_VALUE_SHIFT 8 117 #define EMMC_DLL_STRBIN_TAP_VALUE_MASK 0xff 118 #define EMMC_DLL_STRBIN_DELAY_NUM_SHIFT 16 119 #define EMMC_DLL_STRBIN_DELAY_NUM_MASK 0xff 120 #define EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT 0x16 121 #define EMMC_DLL_STRBIN_TAP_NUM_SEL (1U << 24) 122 #define EMMC_DLL_STRBIN_TAP_VALUE_SEL (1U << 25) 123 #define EMMC_DLL_STRBIN_DELAY_NUM_SEL (1U << 26) 124 #define EMMC_DLL_STRBIN_DELAY_ENA (1U << 27) 125 #define EMMC_DLL_STATUS0 0x840 126 #define EMMC_DLL_STATUS0_DLL_LOCK_VALUE_SHIFT 0 127 #define EMMC_DLL_STATUS0_DLL_LOCK_VALUE_MASK 0xff 128 #define EMMC_DLL_STATUS0_DLL_LOCK (1U << 8) 129 #define EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT (1U << 9) 130 #define EMMC_DLL_STATUS1 0x844 131 #define EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_SHIFT \ 132 0 133 #define EMMC_DLL_STATUS1_DLL_TXCLK_DELAY_VALUE_MASK \ 134 0xff 135 #define EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_SHIFT \ 136 8 137 #define EMMC_DLL_STATUS1_DLL_RXCLK_DELAY_VALUE_MASK \ 138 0xff 139 #define EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_SHIFT \ 140 16 141 #define EMMC_DLL_STATUS1_DLL_STRBIN_DELAY_VALUE_MASK \ 142 0xff 143 144 struct dwmshc_softc { 145 struct sdhc_softc sc_sdhc; 146 147 int sc_node; 148 149 bus_space_tag_t sc_iot; 150 bus_space_handle_t sc_ioh; 151 bus_size_t sc_ios; 152 bus_dma_tag_t sc_dmat; 153 void *sc_ih; 154 155 struct sdhc_host *sc_host; 156 }; 157 158 static int dwmshc_match(struct device *, void *, void *); 159 static void dwmshc_attach(struct device *, struct device *, 160 void *); 161 162 static inline void dwmshc_wr1(struct dwmshc_softc *, 163 bus_size_t, uint8_t); 164 static inline void dwmshc_wr4(struct dwmshc_softc *, 165 bus_size_t, uint32_t); 166 static inline uint32_t dwmshc_rd4(struct dwmshc_softc *, bus_size_t); 167 168 static void dwmshc_clock_pre(struct sdhc_softc *, int, int); 169 static void dwmshc_clock_post(struct sdhc_softc *, int, int); 170 static int dwmshc_non_removable(struct sdhc_softc *); 171 172 const struct cfattach dwmshc_ca = { 173 sizeof(struct dwmshc_softc), dwmshc_match, dwmshc_attach 174 }; 175 176 struct cfdriver dwmshc_cd = { 177 NULL, "dwmshc", DV_DULL 178 }; 179 180 int 181 dwmshc_match(struct device *parent, void *match, void *aux) 182 { 183 struct fdt_attach_args *faa = aux; 184 185 return (OF_is_compatible(faa->fa_node, "rockchip,rk3568-dwcmshc")); 186 } 187 static void 188 dwmshc_attach(struct device *parent, struct device *self, void *aux) 189 { 190 struct dwmshc_softc *sc = (struct dwmshc_softc *)self; 191 struct sdhc_softc *sdhc = &sc->sc_sdhc; 192 struct fdt_attach_args *faa = aux; 193 uint64_t capmask = 0; 194 uint16_t capset = 0; 195 int bus_width; 196 uint32_t freq; 197 198 sc->sc_node = faa->fa_node; 199 sc->sc_iot = faa->fa_iot; 200 sc->sc_ios = faa->fa_reg[0].size; 201 sc->sc_dmat = faa->fa_dmat; 202 203 if (faa->fa_nreg < 1) { 204 printf(": no registers\n"); 205 return; 206 } 207 208 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 209 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 210 printf(": can't map registers\n"); 211 return; 212 } 213 214 pinctrl_byname(sc->sc_node, "default"); 215 216 clock_set_assigned(sc->sc_node); 217 clock_enable_all(sc->sc_node); 218 reset_deassert_all(sc->sc_node); 219 220 sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, 221 sdhc_intr, sdhc, DEVNAME(sdhc)); 222 if (sc->sc_ih == NULL) { 223 printf(": can't establish interrupt\n"); 224 return; 225 } 226 227 printf("\n"); 228 229 /* Disable Command Conflict Check */ 230 dwmshc_wr1(sc, EMMC_HOST_CTRL3, 0); 231 232 sdhc->sc_host = &sc->sc_host; 233 sdhc->sc_dmat = faa->fa_dmat; 234 sdhc->sc_dma_boundary = 128 * 1024 * 1024; 235 236 sdhc->sc_bus_clock_pre = dwmshc_clock_pre; 237 sdhc->sc_bus_clock_post = dwmshc_clock_post; 238 239 if (OF_getpropbool(sc->sc_node, "non-removable")) { 240 SET(sdhc->sc_flags, SDHC_F_NONREMOVABLE); 241 sdhc->sc_card_detect = dwmshc_non_removable; 242 } 243 244 bus_width = OF_getpropint(faa->fa_node, "bus-width", 1); 245 if (bus_width < 8) 246 SET(capmask, SDHC_8BIT_MODE_SUPP); 247 248 freq = clock_get_frequency(faa->fa_node, "block"); 249 sdhc->sc_clkbase = freq / 1000; 250 251 SET(sdhc->sc_flags, SDHC_F_NOPWR0); 252 SET(capmask, (uint64_t)SDHC_DDR50_SUPP << 32); 253 254 sdhc_host_found(sdhc, sc->sc_iot, sc->sc_ioh, sc->sc_ios, 1, 255 capmask, capset); 256 } 257 258 static void 259 dwmshc_clock_pre(struct sdhc_softc *sdhc, int freq, int timing) 260 { 261 #if 0 262 struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc; 263 264 /* 265 * before switching to hs400es the driver needs to enable 266 * enhanced strobe. i think this is the right place to do 267 * that. 268 */ 269 if (timing == hs400es) { 270 dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA | 271 EMMC_DLL_STRBIN_DELAY_NUM_SEL | 272 (EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT << 273 EMMC_DLL_STRBIN_DELAY_NUM_SHIFT)); 274 } 275 #endif 276 } 277 278 static int 279 dwmshc_dll_wait(struct dwmshc_softc *sc) 280 { 281 uint32_t status0; 282 int i; 283 284 for (i = 0; i < 500 * 1000; i++) { 285 delay(1); 286 287 status0 = dwmshc_rd4(sc, EMMC_DLL_STATUS0); 288 if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK)) { 289 if (ISSET(status0, EMMC_DLL_STATUS0_DLL_LOCK_TIMEOUT)) { 290 printf("%s: lock timeout\n", 291 DEVNAME(&sc->sc_sdhc)); 292 return (EIO); 293 } 294 return (0); 295 } 296 } 297 298 printf("%s: poll timeout\n", DEVNAME(&sc->sc_sdhc)); 299 return (ETIMEDOUT); 300 } 301 302 static void 303 dwmshc_clock_post(struct sdhc_softc *sdhc, int freq, int timing) 304 { 305 struct dwmshc_softc *sc = (struct dwmshc_softc *)sdhc; 306 uint32_t txclk_tapnum = EMMC_DLL_STRBIN_DELAY_NUM_DEFAULT; 307 308 clock_set_frequency(sc->sc_node, 0, freq * 1000); 309 310 if (timing == SDMMC_TIMING_LEGACY) { /* disable dll */ 311 /* 312 * the bypass and start bits need to be set if dll 313 * is not locked. 314 */ 315 dwmshc_wr4(sc, EMMC_DLL_CTRL, 316 EMMC_DLL_CTRL_DLL_START | EMMC_DLL_CTRL_DLL_BYPASS_MODE); 317 dwmshc_wr4(sc, EMMC_DLL_RXCLK, 0); 318 dwmshc_wr4(sc, EMMC_DLL_TXCLK, 0); 319 dwmshc_wr4(sc, EMMC_DLL_STRBIN, 0); 320 return; 321 } 322 323 dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_SRST); 324 delay(1); 325 dwmshc_wr4(sc, EMMC_DLL_CTRL, 0); 326 327 dwmshc_wr4(sc, EMMC_DLL_RXCLK, EMMC_DLL_RXCLK_RX_CLK_OUT_SEL | 328 /* rk3568 */ EMMC_DLL_RXCLK_RX_CLK_SRC_SEL); 329 dwmshc_wr4(sc, EMMC_DLL_CTRL, EMMC_DLL_CTRL_DLL_START | 330 0x5 << EMMC_DLL_CTRL_DLL_START_POINT_SHIFT | 331 0x2 << EMMC_DLL_CTRL_DLL_INCREMENT_SHIFT); 332 333 if (dwmshc_dll_wait(sc) != 0) 334 return; 335 336 dwmshc_wr4(sc, EMMC_AT_CTRL, EMMC_AT_CTRL_TUNE_CLK_STOP_EN | 337 EMMC_AT_CTRL_PRE_CHANGE_DLY_LT4 | 338 EMMC_AT_CTRL_POST_CHANGE_DLY_LT4); 339 340 if (timing >= SDMMC_TIMING_MMC_HS200) { 341 txclk_tapnum = OF_getpropint(sc->sc_node, 342 "rockchip,txclk-tapnum", txclk_tapnum); 343 344 /* XXX rk3588 hs400 */ 345 } 346 347 dwmshc_wr4(sc, EMMC_DLL_TXCLK, EMMC_DLL_TXCLK_TX_CLK_OUT_SEL | 348 EMMC_DLL_TXCLK_TX_TAP_NUM_SEL | 349 txclk_tapnum << EMMC_DLL_TXCLK_TX_TAP_NUM_SHIFT); 350 dwmshc_wr4(sc, EMMC_DLL_STRBIN, EMMC_DLL_STRBIN_DELAY_ENA | 351 EMMC_DLL_STRBIN_TAP_NUM_SEL | 352 (EMMC_DLL_STRBIN_TAP_NUM_DEFAULT << 353 EMMC_DLL_STRBIN_TAP_NUM_SHIFT)); 354 } 355 356 static int 357 dwmshc_non_removable(struct sdhc_softc *sdhc) 358 { 359 return (1); 360 } 361 362 static inline void 363 dwmshc_wr1(struct dwmshc_softc *sc, bus_size_t off, uint8_t v) 364 { 365 bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, v); 366 } 367 368 static inline void 369 dwmshc_wr4(struct dwmshc_softc *sc, bus_size_t off, uint32_t v) 370 { 371 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, v); 372 } 373 374 static inline uint32_t 375 dwmshc_rd4(struct dwmshc_softc *sc, bus_size_t off) 376 { 377 return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, off)); 378 } 379