1 /* $NetBSD: dwc_mmc.c,v 1.6 2015/01/22 17:06:15 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "opt_dwc_mmc.h" 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.6 2015/01/22 17:06:15 jmcneill Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/bus.h> 36 #include <sys/device.h> 37 #include <sys/intr.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 41 #include <dev/sdmmc/sdmmcvar.h> 42 #include <dev/sdmmc/sdmmcchip.h> 43 #include <dev/sdmmc/sdmmc_ioreg.h> 44 45 #include <dev/ic/dwc_mmc_reg.h> 46 #include <dev/ic/dwc_mmc_var.h> 47 48 static int dwc_mmc_host_reset(sdmmc_chipset_handle_t); 49 static uint32_t dwc_mmc_host_ocr(sdmmc_chipset_handle_t); 50 static int dwc_mmc_host_maxblklen(sdmmc_chipset_handle_t); 51 static int dwc_mmc_card_detect(sdmmc_chipset_handle_t); 52 static int dwc_mmc_write_protect(sdmmc_chipset_handle_t); 53 static int dwc_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t); 54 static int dwc_mmc_bus_clock(sdmmc_chipset_handle_t, int); 55 static int dwc_mmc_bus_width(sdmmc_chipset_handle_t, int); 56 static int dwc_mmc_bus_rod(sdmmc_chipset_handle_t, int); 57 static void dwc_mmc_exec_command(sdmmc_chipset_handle_t, 58 struct sdmmc_command *); 59 static void dwc_mmc_card_enable_intr(sdmmc_chipset_handle_t, int); 60 static void dwc_mmc_card_intr_ack(sdmmc_chipset_handle_t); 61 62 static int dwc_mmc_set_clock(struct dwc_mmc_softc *, u_int); 63 static int dwc_mmc_update_clock(struct dwc_mmc_softc *); 64 static int dwc_mmc_wait_rint(struct dwc_mmc_softc *, uint32_t, int); 65 static int dwc_mmc_pio_wait(struct dwc_mmc_softc *, 66 struct sdmmc_command *); 67 static int dwc_mmc_pio_transfer(struct dwc_mmc_softc *, 68 struct sdmmc_command *); 69 70 #ifdef DWC_MMC_DEBUG 71 static void dwc_mmc_print_rint(struct dwc_mmc_softc *, const char *, 72 uint32_t); 73 #endif 74 75 void dwc_mmc_dump_regs(void); 76 77 static struct sdmmc_chip_functions dwc_mmc_chip_functions = { 78 .host_reset = dwc_mmc_host_reset, 79 .host_ocr = dwc_mmc_host_ocr, 80 .host_maxblklen = dwc_mmc_host_maxblklen, 81 .card_detect = dwc_mmc_card_detect, 82 .write_protect = dwc_mmc_write_protect, 83 .bus_power = dwc_mmc_bus_power, 84 .bus_clock = dwc_mmc_bus_clock, 85 .bus_width = dwc_mmc_bus_width, 86 .bus_rod = dwc_mmc_bus_rod, 87 .exec_command = dwc_mmc_exec_command, 88 .card_enable_intr = dwc_mmc_card_enable_intr, 89 .card_intr_ack = dwc_mmc_card_intr_ack, 90 }; 91 92 #define MMC_WRITE(sc, reg, val) \ 93 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 94 #define MMC_READ(sc, reg) \ 95 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 96 97 void 98 dwc_mmc_init(struct dwc_mmc_softc *sc) 99 { 100 struct sdmmcbus_attach_args saa; 101 102 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO); 103 cv_init(&sc->sc_intr_cv, "dwcmmcirq"); 104 105 dwc_mmc_host_reset(sc); 106 dwc_mmc_bus_width(sc, 1); 107 108 memset(&saa, 0, sizeof(saa)); 109 saa.saa_busname = "sdmmc"; 110 saa.saa_sct = &dwc_mmc_chip_functions; 111 saa.saa_sch = sc; 112 saa.saa_clkmin = 400; 113 if (sc->sc_clock_max) { 114 saa.saa_clkmax = sc->sc_clock_max; 115 } else { 116 saa.saa_clkmax = sc->sc_clock_freq / 1000; 117 } 118 saa.saa_caps = SMC_CAPS_4BIT_MODE| 119 SMC_CAPS_8BIT_MODE| 120 SMC_CAPS_SD_HIGHSPEED| 121 SMC_CAPS_MMC_HIGHSPEED| 122 SMC_CAPS_AUTO_STOP; 123 124 #if notyet 125 saa.saa_dmat = sc->sc_dmat; 126 saa.saa_caps |= SMC_CAPS_DMA| 127 SMC_CAPS_MULTI_SEG_DMA; 128 #endif 129 130 sc->sc_sdmmc_dev = config_found(sc->sc_dev, &saa, NULL); 131 } 132 133 int 134 dwc_mmc_intr(void *priv) 135 { 136 struct dwc_mmc_softc *sc = priv; 137 uint32_t mint, rint; 138 139 mutex_enter(&sc->sc_intr_lock); 140 rint = MMC_READ(sc, DWC_MMC_RINTSTS_REG); 141 mint = MMC_READ(sc, DWC_MMC_MINTSTS_REG); 142 if (!rint && !mint) { 143 mutex_exit(&sc->sc_intr_lock); 144 return 0; 145 } 146 MMC_WRITE(sc, DWC_MMC_RINTSTS_REG, rint); 147 MMC_WRITE(sc, DWC_MMC_MINTSTS_REG, mint); 148 149 #ifdef DWC_MMC_DEBUG 150 dwc_mmc_print_rint(sc, "irq", rint); 151 #endif 152 153 if (rint & DWC_MMC_INT_CARDDET) { 154 rint &= ~DWC_MMC_INT_CARDDET; 155 if (sc->sc_sdmmc_dev) { 156 sdmmc_needs_discover(sc->sc_sdmmc_dev); 157 } 158 } 159 160 if (rint) { 161 sc->sc_intr_rint |= rint; 162 cv_broadcast(&sc->sc_intr_cv); 163 } 164 165 mutex_exit(&sc->sc_intr_lock); 166 167 return 1; 168 } 169 170 static int 171 dwc_mmc_set_clock(struct dwc_mmc_softc *sc, u_int freq) 172 { 173 u_int pll_freq, clk_div; 174 175 pll_freq = sc->sc_clock_freq / 1000; 176 clk_div = (pll_freq / freq) >> 1; 177 if (pll_freq % freq) 178 clk_div++; 179 180 MMC_WRITE(sc, DWC_MMC_CLKDIV_REG, 181 __SHIFTIN(clk_div, DWC_MMC_CLKDIV_CLK_DIVIDER0)); 182 return dwc_mmc_update_clock(sc); 183 } 184 185 static int 186 dwc_mmc_update_clock(struct dwc_mmc_softc *sc) 187 { 188 uint32_t cmd; 189 int retry; 190 191 cmd = DWC_MMC_CMD_START_CMD | 192 DWC_MMC_CMD_UPDATE_CLOCK_REGS_ONLY | 193 DWC_MMC_CMD_WAIT_PRVDATA_COMPLETE; 194 195 if (sc->sc_flags & DWC_MMC_F_USE_HOLD_REG) 196 cmd |= DWC_MMC_CMD_USE_HOLD_REG; 197 198 MMC_WRITE(sc, DWC_MMC_CMD_REG, cmd); 199 retry = 0xfffff; 200 while (--retry > 0) { 201 cmd = MMC_READ(sc, DWC_MMC_CMD_REG); 202 if ((cmd & DWC_MMC_CMD_START_CMD) == 0) 203 break; 204 delay(10); 205 } 206 207 if (retry == 0) { 208 device_printf(sc->sc_dev, "timeout updating clock\n"); 209 return ETIMEDOUT; 210 } 211 212 return 0; 213 } 214 215 static int 216 dwc_mmc_wait_rint(struct dwc_mmc_softc *sc, uint32_t mask, int timeout) 217 { 218 int retry, error; 219 220 KASSERT(mutex_owned(&sc->sc_intr_lock)); 221 222 if (sc->sc_intr_rint & mask) 223 return 0; 224 225 retry = timeout / hz; 226 227 while (retry > 0) { 228 error = cv_timedwait(&sc->sc_intr_cv, &sc->sc_intr_lock, hz); 229 if (error && error != EWOULDBLOCK) 230 return error; 231 if (sc->sc_intr_rint & mask) 232 return 0; 233 --retry; 234 } 235 236 return ETIMEDOUT; 237 } 238 239 static int 240 dwc_mmc_pio_wait(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd) 241 { 242 int retry = 0xfffff; 243 uint32_t bit = (cmd->c_flags & SCF_CMD_READ) ? 244 DWC_MMC_STATUS_FIFO_EMPTY : DWC_MMC_STATUS_FIFO_FULL; 245 246 while (--retry > 0) { 247 uint32_t status = MMC_READ(sc, DWC_MMC_STATUS_REG); 248 if (!(status & bit)) 249 return 0; 250 delay(10); 251 } 252 253 #ifdef DWC_MMC_DEBUG 254 device_printf(sc->sc_dev, "%s: timed out\n", __func__); 255 #endif 256 257 return ETIMEDOUT; 258 } 259 260 static int 261 dwc_mmc_pio_transfer(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd) 262 { 263 uint32_t *datap = (uint32_t *)cmd->c_data; 264 int i; 265 266 for (i = 0; i < (cmd->c_resid >> 2); i++) { 267 if (dwc_mmc_pio_wait(sc, cmd)) 268 return ETIMEDOUT; 269 if (cmd->c_flags & SCF_CMD_READ) { 270 datap[i] = MMC_READ(sc, DWC_MMC_FIFO_BASE_REG); 271 } else { 272 MMC_WRITE(sc, DWC_MMC_FIFO_BASE_REG, datap[i]); 273 } 274 } 275 276 return 0; 277 } 278 279 static int 280 dwc_mmc_host_reset(sdmmc_chipset_handle_t sch) 281 { 282 struct dwc_mmc_softc *sc = sch; 283 int retry = 1000; 284 uint32_t ctrl, fifoth; 285 uint32_t rx_wmark, tx_wmark; 286 287 if (sc->sc_flags & DWC_MMC_F_PWREN_CLEAR) { 288 MMC_WRITE(sc, DWC_MMC_PWREN_REG, 0); 289 } else { 290 MMC_WRITE(sc, DWC_MMC_PWREN_REG, DWC_MMC_PWREN_POWER_ENABLE); 291 } 292 293 MMC_WRITE(sc, DWC_MMC_CTRL_REG, DWC_MMC_CTRL_RESET_ALL); 294 while (--retry > 0) { 295 ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); 296 if ((ctrl & DWC_MMC_CTRL_RESET_ALL) == 0) 297 break; 298 delay(100); 299 } 300 301 MMC_WRITE(sc, DWC_MMC_CLKSRC_REG, 0); 302 303 MMC_WRITE(sc, DWC_MMC_TMOUT_REG, 0xffffff40); 304 MMC_WRITE(sc, DWC_MMC_RINTSTS_REG, 0xffffffff); 305 306 MMC_WRITE(sc, DWC_MMC_INTMASK_REG, 307 DWC_MMC_INT_CD | DWC_MMC_INT_ACD | DWC_MMC_INT_DTO | 308 DWC_MMC_INT_ERROR | DWC_MMC_INT_CARDDET | 309 DWC_MMC_INT_RXDR | DWC_MMC_INT_TXDR); 310 311 rx_wmark = (sc->sc_fifo_depth / 2) - 1; 312 tx_wmark = sc->sc_fifo_depth / 2; 313 fifoth = __SHIFTIN(DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_16, 314 DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE); 315 fifoth |= __SHIFTIN(rx_wmark, DWC_MMC_FIFOTH_RX_WMARK); 316 fifoth |= __SHIFTIN(tx_wmark, DWC_MMC_FIFOTH_TX_WMARK); 317 MMC_WRITE(sc, DWC_MMC_FIFOTH_REG, fifoth); 318 319 ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); 320 ctrl |= DWC_MMC_CTRL_INT_ENABLE; 321 MMC_WRITE(sc, DWC_MMC_CTRL_REG, ctrl); 322 323 return 0; 324 } 325 326 static uint32_t 327 dwc_mmc_host_ocr(sdmmc_chipset_handle_t sch) 328 { 329 return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 330 } 331 332 static int 333 dwc_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) 334 { 335 return 32768; 336 } 337 338 static int 339 dwc_mmc_card_detect(sdmmc_chipset_handle_t sch) 340 { 341 struct dwc_mmc_softc *sc = sch; 342 uint32_t cdetect; 343 344 cdetect = MMC_READ(sc, DWC_MMC_CDETECT_REG); 345 return !(cdetect & DWC_MMC_CDETECT_CARD_DETECT_N); 346 } 347 348 static int 349 dwc_mmc_write_protect(sdmmc_chipset_handle_t sch) 350 { 351 struct dwc_mmc_softc *sc = sch; 352 uint32_t wrtprt; 353 354 wrtprt = MMC_READ(sc, DWC_MMC_WRTPRT_REG); 355 return !!(wrtprt & DWC_MMC_WRTPRT_WRITE_PROTECT); 356 } 357 358 static int 359 dwc_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 360 { 361 return 0; 362 } 363 364 static int 365 dwc_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) 366 { 367 struct dwc_mmc_softc *sc = sch; 368 uint32_t clkena; 369 370 #ifdef DWC_MMC_DEBUG 371 device_printf(sc->sc_dev, "%s: freq %d\n", __func__, freq); 372 #endif 373 374 MMC_WRITE(sc, DWC_MMC_CLKENA_REG, 0); 375 if (dwc_mmc_update_clock(sc) != 0) 376 return ETIMEDOUT; 377 378 if (freq) { 379 if (dwc_mmc_set_clock(sc, freq) != 0) 380 return EIO; 381 382 clkena = DWC_MMC_CLKENA_CCLK_ENABLE; 383 clkena |= DWC_MMC_CLKENA_CCLK_LOW_POWER; /* XXX SD/MMC only */ 384 MMC_WRITE(sc, DWC_MMC_CLKENA_REG, clkena); 385 if (dwc_mmc_update_clock(sc) != 0) 386 return ETIMEDOUT; 387 } 388 389 delay(1000); 390 391 sc->sc_cur_freq = freq; 392 393 return 0; 394 } 395 396 static int 397 dwc_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) 398 { 399 struct dwc_mmc_softc *sc = sch; 400 uint32_t ctype; 401 402 switch (width) { 403 case 1: 404 ctype = DWC_MMC_CTYPE_CARD_WIDTH_1; 405 break; 406 case 4: 407 ctype = DWC_MMC_CTYPE_CARD_WIDTH_4; 408 break; 409 case 8: 410 ctype = DWC_MMC_CTYPE_CARD_WIDTH_8; 411 break; 412 default: 413 return EINVAL; 414 } 415 416 MMC_WRITE(sc, DWC_MMC_CTYPE_REG, ctype); 417 418 return 0; 419 } 420 421 static int 422 dwc_mmc_bus_rod(sdmmc_chipset_handle_t sch, int on) 423 { 424 return ENOTSUP; 425 } 426 427 static void 428 dwc_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 429 { 430 struct dwc_mmc_softc *sc = sch; 431 uint32_t cmdval = DWC_MMC_CMD_START_CMD; 432 uint32_t ctrl; 433 434 #ifdef DWC_MMC_DEBUG 435 device_printf(sc->sc_dev, "exec opcode=%d flags=%#x\n", 436 cmd->c_opcode, cmd->c_flags); 437 #endif 438 439 if (sc->sc_flags & DWC_MMC_F_FORCE_CLK) { 440 cmd->c_error = dwc_mmc_bus_clock(sc, sc->sc_cur_freq); 441 if (cmd->c_error) 442 return; 443 } 444 445 if (sc->sc_flags & DWC_MMC_F_USE_HOLD_REG) 446 cmdval |= DWC_MMC_CMD_USE_HOLD_REG; 447 448 mutex_enter(&sc->sc_intr_lock); 449 if (cmd->c_opcode == 0) 450 cmdval |= DWC_MMC_CMD_SEND_INIT; 451 if (cmd->c_flags & SCF_RSP_PRESENT) 452 cmdval |= DWC_MMC_CMD_RESP_EXPECTED; 453 if (cmd->c_flags & SCF_RSP_136) 454 cmdval |= DWC_MMC_CMD_RESP_LEN; 455 if (cmd->c_flags & SCF_RSP_CRC) 456 cmdval |= DWC_MMC_CMD_CHECK_RESP_CRC; 457 458 if (cmd->c_datalen > 0) { 459 unsigned int nblks; 460 461 cmdval |= DWC_MMC_CMD_DATA_EXPECTED; 462 cmdval |= DWC_MMC_CMD_WAIT_PRVDATA_COMPLETE; 463 if (!ISSET(cmd->c_flags, SCF_CMD_READ)) { 464 cmdval |= DWC_MMC_CMD_WR; 465 } 466 467 nblks = cmd->c_datalen / cmd->c_blklen; 468 if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0) 469 ++nblks; 470 471 if (nblks > 1) { 472 cmdval |= DWC_MMC_CMD_SEND_AUTO_STOP; 473 } 474 475 MMC_WRITE(sc, DWC_MMC_BLKSIZ_REG, cmd->c_blklen); 476 MMC_WRITE(sc, DWC_MMC_BYTCNT_REG, nblks * cmd->c_blklen); 477 } 478 479 sc->sc_intr_rint = 0; 480 481 MMC_WRITE(sc, DWC_MMC_CMDARG_REG, cmd->c_arg); 482 483 cmd->c_resid = cmd->c_datalen; 484 MMC_WRITE(sc, DWC_MMC_CMD_REG, cmdval | cmd->c_opcode); 485 if (cmd->c_datalen > 0) { 486 cmd->c_error = dwc_mmc_pio_transfer(sc, cmd); 487 if (cmd->c_error) { 488 goto done; 489 } 490 } 491 492 cmd->c_error = dwc_mmc_wait_rint(sc, 493 DWC_MMC_INT_ERROR|DWC_MMC_INT_CD, hz * 10); 494 if (cmd->c_error == 0 && (sc->sc_intr_rint & DWC_MMC_INT_ERROR)) { 495 #ifdef DWC_MMC_DEBUG 496 dwc_mmc_print_rint(sc, "exec1", sc->sc_intr_rint); 497 #endif 498 if (sc->sc_intr_rint & DWC_MMC_INT_RTO) { 499 cmd->c_error = ETIMEDOUT; 500 } else { 501 cmd->c_error = EIO; 502 } 503 } 504 if (cmd->c_error) { 505 goto done; 506 } 507 508 if (cmd->c_datalen > 0) { 509 cmd->c_error = dwc_mmc_wait_rint(sc, 510 DWC_MMC_INT_ERROR|DWC_MMC_INT_ACD|DWC_MMC_INT_DTO, 511 hz * 10); 512 if (cmd->c_error == 0 && 513 (sc->sc_intr_rint & DWC_MMC_INT_ERROR)) { 514 #ifdef DWC_MMC_DEBUG 515 dwc_mmc_print_rint(sc, "exec2", sc->sc_intr_rint); 516 #endif 517 cmd->c_error = ETIMEDOUT; 518 } 519 if (cmd->c_error) { 520 goto done; 521 } 522 } 523 524 if (cmd->c_flags & SCF_RSP_PRESENT) { 525 if (cmd->c_flags & SCF_RSP_136) { 526 cmd->c_resp[0] = MMC_READ(sc, DWC_MMC_RESP0_REG); 527 cmd->c_resp[1] = MMC_READ(sc, DWC_MMC_RESP1_REG); 528 cmd->c_resp[2] = MMC_READ(sc, DWC_MMC_RESP2_REG); 529 cmd->c_resp[3] = MMC_READ(sc, DWC_MMC_RESP3_REG); 530 if (cmd->c_flags & SCF_RSP_CRC) { 531 cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | 532 (cmd->c_resp[1] << 24); 533 cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | 534 (cmd->c_resp[2] << 24); 535 cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | 536 (cmd->c_resp[3] << 24); 537 cmd->c_resp[3] = (cmd->c_resp[3] >> 8); 538 } 539 } else { 540 cmd->c_resp[0] = MMC_READ(sc, DWC_MMC_RESP0_REG); 541 } 542 } 543 544 done: 545 cmd->c_flags |= SCF_ITSDONE; 546 mutex_exit(&sc->sc_intr_lock); 547 548 ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); 549 ctrl |= DWC_MMC_CTRL_FIFO_RESET; 550 MMC_WRITE(sc, DWC_MMC_CTRL_REG, ctrl); 551 } 552 553 static void 554 dwc_mmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) 555 { 556 } 557 558 static void 559 dwc_mmc_card_intr_ack(sdmmc_chipset_handle_t sch) 560 { 561 } 562 563 #ifdef DWC_MMC_DEBUG 564 static void 565 dwc_mmc_print_rint(struct dwc_mmc_softc *sc, const char *tag, uint32_t rint) 566 { 567 char buf[128]; 568 snprintb(buf, sizeof(buf), DWC_MMC_INT_BITS, rint); 569 device_printf(sc->sc_dev, "[%s] rint %s\n", tag, buf); 570 } 571 #endif 572 573 void 574 dwc_mmc_dump_regs(void) 575 { 576 static const struct { 577 const char *name; 578 unsigned int reg; 579 } regs[] = { 580 { "CTRL", DWC_MMC_CTRL_REG }, 581 { "PWREN", DWC_MMC_PWREN_REG }, 582 { "CLKDIV", DWC_MMC_CLKDIV_REG }, 583 { "CLKENA", DWC_MMC_CLKENA_REG }, 584 { "TMOUT", DWC_MMC_TMOUT_REG }, 585 { "CTYPE", DWC_MMC_CTYPE_REG }, 586 { "BLKSIZ", DWC_MMC_BLKSIZ_REG }, 587 { "BYTCNT", DWC_MMC_BYTCNT_REG }, 588 { "INTMASK", DWC_MMC_INTMASK_REG }, 589 { "MINTSTS", DWC_MMC_MINTSTS_REG }, 590 { "RINTSTS", DWC_MMC_RINTSTS_REG }, 591 { "STATUS", DWC_MMC_STATUS_REG }, 592 { "CDETECT", DWC_MMC_CDETECT_REG }, 593 { "WRTPRT", DWC_MMC_WRTPRT_REG }, 594 { "USRID", DWC_MMC_USRID_REG }, 595 { "VERID", DWC_MMC_VERID_REG }, 596 { "RST", DWC_MMC_RST_REG }, 597 { "BACK_END_POWER", DWC_MMC_BACK_END_POWER_REG }, 598 }; 599 device_t self = device_find_by_driver_unit("dwcmmc", 0); 600 if (self == NULL) 601 return; 602 struct dwc_mmc_softc *sc = device_private(self); 603 int i; 604 605 for (i = 0; i < __arraycount(regs); i++) { 606 device_printf(sc->sc_dev, "%s: %#x\n", regs[i].name, 607 MMC_READ(sc, regs[i].reg)); 608 } 609 } 610