1 /* $OpenBSD: bcm2835_sdhost.c,v 1.2 2022/04/06 18:59:28 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Tobias Heider <tobhe@openbsd.org> 5 * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org> 6 * Copyright (c) 2019 Neil Ashford <ashfordneil0@gmail.com> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 /*- 22 * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca> 23 * All rights reserved. 24 * 25 * Redistribution and use in source and binary forms, with or without 26 * modification, are permitted provided that the following conditions 27 * are met: 28 * 1. Redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer. 30 * 2. Redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 35 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 36 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 37 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 39 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 40 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 41 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 42 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 */ 46 47 #include <sys/types.h> 48 #include <sys/device.h> 49 #include <sys/mutex.h> 50 #include <sys/systm.h> 51 #include <sys/task.h> 52 53 #include <machine/bus.h> 54 #include <machine/fdt.h> 55 #include <machine/intr.h> 56 57 #include <dev/ofw/fdt.h> 58 #include <dev/ofw/ofw_clock.h> 59 #include <dev/ofw/openfirm.h> 60 61 #include <dev/sdmmc/sdmmcreg.h> 62 #include <dev/sdmmc/sdmmcvar.h> 63 64 #include <dev/ic/bcm2835_dmac.h> 65 66 #define SDCMD 0x00 67 #define SDCMD_NEW (1 << 15) 68 #define SDCMD_FAIL (1 << 14) 69 #define SDCMD_BUSY (1 << 11) 70 #define SDCMD_NORESP (1 << 10) 71 #define SDCMD_LONGRESP (1 << 9) 72 #define SDCMD_WRITE (1 << 7) 73 #define SDCMD_READ (1 << 6) 74 #define SDARG 0x04 75 #define SDTOUT 0x08 76 #define SDTOUT_DEFAULT 0xf00000 77 #define SDCDIV 0x0c 78 #define SDCDIV_MASK ((1 << 11) - 1) 79 #define SDRSP0 0x10 80 #define SDRSP1 0x14 81 #define SDRSP2 0x18 82 #define SDRSP3 0x1c 83 #define SDHSTS 0x20 84 #define SDHSTS_BUSY (1 << 10) 85 #define SDHSTS_BLOCK (1 << 9) 86 #define SDHSTS_SDIO (1 << 8) 87 #define SDHSTS_REW_TO (1 << 7) 88 #define SDHSTS_CMD_TO (1 << 6) 89 #define SDHSTS_CRC16_E (1 << 5) 90 #define SDHSTS_CRC7_E (1 << 4) 91 #define SDHSTS_FIFO_E (1 << 3) 92 #define SDHSTS_DATA (1 << 0) 93 #define SDHSTS_TO_MASK (SDHSTS_REW_TO | SDHSTS_CMD_TO) 94 #define SDHSTS_E_MASK (SDHSTS_CRC16_E | SDHSTS_CRC7_E | SDHSTS_FIFO_E) 95 #define SDVDD 0x30 96 #define SDVDD_POWER (1 << 0) 97 #define SDEDM 0x34 98 #define SDEDM_RD_FIFO_MASK (0x1f << 14) 99 #define SDEDM_RD_FIFO_SHIFT 14 100 #define SDEDM_WR_FIFO_MASK (0x1f << 9) 101 #define SDEDM_WR_FIFO_SHIFT 9 102 #define SDEDM_FIFO_LEVEL(x) (((x) >> 4) & 0x1f) 103 #define SDHCFG 0x38 104 #define SDHCFG_BUSY_EN (1 << 10) 105 #define SDHCFG_BLOCK_EN (1 << 8) 106 #define SDHCFG_SDIO_EN (1 << 5) 107 #define SDHCFG_DATA_EN (1 << 4) 108 #define SDHCFG_SLOW (1 << 3) 109 #define SDHCFG_WIDE_EXT (1 << 2) 110 #define SDHCFG_WIDE_INT (1 << 1) 111 #define SDHCFG_REL_CMD (1 << 0) 112 #define SDHBCT 0x3c 113 #define SDDATA 0x40 114 #define SDHBLC 0x50 115 116 #define SDHOST_FIFO_SIZE 16 117 118 struct bcmsdhost_softc { 119 struct device sc_dev; 120 bus_space_tag_t sc_iot; 121 bus_space_handle_t sc_ioh; 122 bus_addr_t sc_addr; 123 bus_size_t sc_size; 124 125 void *sc_ih; 126 127 bus_dma_tag_t sc_dmat; 128 bus_dmamap_t sc_dmamap; 129 bus_dma_segment_t sc_segs[1]; 130 struct bcmdmac_conblk *sc_cblk; 131 struct bcmdmac_channel *sc_dmac; 132 133 struct mutex sc_intr_lock; 134 uint32_t sc_intr_hsts; 135 uint32_t sc_intr_cv; 136 uint32_t sc_dma_cv; 137 138 unsigned int sc_rate; 139 140 uint32_t sc_dma_status; 141 uint32_t sc_dma_error; 142 143 struct device *sc_sdmmc; 144 }; 145 146 int bcmsdhost_match(struct device *, void *, void *); 147 void bcmsdhost_attach(struct device *, struct device *, void *); 148 149 const struct cfattach bcmsdhost_ca = { 150 sizeof(struct bcmsdhost_softc), 151 bcmsdhost_match, 152 bcmsdhost_attach 153 }; 154 155 int bcmsdhost_host_reset(sdmmc_chipset_handle_t); 156 uint32_t bcmsdhost_host_ocr(sdmmc_chipset_handle_t); 157 int bcmsdhost_host_maxblklen(sdmmc_chipset_handle_t); 158 int bcmsdhost_card_detect(sdmmc_chipset_handle_t); 159 int bcmsdhost_bus_power(sdmmc_chipset_handle_t, uint32_t); 160 int bcmsdhost_bus_clock(sdmmc_chipset_handle_t, int, int); 161 int bcmsdhost_bus_width(sdmmc_chipset_handle_t, int); 162 void bcmsdhost_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); 163 164 struct sdmmc_chip_functions bcmsdhost_chip_functions = { 165 .host_reset = bcmsdhost_host_reset, 166 .host_ocr = bcmsdhost_host_ocr, 167 .host_maxblklen = bcmsdhost_host_maxblklen, 168 .card_detect = bcmsdhost_card_detect, 169 .bus_power = bcmsdhost_bus_power, 170 .bus_clock = bcmsdhost_bus_clock, 171 .bus_width = bcmsdhost_bus_width, 172 .exec_command = bcmsdhost_exec_command, 173 }; 174 175 int bcmsdhost_wait_idle(struct bcmsdhost_softc *sc, int timeout); 176 int bcmsdhost_dma_wait(struct bcmsdhost_softc *, struct sdmmc_command *); 177 int bcmsdhost_dma_transfer(struct bcmsdhost_softc *, struct sdmmc_command *); 178 void bcmsdhost_dma_done(uint32_t, uint32_t, void *); 179 int bcmsdhost_pio_transfer(struct bcmsdhost_softc *, struct sdmmc_command *); 180 int bcmsdhost_intr(void *); 181 182 struct cfdriver bcmsdhost_cd = { NULL, "bcmsdhost", DV_DISK }; 183 184 static inline void 185 bcmsdhost_write(struct bcmsdhost_softc *sc, bus_size_t offset, uint32_t value) 186 { 187 bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, value); 188 } 189 190 static inline uint32_t 191 bcmsdhost_read(struct bcmsdhost_softc *sc, bus_size_t offset) 192 { 193 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset); 194 } 195 196 int 197 bcmsdhost_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, "brcm,bcm2835-sdhost"); 202 } 203 204 void 205 bcmsdhost_attach(struct device *parent, struct device *self, void *aux) 206 { 207 struct bcmsdhost_softc *sc = (struct bcmsdhost_softc *)self; 208 struct fdt_attach_args *faa = aux; 209 struct sdmmcbus_attach_args saa; 210 int rseg; 211 212 if (faa->fa_nreg < 1) { 213 printf(": no registers\n"); 214 return; 215 } 216 217 mtx_init(&sc->sc_intr_lock, IPL_BIO); 218 219 sc->sc_iot = faa->fa_iot; 220 sc->sc_dmat = faa->fa_dmat; 221 sc->sc_size = faa->fa_reg[0].size; 222 sc->sc_addr = faa->fa_reg[0].addr; 223 224 if (bus_space_map(sc->sc_iot, sc->sc_addr, sc->sc_size, 0, 225 &sc->sc_ioh)) { 226 printf(": can't map registers\n"); 227 return; 228 } 229 230 clock_enable_all(faa->fa_node); 231 sc->sc_rate = clock_get_frequency_idx(faa->fa_node, 0); 232 233 sc->sc_dmac = bcmdmac_alloc(BCMDMAC_TYPE_NORMAL, IPL_SDMMC, 234 bcmsdhost_dma_done, sc); 235 if (sc->sc_dmac == NULL) { 236 printf(": can't allocate DMA channel\n"); 237 goto clean_clocks; 238 } 239 240 sc->sc_dmat = faa->fa_dmat; 241 if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, 242 sc->sc_segs, 1, &rseg, BUS_DMA_WAITOK)) { 243 printf(": can't allocate DMA memory\n"); 244 goto clean_dmac_channel; 245 } 246 247 if (bus_dmamem_map(sc->sc_dmat, sc->sc_segs, rseg, PAGE_SIZE, 248 (char **)&sc->sc_cblk, BUS_DMA_WAITOK)) { 249 printf(": can't map DMA memory\n"); 250 goto clean_dmamap_free; 251 } 252 253 memset(sc->sc_cblk, 0, PAGE_SIZE); 254 255 if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0, 256 BUS_DMA_WAITOK, &sc->sc_dmamap)) { 257 printf(": can't create DMA map\n"); 258 goto clean_dmamap_unmap; 259 } 260 261 if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_cblk, PAGE_SIZE, 262 NULL, BUS_DMA_WAITOK | BUS_DMA_WRITE)) { 263 printf(": can't load DMA map\n"); 264 goto clean_dmamap_destroy; 265 } 266 267 sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_SDMMC, bcmsdhost_intr, 268 sc, sc->sc_dev.dv_xname); 269 if (sc->sc_ih == NULL) { 270 printf(": can't establish interrupt\n"); 271 goto clean_dmamap; 272 } 273 274 printf(": %u MHz base clock\n", sc->sc_rate / 1000000); 275 276 bcmsdhost_write(sc, SDHCFG, SDHCFG_BUSY_EN); 277 bcmsdhost_bus_clock(sc, 400, false); 278 bcmsdhost_host_reset(sc); 279 bcmsdhost_bus_width(sc, 1); 280 281 memset(&saa, 0, sizeof(saa)); 282 saa.saa_busname = "sdmmc"; 283 saa.sct = &bcmsdhost_chip_functions; 284 saa.sch = sc; 285 saa.dmat = sc->sc_dmat; 286 saa.flags = SMF_SD_MODE | SMF_STOP_AFTER_MULTIPLE; 287 saa.caps = SMC_CAPS_DMA | SMC_CAPS_4BIT_MODE | 288 SMC_CAPS_SD_HIGHSPEED | SMC_CAPS_MMC_HIGHSPEED; 289 290 sc->sc_sdmmc = config_found(&sc->sc_dev, &saa, NULL); 291 return; 292 293 clean_dmamap: 294 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); 295 clean_dmamap_destroy: 296 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 297 clean_dmamap_unmap: 298 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_cblk, PAGE_SIZE); 299 clean_dmamap_free: 300 bus_dmamem_free(sc->sc_dmat, sc->sc_segs, 1); 301 clean_dmac_channel: 302 bcmdmac_free(sc->sc_dmac); 303 clean_clocks: 304 clock_disable_all(faa->fa_node); 305 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); 306 } 307 308 int 309 bcmsdhost_host_reset(sdmmc_chipset_handle_t sch) 310 { 311 struct bcmsdhost_softc *sc = sch; 312 uint32_t edm; 313 314 bcmsdhost_write(sc, SDVDD, 0); 315 bcmsdhost_write(sc, SDCMD, 0); 316 bcmsdhost_write(sc, SDARG, 0); 317 bcmsdhost_write(sc, SDTOUT, SDTOUT_DEFAULT); 318 bcmsdhost_write(sc, SDCDIV, 0); 319 bcmsdhost_write(sc, SDHSTS, bcmsdhost_read(sc, SDHSTS)); 320 bcmsdhost_write(sc, SDHCFG, 0); 321 bcmsdhost_write(sc, SDHBCT, 0); 322 bcmsdhost_write(sc, SDHBLC, 0); 323 324 edm = bcmsdhost_read(sc, SDEDM); 325 edm &= ~(SDEDM_RD_FIFO_MASK | SDEDM_WR_FIFO_MASK); 326 edm |= (4 << SDEDM_RD_FIFO_SHIFT); 327 edm |= (4 << SDEDM_WR_FIFO_SHIFT); 328 bcmsdhost_write(sc, SDEDM, edm); 329 330 delay(20000); 331 bcmsdhost_write(sc, SDVDD, SDVDD_POWER); 332 delay(20000); 333 334 bcmsdhost_write(sc, SDHCFG, bcmsdhost_read(sc, SDHCFG)); 335 bcmsdhost_write(sc, SDCDIV, bcmsdhost_read(sc, SDCDIV)); 336 337 return 0; 338 } 339 340 uint32_t 341 bcmsdhost_host_ocr(sdmmc_chipset_handle_t sch) 342 { 343 return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 344 } 345 346 int 347 bcmsdhost_host_maxblklen(sdmmc_chipset_handle_t sch) 348 { 349 return 1024; 350 } 351 352 int 353 bcmsdhost_card_detect(sdmmc_chipset_handle_t sch) 354 { 355 return 1; 356 } 357 358 int 359 bcmsdhost_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 360 { 361 return 0; 362 } 363 364 int 365 bcmsdhost_bus_clock(sdmmc_chipset_handle_t sch, int freq, int ddr) 366 { 367 struct bcmsdhost_softc *sc = sch; 368 unsigned int target_rate = freq * 1000; 369 int div; 370 371 if (freq == 0) 372 div = SDCDIV_MASK; 373 else { 374 div = sc->sc_rate / target_rate; 375 if (div < 2) 376 div = 2; 377 if ((sc->sc_rate / div) > target_rate) 378 div++; 379 div -= 2; 380 if (div > SDCDIV_MASK) 381 div = SDCDIV_MASK; 382 } 383 384 bcmsdhost_write(sc, SDCDIV, div); 385 386 return 0; 387 } 388 389 int 390 bcmsdhost_bus_width(sdmmc_chipset_handle_t sch, int width) 391 { 392 struct bcmsdhost_softc *sc = sch; 393 uint32_t hcfg; 394 395 hcfg = bcmsdhost_read(sc, SDHCFG); 396 if (width == 4) 397 hcfg |= SDHCFG_WIDE_EXT; 398 else 399 hcfg &= ~SDHCFG_WIDE_EXT; 400 hcfg |= (SDHCFG_WIDE_INT | SDHCFG_SLOW); 401 bcmsdhost_write(sc, SDHCFG, hcfg); 402 403 return 0; 404 } 405 406 void 407 bcmsdhost_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 408 { 409 struct bcmsdhost_softc *sc = sch; 410 uint32_t cmdval, hcfg; 411 unsigned int nblks; 412 413 mtx_enter(&sc->sc_intr_lock); 414 415 hcfg = bcmsdhost_read(sc, SDHCFG); 416 bcmsdhost_write(sc, SDHCFG, hcfg | SDHCFG_BUSY_EN); 417 418 sc->sc_intr_hsts = 0; 419 420 cmd->c_error = bcmsdhost_wait_idle(sc, 5000); 421 if (cmd->c_error != 0) 422 goto done; 423 424 cmdval = SDCMD_NEW; 425 if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT)) 426 cmdval |= SDCMD_NORESP; 427 if (ISSET(cmd->c_flags, SCF_RSP_136)) 428 cmdval |= SDCMD_LONGRESP; 429 if (ISSET(cmd->c_flags, SCF_RSP_BSY)) 430 cmdval |= SDCMD_BUSY; 431 432 if (cmd->c_datalen > 0) { 433 if (ISSET(cmd->c_flags, SCF_CMD_READ)) 434 cmdval |= SDCMD_READ; 435 else 436 cmdval |= SDCMD_WRITE; 437 438 nblks = cmd->c_datalen / cmd->c_blklen; 439 if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0) 440 ++nblks; 441 442 bcmsdhost_write(sc, SDHBCT, cmd->c_blklen); 443 bcmsdhost_write(sc, SDHBLC, nblks); 444 } 445 446 if (cmd->c_datalen > 0 && cmd->c_dmamap) { 447 cmd->c_resid = cmd->c_datalen; 448 cmd->c_error = bcmsdhost_dma_transfer(sc, cmd); 449 if (cmd->c_error != 0) 450 goto done; 451 } 452 453 bcmsdhost_write(sc, SDARG, cmd->c_arg); 454 bcmsdhost_write(sc, SDCMD, cmdval | cmd->c_opcode); 455 456 if (cmd->c_datalen > 0 && cmd->c_dmamap) { 457 cmd->c_error = bcmsdhost_dma_wait(sc, cmd); 458 if (cmd->c_error != 0) 459 goto done; 460 } else if (cmd->c_datalen > 0) { 461 cmd->c_resid = cmd->c_datalen; 462 cmd->c_error = bcmsdhost_pio_transfer(sc, cmd); 463 if (cmd->c_error != 0) 464 goto done; 465 } 466 467 cmd->c_error = bcmsdhost_wait_idle(sc, 5000); 468 if (cmd->c_error != 0) 469 goto done; 470 471 if (ISSET(bcmsdhost_read(sc, SDCMD), SDCMD_FAIL)) { 472 cmd->c_error = EIO; 473 goto done; 474 } 475 476 if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { 477 if (ISSET(cmd->c_flags, SCF_RSP_136)) { 478 cmd->c_resp[0] = bcmsdhost_read(sc, SDRSP0); 479 cmd->c_resp[1] = bcmsdhost_read(sc, SDRSP1); 480 cmd->c_resp[2] = bcmsdhost_read(sc, SDRSP2); 481 cmd->c_resp[3] = bcmsdhost_read(sc, SDRSP3); 482 if (ISSET(cmd->c_flags, SCF_RSP_CRC)) { 483 cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | 484 (cmd->c_resp[1] << 24); 485 cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | 486 (cmd->c_resp[2] << 24); 487 cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | 488 (cmd->c_resp[3] << 24); 489 cmd->c_resp[3] = (cmd->c_resp[3] >> 8); 490 } 491 } else { 492 cmd->c_resp[0] = bcmsdhost_read(sc, SDRSP0); 493 } 494 } 495 496 done: 497 cmd->c_flags |= SCF_ITSDONE; 498 bcmsdhost_write(sc, SDHCFG, hcfg); 499 bcmsdhost_write(sc, SDHSTS, bcmsdhost_read(sc, SDHSTS)); 500 mtx_leave(&sc->sc_intr_lock); 501 } 502 503 int 504 bcmsdhost_wait_idle(struct bcmsdhost_softc *sc, int timeout) 505 { 506 int retry = timeout * 1000; 507 508 while (--retry > 0) { 509 const uint32_t cmd = bcmsdhost_read(sc, SDCMD); 510 if (!ISSET(cmd, SDCMD_NEW)) 511 return 0; 512 delay(1); 513 } 514 515 return ETIMEDOUT; 516 } 517 518 int 519 bcmsdhost_dma_wait(struct bcmsdhost_softc *sc, struct sdmmc_command *cmd) 520 { 521 int error = 0; 522 523 while (sc->sc_dma_status == 0 && sc->sc_dma_error == 0) { 524 error = msleep_nsec(&sc->sc_dma_cv, &sc->sc_intr_lock, 525 PPAUSE, "pause", SEC_TO_NSEC(5)); 526 if (error == EWOULDBLOCK) { 527 printf("%s: transfer timeout!\n", DEVNAME(sc)); 528 bcmdmac_halt(sc->sc_dmac); 529 error = ETIMEDOUT; 530 goto error; 531 } 532 } 533 534 if (ISSET(sc->sc_dma_status, DMAC_CS_END)) { 535 cmd->c_resid = 0; 536 error = 0; 537 } else { 538 error = EIO; 539 } 540 541 error: 542 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, 543 sc->sc_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); 544 545 return error; 546 } 547 548 int 549 bcmsdhost_dma_transfer(struct bcmsdhost_softc *sc, struct sdmmc_command *cmd) 550 { 551 const bus_addr_t ad_sddata = sc->sc_addr + SDDATA; 552 size_t seg; 553 int error; 554 555 for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) { 556 if (sizeof(cmd->c_dmamap->dm_segs[seg].ds_addr) > 557 sizeof(sc->sc_cblk[seg].cb_source_ad)) { 558 if (cmd->c_dmamap->dm_segs[seg].ds_addr > 0xffffffffU) 559 return EFBIG; 560 } 561 sc->sc_cblk[seg].cb_ti = 13 * DMAC_TI_PERMAP_BASE; 562 sc->sc_cblk[seg].cb_txfr_len = 563 cmd->c_dmamap->dm_segs[seg].ds_len; 564 565 /* 566 * All transfers are assumed to be multiples of 32 bits 567 */ 568 KASSERTMSG((sc->sc_cblk[seg].cb_txfr_len & 0x3) == 0, 569 "seg %zu len %d", seg, sc->sc_cblk[seg].cb_txfr_len); 570 /* Use 128-bit mode if transfer is a multiple of 16 bytes. */ 571 if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 572 sc->sc_cblk[seg].cb_ti |= DMAC_TI_DEST_INC; 573 if ((sc->sc_cblk[seg].cb_txfr_len & 0xf) == 0) 574 sc->sc_cblk[seg].cb_ti |= DMAC_TI_DEST_WIDTH; 575 sc->sc_cblk[seg].cb_ti |= DMAC_TI_SRC_DREQ; 576 sc->sc_cblk[seg].cb_source_ad = ad_sddata; 577 sc->sc_cblk[seg].cb_dest_ad = 578 cmd->c_dmamap->dm_segs[seg].ds_addr; 579 } else { 580 sc->sc_cblk[seg].cb_ti |= DMAC_TI_SRC_INC; 581 if ((sc->sc_cblk[seg].cb_txfr_len & 0xf) == 0) 582 sc->sc_cblk[seg].cb_ti |= DMAC_TI_SRC_WIDTH; 583 sc->sc_cblk[seg].cb_ti |= DMAC_TI_DEST_DREQ; 584 sc->sc_cblk[seg].cb_ti |= DMAC_TI_WAIT_RESP; 585 sc->sc_cblk[seg].cb_source_ad = 586 cmd->c_dmamap->dm_segs[seg].ds_addr; 587 sc->sc_cblk[seg].cb_dest_ad = ad_sddata; 588 } 589 sc->sc_cblk[seg].cb_stride = 0; 590 if (seg == cmd->c_dmamap->dm_nsegs - 1) { 591 sc->sc_cblk[seg].cb_ti |= DMAC_TI_INTEN; 592 sc->sc_cblk[seg].cb_nextconbk = 0; 593 } else { 594 sc->sc_cblk[seg].cb_nextconbk = 595 sc->sc_dmamap->dm_segs[0].ds_addr + 596 sizeof(struct bcmdmac_conblk) * (seg + 1); 597 } 598 sc->sc_cblk[seg].cb_padding[0] = 0; 599 sc->sc_cblk[seg].cb_padding[1] = 0; 600 } 601 602 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0, 603 sc->sc_dmamap->dm_mapsize, BUS_DMASYNC_PREWRITE); 604 605 sc->sc_dma_status = 0; 606 sc->sc_dma_error = 0; 607 608 bcmdmac_set_conblk_addr(sc->sc_dmac, sc->sc_dmamap->dm_segs[0].ds_addr); 609 error = bcmdmac_transfer(sc->sc_dmac); 610 611 if (error) 612 return error; 613 614 return 0; 615 } 616 617 void 618 bcmsdhost_dma_done(uint32_t status, uint32_t error, void *arg) 619 { 620 struct bcmsdhost_softc *sc = arg; 621 622 mtx_enter(&sc->sc_intr_lock); 623 624 sc->sc_dma_status = status; 625 sc->sc_dma_error = error; 626 wakeup(&sc->sc_dma_cv); 627 628 mtx_leave(&sc->sc_intr_lock); 629 } 630 631 int 632 bcmsdhost_pio_transfer(struct bcmsdhost_softc *sc, struct sdmmc_command *cmd) 633 { 634 uint32_t *datap = cmd->c_data; 635 uint32_t edm, status; 636 int count; 637 638 if ((cmd->c_datalen % 4) != 0) 639 return EINVAL; 640 641 while (cmd->c_resid > 0) { 642 edm = bcmsdhost_read(sc, SDEDM); 643 count = SDEDM_FIFO_LEVEL(edm); 644 if (!ISSET(cmd->c_flags, SCF_CMD_READ)) 645 count = SDHOST_FIFO_SIZE - count; 646 647 if (count == 0) { 648 status = bcmsdhost_read(sc, SDHSTS); 649 if (status & SDHSTS_E_MASK) 650 return EIO; 651 if (status & SDHSTS_TO_MASK) 652 return ETIMEDOUT; 653 } 654 655 while (count-- > 0 && cmd->c_resid > 0) { 656 if (ISSET(cmd->c_flags, SCF_CMD_READ)) 657 *(datap++) = bcmsdhost_read(sc, SDDATA); 658 else 659 bcmsdhost_write(sc, SDDATA, *(datap++)); 660 661 cmd->c_resid -= 4; 662 count--; 663 } 664 } 665 666 status = bcmsdhost_read(sc, SDHSTS); 667 if (status & SDHSTS_E_MASK) 668 return EIO; 669 if (status & SDHSTS_TO_MASK) 670 return ETIMEDOUT; 671 return 0; 672 } 673 674 int 675 bcmsdhost_intr(void *arg) 676 { 677 struct bcmsdhost_softc *sc = arg; 678 uint32_t hsts; 679 680 mtx_enter(&sc->sc_intr_lock); 681 682 hsts = bcmsdhost_read(sc, SDHSTS); 683 if (hsts) { 684 bcmsdhost_write(sc, SDHSTS, hsts); 685 sc->sc_intr_hsts |= hsts; 686 wakeup(&sc->sc_intr_cv); 687 } 688 689 mtx_leave(&sc->sc_intr_lock); 690 691 return hsts ? 1 : 0; 692 } 693