1 /* $NetBSD: ti_sdhc.c,v 1.13 2026/08/12 09:36:49 yurix Exp $ */ 2 /*- 3 * Copyright (c) 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Matt Thomas of 3am Software Foundry. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: ti_sdhc.c,v 1.13 2026/08/12 09:36:49 yurix Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/device.h> 37 #include <sys/errno.h> 38 #include <sys/kernel.h> 39 #include <sys/proc.h> 40 #include <sys/queue.h> 41 #include <sys/mutex.h> 42 #include <sys/condvar.h> 43 #include <sys/bus.h> 44 45 #include <arm/ti/ti_prcm.h> 46 #include <arm/ti/ti_sdhcreg.h> 47 48 #include <dev/sdmmc/sdhcreg.h> 49 #include <dev/sdmmc/sdhcvar.h> 50 #include <dev/sdmmc/sdmmcvar.h> 51 52 #include <dev/fdt/fdtvar.h> 53 54 #ifdef TISDHC_DEBUG 55 int tisdhcdebug = 1; 56 #define DPRINTF(n,s) do { if ((n) <= tisdhcdebug) device_printf s; } while (0) 57 #else 58 #define DPRINTF(n,s) do {} while (0) 59 #endif 60 61 62 #define CLKD(kz) (sc->sc.sc_clkbase / (kz)) 63 64 #define SDHC_READ(sc, reg) \ 65 bus_space_read_4((sc)->sc_bst, (sc)->sc_sdhc_bsh, (reg)) 66 #define SDHC_WRITE(sc, reg, val) \ 67 bus_space_write_4((sc)->sc_bst, (sc)->sc_sdhc_bsh, (reg), (val)) 68 69 struct ti_sdhc_config { 70 bus_size_t regoff; 71 uint32_t flags; 72 }; 73 74 static const struct ti_sdhc_config omap2_hsmmc_config = { 75 }; 76 77 static const struct ti_sdhc_config omap3_pre_es3_hsmmc_config = { 78 .flags = SDHC_FLAG_SINGLE_ONLY 79 }; 80 81 static const struct ti_sdhc_config omap4_hsmmc_config = { 82 .regoff = 0x100 83 }; 84 85 static const struct ti_sdhc_config am335_sdhci_config = { 86 .regoff = 0x100 87 }; 88 89 static const struct device_compatible_entry compat_data[] = { 90 { .compat = "ti,omap2-hsmmc", 91 .data = &omap2_hsmmc_config }, 92 { .compat = "ti,omap3-hsmmc", 93 .data = &omap2_hsmmc_config }, 94 { .compat = "ti,omap3-pre-es3-hsmmc", 95 .data = &omap3_pre_es3_hsmmc_config }, 96 { .compat = "ti,omap4-hsmmc", 97 .data = &omap4_hsmmc_config }, 98 { .compat = "ti,am335-sdhci", 99 .data = &am335_sdhci_config }, 100 101 DEVICE_COMPAT_EOL 102 }; 103 104 enum { 105 EDMA_CHAN_TX, 106 EDMA_CHAN_RX, 107 EDMA_NCHAN 108 }; 109 110 struct ti_sdhc_softc { 111 struct sdhc_softc sc; 112 int sc_phandle; 113 bus_addr_t sc_addr; 114 bus_space_tag_t sc_bst; 115 bus_space_handle_t sc_bsh; 116 bus_space_handle_t sc_hl_bsh; 117 bus_space_handle_t sc_sdhc_bsh; 118 struct sdhc_host *sc_hosts[1]; 119 void *sc_ih; /* interrupt vectoring */ 120 121 struct fdtbus_dma *sc_rx_dma; 122 struct fdtbus_dma *sc_tx_dma; 123 124 kcondvar_t sc_edma_cv; 125 bus_addr_t sc_edma_fifo; 126 bool sc_edma_pending; 127 bus_dmamap_t sc_edma_dmamap; 128 bus_dma_segment_t sc_edma_segs[1]; 129 void *sc_edma_bbuf; 130 }; 131 132 static int ti_sdhc_match(device_t, cfdata_t, void *); 133 static void ti_sdhc_attach(device_t, device_t, void *); 134 135 static void ti_sdhc_init(struct ti_sdhc_softc *, const struct ti_sdhc_config *); 136 137 static int ti_sdhc_bus_width(struct sdhc_softc *, int); 138 static int ti_sdhc_rod(struct sdhc_softc *, int); 139 static int ti_sdhc_write_protect(struct sdhc_softc *); 140 static int ti_sdhc_card_detect(struct sdhc_softc *); 141 142 static int ti_sdhc_edma_init(struct ti_sdhc_softc *); 143 static int ti_sdhc_edma_xfer_data(struct sdhc_softc *, struct sdmmc_command *); 144 static void ti_sdhc_edma_done(void *); 145 static int ti_sdhc_edma_transfer(struct sdhc_softc *, struct sdmmc_command *); 146 147 CFATTACH_DECL_NEW(ti_sdhc, sizeof(struct ti_sdhc_softc), 148 ti_sdhc_match, ti_sdhc_attach, NULL, NULL); 149 150 static int 151 ti_sdhc_match(device_t parent, cfdata_t cf, void *aux) 152 { 153 struct fdt_attach_args * const faa = aux; 154 155 return of_compatible_match(faa->faa_phandle, compat_data); 156 } 157 158 static void 159 ti_sdhc_attach(device_t parent, device_t self, void *aux) 160 { 161 struct ti_sdhc_softc * const sc = device_private(self); 162 struct fdt_attach_args * const faa = aux; 163 const int phandle = faa->faa_phandle; 164 const struct ti_sdhc_config *conf; 165 bus_addr_t addr; 166 bus_size_t size; 167 u_int bus_width; 168 169 conf = of_compatible_lookup(phandle, compat_data)->data; 170 171 if (ti_prcm_enable_hwmod(phandle, 0) != 0) { 172 aprint_error(": couldn't enable module\n"); 173 return; 174 } 175 176 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0 || size <= conf->regoff) { 177 aprint_error(": couldn't get registers\n"); 178 return; 179 } 180 addr += conf->regoff; 181 size -= conf->regoff; 182 183 sc->sc.sc_dmat = faa->faa_dmat; 184 sc->sc.sc_dev = self; 185 sc->sc_phandle = phandle; 186 sc->sc_addr = addr; 187 sc->sc_bst = faa->faa_bst; 188 189 sc->sc_rx_dma = fdtbus_dma_get(phandle, "rx", ti_sdhc_edma_done, sc); 190 sc->sc_tx_dma = fdtbus_dma_get(phandle, "tx", ti_sdhc_edma_done, sc); 191 192 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 193 aprint_error(": couldn't map registers\n"); 194 return; 195 } 196 197 if (of_getprop_uint32(phandle, "bus-width", &bus_width) != 0) 198 bus_width = 4; 199 200 sc->sc.sc_flags |= conf->flags; 201 sc->sc.sc_flags |= SDHC_FLAG_32BIT_ACCESS; 202 sc->sc.sc_flags |= SDHC_FLAG_NO_LED_ON; 203 sc->sc.sc_flags |= SDHC_FLAG_RSP136_CRC; 204 if (bus_width == 8) 205 sc->sc.sc_flags |= SDHC_FLAG_8BIT_MODE; 206 if (of_hasprop(phandle, "ti,needs-special-reset")) 207 sc->sc.sc_flags |= SDHC_FLAG_WAIT_RESET; 208 if (!of_hasprop(phandle, "ti,needs-special-hs-handling")) 209 sc->sc.sc_flags |= SDHC_FLAG_NO_HS_BIT; 210 if (of_hasprop(phandle, "ti,dual-volt")) 211 sc->sc.sc_caps = SDHC_VOLTAGE_SUPP_3_0V; 212 213 sc->sc.sc_host = sc->sc_hosts; 214 sc->sc.sc_clkbase = 96000; /* 96MHZ */ 215 sc->sc.sc_clkmsk = 0x0000ffc0; 216 sc->sc.sc_vendor_rod = ti_sdhc_rod; 217 sc->sc.sc_vendor_write_protect = ti_sdhc_write_protect; 218 sc->sc.sc_vendor_card_detect = ti_sdhc_card_detect; 219 sc->sc.sc_vendor_bus_width = ti_sdhc_bus_width; 220 221 if (bus_space_subregion(sc->sc_bst, sc->sc_bsh, 0x100, 0x100, 222 &sc->sc_sdhc_bsh) != 0) { 223 aprint_error(": couldn't map subregion\n"); 224 return; 225 } 226 227 aprint_naive("\n"); 228 aprint_normal(": MMCHS\n"); 229 230 ti_sdhc_init(sc, conf); 231 } 232 233 static void 234 ti_sdhc_init(struct ti_sdhc_softc *sc, const struct ti_sdhc_config *conf) 235 { 236 device_t dev = sc->sc.sc_dev; 237 uint32_t clkd, stat; 238 int error, timo, clksft, n; 239 char intrstr[128]; 240 241 if (sc->sc_rx_dma != NULL && sc->sc_tx_dma != NULL) { 242 aprint_normal_dev(dev,"DMA available\n"); 243 244 if (ti_sdhc_edma_init(sc) != 0) { 245 aprint_error_dev(dev, "EDMA disabled\n"); 246 goto no_dma; 247 } 248 249 cv_init(&sc->sc_edma_cv, "sdhcedma"); 250 sc->sc_edma_fifo = sc->sc_addr + 0x100 + SDHC_DATA; 251 sc->sc.sc_flags |= SDHC_FLAG_USE_DMA; 252 sc->sc.sc_flags |= SDHC_FLAG_EXTERNAL_DMA; 253 sc->sc.sc_flags |= SDHC_FLAG_EXTDMA_DMAEN; 254 sc->sc.sc_vendor_transfer_data_dma = ti_sdhc_edma_xfer_data; 255 } 256 no_dma: 257 258 /* XXXXXX: Turn-on regulator via I2C. */ 259 /* XXXXXX: And enable ICLOCK/FCLOCK. */ 260 261 SDHC_WRITE(sc, SDHC_CAPABILITIES, 262 SDHC_READ(sc, SDHC_CAPABILITIES) | SDHC_VOLTAGE_SUPP_1_8V); 263 if (sc->sc.sc_caps & SDHC_VOLTAGE_SUPP_3_0V) 264 SDHC_WRITE(sc, SDHC_CAPABILITIES, 265 SDHC_READ(sc, SDHC_CAPABILITIES) | SDHC_VOLTAGE_SUPP_3_0V); 266 267 /* MMCHS Soft reset */ 268 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSCONFIG, 269 SYSCONFIG_SOFTRESET); 270 timo = 3000000; /* XXXX 3 sec. */ 271 while (timo--) { 272 if (bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSSTATUS) & 273 SYSSTATUS_RESETDONE) 274 break; 275 delay(1); 276 } 277 if (timo == 0) 278 aprint_error_dev(dev, "Soft reset timeout\n"); 279 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_SYSCONFIG, 280 SYSCONFIG_ENAWAKEUP | 281 #if notyet 282 SYSCONFIG_AUTOIDLE | 283 SYSCONFIG_SIDLEMODE_AUTO | 284 #else 285 SYSCONFIG_SIDLEMODE_IGNORE | 286 #endif 287 SYSCONFIG_CLOCKACTIVITY_FCLK | 288 SYSCONFIG_CLOCKACTIVITY_ICLK); 289 290 if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr))) { 291 aprint_error_dev(dev, "couldn't decode interrupt\n"); 292 return; 293 } 294 sc->sc_ih = fdtbus_intr_establish_xname(sc->sc_phandle, 0, IPL_VM, 295 0, sdhc_intr, &sc->sc, device_xname(dev)); 296 if (sc->sc_ih == NULL) { 297 aprint_error_dev(dev, "couldn't establish interrupt\n"); 298 return; 299 } 300 aprint_normal_dev(dev, "interrupting on %s\n", intrstr); 301 302 error = sdhc_host_found(&sc->sc, sc->sc_bst, sc->sc_sdhc_bsh, 0x100); 303 if (error != 0) { 304 aprint_error_dev(dev, "couldn't initialize host, error=%d\n", 305 error); 306 fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); 307 return; 308 } 309 310 clksft = ffs(sc->sc.sc_clkmsk) - 1; 311 312 /* Set SDVS 1.8v and DTW 1bit mode */ 313 SDHC_WRITE(sc, SDHC_HOST_CTL, 314 SDHC_VOLTAGE_1_8V << (SDHC_VOLTAGE_SHIFT + 8)); 315 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 316 SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_INTCLK_ENABLE | 317 SDHC_SDCLK_ENABLE); 318 SDHC_WRITE(sc, SDHC_HOST_CTL, 319 SDHC_READ(sc, SDHC_HOST_CTL) | SDHC_BUS_POWER << 8); 320 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 321 SDHC_READ(sc, SDHC_CLOCK_CTL) | CLKD(150) << clksft); 322 323 /* 324 * 22.6.1.3.1.5 MMCHS Controller INIT Procedure Start 325 * from 'OMAP35x Applications Processor Technical Reference Manual'. 326 * 327 * During the INIT procedure, the MMCHS controller generates 80 clock 328 * periods. In order to keep the 1ms gap, the MMCHS controller should 329 * be configured to generate a clock whose frequency is smaller or 330 * equal to 80 KHz. 331 */ 332 333 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 334 SDHC_READ(sc, SDHC_CLOCK_CTL) & ~SDHC_SDCLK_ENABLE); 335 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 336 SDHC_READ(sc, SDHC_CLOCK_CTL) & ~sc->sc.sc_clkmsk); 337 clkd = CLKD(80); 338 n = 1; 339 while (clkd & ~(sc->sc.sc_clkmsk >> clksft)) { 340 clkd >>= 1; 341 n <<= 1; 342 } 343 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 344 SDHC_READ(sc, SDHC_CLOCK_CTL) | (clkd << clksft)); 345 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 346 SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_SDCLK_ENABLE); 347 348 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON, 349 bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) | CON_INIT); 350 SDHC_WRITE(sc, SDHC_TRANSFER_MODE, 0x00000000); 351 delay(1000); 352 stat = SDHC_READ(sc, SDHC_NINTR_STATUS); 353 SDHC_WRITE(sc, SDHC_NINTR_STATUS, stat | SDHC_COMMAND_COMPLETE); 354 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON, 355 bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) & ~CON_INIT); 356 SDHC_WRITE(sc, SDHC_NINTR_STATUS, 0xffffffff); 357 358 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 359 SDHC_READ(sc, SDHC_CLOCK_CTL) & ~SDHC_SDCLK_ENABLE); 360 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 361 SDHC_READ(sc, SDHC_CLOCK_CTL) & ~sc->sc.sc_clkmsk); 362 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 363 SDHC_READ(sc, SDHC_CLOCK_CTL) | CLKD(150) << clksft); 364 timo = 3000000; /* XXXX 3 sec. */ 365 while (--timo) { 366 if (SDHC_READ(sc, SDHC_CLOCK_CTL) & SDHC_INTCLK_STABLE) 367 break; 368 delay(1); 369 } 370 if (timo == 0) 371 aprint_error_dev(dev, "ICS timeout\n"); 372 SDHC_WRITE(sc, SDHC_CLOCK_CTL, 373 SDHC_READ(sc, SDHC_CLOCK_CTL) | SDHC_SDCLK_ENABLE); 374 375 #if notyet 376 if (sc->sc_use_adma2) { 377 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON, 378 bus_space_read_4(sc->sc_bst, sc->sc_bsh, MMCHS_CON) | 379 CON_MNS); 380 } 381 #endif 382 } 383 384 static int 385 ti_sdhc_rod(struct sdhc_softc *sc, int on) 386 { 387 struct ti_sdhc_softc *hmsc = (struct ti_sdhc_softc *)sc; 388 uint32_t con; 389 390 con = bus_space_read_4(hmsc->sc_bst, hmsc->sc_bsh, MMCHS_CON); 391 if (on) 392 con |= CON_OD; 393 else 394 con &= ~CON_OD; 395 bus_space_write_4(hmsc->sc_bst, hmsc->sc_bsh, MMCHS_CON, con); 396 397 return 0; 398 } 399 400 static int 401 ti_sdhc_write_protect(struct sdhc_softc *sc) 402 { 403 404 /* Maybe board dependent, using GPIO. Get GPIO-pin from prop? */ 405 return 0; /* XXXXXXX */ 406 } 407 408 static int 409 ti_sdhc_card_detect(struct sdhc_softc *sc) 410 { 411 412 /* Maybe board dependent, using GPIO. Get GPIO-pin from prop? */ 413 return 1; /* XXXXXXXX */ 414 } 415 416 static int 417 ti_sdhc_bus_width(struct sdhc_softc *sc, int width) 418 { 419 struct ti_sdhc_softc *hmsc = (struct ti_sdhc_softc *)sc; 420 uint32_t con, hctl; 421 422 con = bus_space_read_4(hmsc->sc_bst, hmsc->sc_bsh, MMCHS_CON); 423 hctl = SDHC_READ(hmsc, SDHC_HOST_CTL); 424 if (width == 8) { 425 con |= CON_DW8; 426 } else if (width == 4) { 427 con &= ~CON_DW8; 428 hctl |= SDHC_4BIT_MODE; 429 } else { 430 con &= ~CON_DW8; 431 hctl &= ~SDHC_4BIT_MODE; 432 } 433 bus_space_write_4(hmsc->sc_bst, hmsc->sc_bsh, MMCHS_CON, con); 434 SDHC_WRITE(hmsc, SDHC_HOST_CTL, hctl); 435 436 return 0; 437 } 438 439 static int 440 ti_sdhc_edma_init(struct ti_sdhc_softc *sc) 441 { 442 int error, rseg; 443 444 /* Setup bounce buffer */ 445 error = bus_dmamem_alloc(sc->sc.sc_dmat, MAXPHYS, 32, MAXPHYS, 446 sc->sc_edma_segs, 1, &rseg, BUS_DMA_WAITOK); 447 if (error) { 448 aprint_error_dev(sc->sc.sc_dev, 449 "couldn't allocate dmamem: %d\n", error); 450 return error; 451 } 452 KASSERT(rseg == 1); 453 error = bus_dmamem_map(sc->sc.sc_dmat, sc->sc_edma_segs, rseg, MAXPHYS, 454 &sc->sc_edma_bbuf, BUS_DMA_WAITOK); 455 if (error) { 456 aprint_error_dev(sc->sc.sc_dev, "couldn't map dmamem: %d\n", 457 error); 458 return error; 459 } 460 error = bus_dmamap_create(sc->sc.sc_dmat, MAXPHYS, 1, MAXPHYS, 0, 461 BUS_DMA_WAITOK, &sc->sc_edma_dmamap); 462 if (error) { 463 aprint_error_dev(sc->sc.sc_dev, "couldn't create dmamap: %d\n", 464 error); 465 return error; 466 } 467 468 return error; 469 } 470 471 static int 472 ti_sdhc_edma_xfer_data(struct sdhc_softc *sdhc_sc, struct sdmmc_command *cmd) 473 { 474 struct ti_sdhc_softc *sc = device_private(sdhc_sc->sc_dev); 475 const bus_dmamap_t map = cmd->c_dmamap; 476 bool bounce; 477 int error; 478 479 #if notyet 480 bounce = false; 481 for (int seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) { 482 if ((cmd->c_dmamap->dm_segs[seg].ds_addr & 0x1f) != 0 || 483 (cmd->c_dmamap->dm_segs[seg].ds_len & 3) != 0) { 484 bounce = true; 485 break; 486 } 487 } 488 #else 489 bounce = true; 490 #endif 491 492 if (bounce) { 493 error = bus_dmamap_load(sc->sc.sc_dmat, sc->sc_edma_dmamap, 494 sc->sc_edma_bbuf, cmd->c_datalen, NULL, 495 BUS_DMA_NOWAIT | BUS_DMA_WRITE | BUS_DMA_READ); 496 if (error) { 497 device_printf(sc->sc.sc_dev, 498 "couldn't load dmamap: %d\n", error); 499 return error; 500 } 501 502 if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 503 bus_dmamap_sync(sc->sc.sc_dmat, sc->sc_edma_dmamap, 0, 504 cmd->c_datalen, BUS_DMASYNC_PREREAD); 505 } else { 506 memcpy(sc->sc_edma_bbuf, cmd->c_data, cmd->c_datalen); 507 bus_dmamap_sync(sc->sc.sc_dmat, sc->sc_edma_dmamap, 0, 508 cmd->c_datalen, BUS_DMASYNC_PREWRITE); 509 } 510 511 cmd->c_dmamap = sc->sc_edma_dmamap; 512 } 513 514 error = ti_sdhc_edma_transfer(sdhc_sc, cmd); 515 516 if (bounce) { 517 if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 518 bus_dmamap_sync(sc->sc.sc_dmat, sc->sc_edma_dmamap, 0, 519 cmd->c_datalen, BUS_DMASYNC_POSTREAD); 520 } else { 521 bus_dmamap_sync(sc->sc.sc_dmat, sc->sc_edma_dmamap, 0, 522 cmd->c_datalen, BUS_DMASYNC_POSTWRITE); 523 } 524 if (ISSET(cmd->c_flags, SCF_CMD_READ) && error == 0) { 525 memcpy(cmd->c_data, sc->sc_edma_bbuf, cmd->c_datalen); 526 } 527 528 bus_dmamap_unload(sc->sc.sc_dmat, sc->sc_edma_dmamap); 529 530 cmd->c_dmamap = map; 531 } 532 533 return error; 534 } 535 536 static int 537 ti_sdhc_edma_transfer(struct sdhc_softc *sdhc_sc, struct sdmmc_command *cmd) 538 { 539 struct ti_sdhc_softc *sc = device_private(sdhc_sc->sc_dev); 540 kmutex_t *plock = sdhc_host_lock(sc->sc_hosts[0]); 541 int error; 542 int blksize = MIN(cmd->c_datalen, cmd->c_blklen); 543 544 /* 545 * In constant addressing mode, the address must be aligned 546 * to 256-bits/32 bytes. 547 */ 548 KASSERT(cmd->c_dmamap->dm_nsegs == 1); 549 KASSERT((cmd->c_dmamap->dm_segs[0].ds_addr & 0x1f) == 0); 550 551 struct fdtbus_dma_req req; 552 memset(&req, 0, sizeof(req)); 553 req.dreq_segs = cmd->c_dmamap->dm_segs; 554 req.dreq_nsegs = cmd->c_dmamap->dm_nsegs; 555 req.dreq_block_irq = 1; 556 req.dreq_block_multi = 1; 557 req.dreq_dev_opt.opt_bus_width = uimin(cmd->c_datalen, 64); 558 req.dreq_dev_opt.opt_burst_len = uimin(cmd->c_datalen, blksize); 559 req.dreq_dev_phys = sc->sc_edma_fifo; 560 req.dreq_sel = 1; /* use SAM/DAM mode */ 561 562 sc->sc_edma_pending = true; 563 if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 564 req.dreq_dir = FDT_DMA_READ; 565 566 fdtbus_dma_transfer(sc->sc_rx_dma, &req); 567 } else { 568 req.dreq_dir = FDT_DMA_WRITE; 569 570 fdtbus_dma_transfer(sc->sc_tx_dma, &req); 571 } 572 573 KASSERT(mutex_owned(plock)); 574 575 error = 0; 576 while (sc->sc_edma_pending) { 577 error = cv_timedwait(&sc->sc_edma_cv, plock, hz*10); 578 if (error == EWOULDBLOCK) { 579 device_printf(sc->sc.sc_dev, "transfer timeout!\n"); 580 sc->sc_edma_pending = false; 581 error = ETIMEDOUT; 582 break; 583 } 584 } 585 if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 586 fdtbus_dma_halt(sc->sc_rx_dma); 587 } else { 588 fdtbus_dma_halt(sc->sc_tx_dma); 589 } 590 591 return error; 592 } 593 594 static void 595 ti_sdhc_edma_done(void *priv) 596 { 597 struct ti_sdhc_softc *sc = priv; 598 kmutex_t *plock = sdhc_host_lock(sc->sc_hosts[0]); 599 600 mutex_enter(plock); 601 KASSERT(sc->sc_edma_pending == true); 602 sc->sc_edma_pending = false; 603 cv_broadcast(&sc->sc_edma_cv); 604 mutex_exit(plock); 605 } 606