dwc_mmc.c revision 1.5
1/* $NetBSD: dwc_mmc.c,v 1.5 2015/01/17 19:10:18 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.5 2015/01/17 19:10:18 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 48static int dwc_mmc_host_reset(sdmmc_chipset_handle_t); 49static uint32_t dwc_mmc_host_ocr(sdmmc_chipset_handle_t); 50static int dwc_mmc_host_maxblklen(sdmmc_chipset_handle_t); 51static int dwc_mmc_card_detect(sdmmc_chipset_handle_t); 52static int dwc_mmc_write_protect(sdmmc_chipset_handle_t); 53static int dwc_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t); 54static int dwc_mmc_bus_clock(sdmmc_chipset_handle_t, int); 55static int dwc_mmc_bus_width(sdmmc_chipset_handle_t, int); 56static int dwc_mmc_bus_rod(sdmmc_chipset_handle_t, int); 57static void dwc_mmc_exec_command(sdmmc_chipset_handle_t, 58 struct sdmmc_command *); 59static void dwc_mmc_card_enable_intr(sdmmc_chipset_handle_t, int); 60static void dwc_mmc_card_intr_ack(sdmmc_chipset_handle_t); 61 62static int dwc_mmc_set_clock(struct dwc_mmc_softc *, u_int); 63static int dwc_mmc_update_clock(struct dwc_mmc_softc *); 64static int dwc_mmc_wait_rint(struct dwc_mmc_softc *, uint32_t, int); 65static int dwc_mmc_pio_wait(struct dwc_mmc_softc *, 66 struct sdmmc_command *); 67static int dwc_mmc_pio_transfer(struct dwc_mmc_softc *, 68 struct sdmmc_command *); 69 70#ifdef DWC_MMC_DEBUG 71static void dwc_mmc_print_rint(struct dwc_mmc_softc *, const char *, 72 uint32_t); 73#endif 74 75void dwc_mmc_dump_regs(void); 76 77static 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 97void 98dwc_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 133int 134dwc_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 170static int 171dwc_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 185static int 186dwc_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 215static int 216dwc_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 239static int 240dwc_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 260static int 261dwc_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 279static int 280dwc_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, 294 MMC_READ(sc, DWC_MMC_CTRL_REG) | DWC_MMC_CTRL_RESET_ALL); 295 while (--retry > 0) { 296 ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); 297 if ((ctrl & DWC_MMC_CTRL_RESET_ALL) == 0) 298 break; 299 delay(100); 300 } 301 302 MMC_WRITE(sc, DWC_MMC_CLKSRC_REG, 0); 303 304 MMC_WRITE(sc, DWC_MMC_TMOUT_REG, 0xffffff40); 305 MMC_WRITE(sc, DWC_MMC_RINTSTS_REG, 0xffffffff); 306 307 MMC_WRITE(sc, DWC_MMC_INTMASK_REG, 308 DWC_MMC_INT_CD | DWC_MMC_INT_ACD | DWC_MMC_INT_DTO | 309 DWC_MMC_INT_ERROR | DWC_MMC_INT_CARDDET | 310 DWC_MMC_INT_RXDR | DWC_MMC_INT_TXDR); 311 312 rx_wmark = (sc->sc_fifo_depth / 2) - 1; 313 tx_wmark = sc->sc_fifo_depth / 2; 314 fifoth = __SHIFTIN(DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_16, 315 DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE); 316 fifoth |= __SHIFTIN(rx_wmark, DWC_MMC_FIFOTH_RX_WMARK); 317 fifoth |= __SHIFTIN(tx_wmark, DWC_MMC_FIFOTH_TX_WMARK); 318 MMC_WRITE(sc, DWC_MMC_FIFOTH_REG, fifoth); 319 320 ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); 321 ctrl |= DWC_MMC_CTRL_INT_ENABLE; 322 MMC_WRITE(sc, DWC_MMC_CTRL_REG, ctrl); 323 324 return 0; 325} 326 327static uint32_t 328dwc_mmc_host_ocr(sdmmc_chipset_handle_t sch) 329{ 330 return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 331} 332 333static int 334dwc_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) 335{ 336 return 32768; 337} 338 339static int 340dwc_mmc_card_detect(sdmmc_chipset_handle_t sch) 341{ 342 struct dwc_mmc_softc *sc = sch; 343 uint32_t cdetect; 344 345 cdetect = MMC_READ(sc, DWC_MMC_CDETECT_REG); 346 return !(cdetect & DWC_MMC_CDETECT_CARD_DETECT_N); 347} 348 349static int 350dwc_mmc_write_protect(sdmmc_chipset_handle_t sch) 351{ 352 struct dwc_mmc_softc *sc = sch; 353 uint32_t wrtprt; 354 355 wrtprt = MMC_READ(sc, DWC_MMC_WRTPRT_REG); 356 return !!(wrtprt & DWC_MMC_WRTPRT_WRITE_PROTECT); 357} 358 359static int 360dwc_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 361{ 362 return 0; 363} 364 365static int 366dwc_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) 367{ 368 struct dwc_mmc_softc *sc = sch; 369 uint32_t clkena; 370 371#ifdef DWC_MMC_DEBUG 372 device_printf(sc->sc_dev, "%s: freq %d\n", __func__, freq); 373#endif 374 375 MMC_WRITE(sc, DWC_MMC_CLKENA_REG, 0); 376 if (dwc_mmc_update_clock(sc) != 0) 377 return ETIMEDOUT; 378 379 if (freq) { 380 if (dwc_mmc_set_clock(sc, freq) != 0) 381 return EIO; 382 383 clkena = DWC_MMC_CLKENA_CCLK_ENABLE; 384 clkena |= DWC_MMC_CLKENA_CCLK_LOW_POWER; /* XXX SD/MMC only */ 385 MMC_WRITE(sc, DWC_MMC_CLKENA_REG, clkena); 386 if (dwc_mmc_update_clock(sc) != 0) 387 return ETIMEDOUT; 388 } 389 390 delay(1000); 391 392 sc->sc_cur_freq = freq; 393 394 return 0; 395} 396 397static int 398dwc_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) 399{ 400 struct dwc_mmc_softc *sc = sch; 401 uint32_t ctype; 402 403 switch (width) { 404 case 1: 405 ctype = DWC_MMC_CTYPE_CARD_WIDTH_1; 406 break; 407 case 4: 408 ctype = DWC_MMC_CTYPE_CARD_WIDTH_4; 409 break; 410 case 8: 411 ctype = DWC_MMC_CTYPE_CARD_WIDTH_8; 412 break; 413 default: 414 return EINVAL; 415 } 416 417 MMC_WRITE(sc, DWC_MMC_CTYPE_REG, ctype); 418 419 return 0; 420} 421 422static int 423dwc_mmc_bus_rod(sdmmc_chipset_handle_t sch, int on) 424{ 425 return ENOTSUP; 426} 427 428static void 429dwc_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 430{ 431 struct dwc_mmc_softc *sc = sch; 432 uint32_t cmdval = DWC_MMC_CMD_START_CMD; 433 uint32_t ctrl; 434 435#ifdef DWC_MMC_DEBUG 436 device_printf(sc->sc_dev, "exec opcode=%d flags=%#x\n", 437 cmd->c_opcode, cmd->c_flags); 438#endif 439 440 if (sc->sc_flags & DWC_MMC_F_FORCE_CLK) { 441 cmd->c_error = dwc_mmc_bus_clock(sc, sc->sc_cur_freq); 442 if (cmd->c_error) 443 return; 444 } 445 446 if (sc->sc_flags & DWC_MMC_F_USE_HOLD_REG) 447 cmdval |= DWC_MMC_CMD_USE_HOLD_REG; 448 449 mutex_enter(&sc->sc_intr_lock); 450 if (cmd->c_opcode == 0) 451 cmdval |= DWC_MMC_CMD_SEND_INIT; 452 if (cmd->c_flags & SCF_RSP_PRESENT) 453 cmdval |= DWC_MMC_CMD_RESP_EXPECTED; 454 if (cmd->c_flags & SCF_RSP_136) 455 cmdval |= DWC_MMC_CMD_RESP_LEN; 456 if (cmd->c_flags & SCF_RSP_CRC) 457 cmdval |= DWC_MMC_CMD_CHECK_RESP_CRC; 458 459 if (cmd->c_datalen > 0) { 460 unsigned int nblks; 461 462 cmdval |= DWC_MMC_CMD_DATA_EXPECTED; 463 cmdval |= DWC_MMC_CMD_WAIT_PRVDATA_COMPLETE; 464 if (!ISSET(cmd->c_flags, SCF_CMD_READ)) { 465 cmdval |= DWC_MMC_CMD_WR; 466 } 467 468 nblks = cmd->c_datalen / cmd->c_blklen; 469 if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0) 470 ++nblks; 471 472 if (nblks > 1) { 473 cmdval |= DWC_MMC_CMD_SEND_AUTO_STOP; 474 } 475 476 MMC_WRITE(sc, DWC_MMC_BLKSIZ_REG, cmd->c_blklen); 477 MMC_WRITE(sc, DWC_MMC_BYTCNT_REG, nblks * cmd->c_blklen); 478 } 479 480 sc->sc_intr_rint = 0; 481 482 MMC_WRITE(sc, DWC_MMC_CMDARG_REG, cmd->c_arg); 483 484 cmd->c_resid = cmd->c_datalen; 485 MMC_WRITE(sc, DWC_MMC_CMD_REG, cmdval | cmd->c_opcode); 486 if (cmd->c_datalen > 0) { 487 cmd->c_error = dwc_mmc_pio_transfer(sc, cmd); 488 if (cmd->c_error) { 489 goto done; 490 } 491 } 492 493 cmd->c_error = dwc_mmc_wait_rint(sc, 494 DWC_MMC_INT_ERROR|DWC_MMC_INT_CD, hz * 10); 495 if (cmd->c_error == 0 && (sc->sc_intr_rint & DWC_MMC_INT_ERROR)) { 496#ifdef DWC_MMC_DEBUG 497 dwc_mmc_print_rint(sc, "exec1", sc->sc_intr_rint); 498#endif 499 if (sc->sc_intr_rint & DWC_MMC_INT_RTO) { 500 cmd->c_error = ETIMEDOUT; 501 } else { 502 cmd->c_error = EIO; 503 } 504 } 505 if (cmd->c_error) { 506 goto done; 507 } 508 509 if (cmd->c_datalen > 0) { 510 cmd->c_error = dwc_mmc_wait_rint(sc, 511 DWC_MMC_INT_ERROR|DWC_MMC_INT_ACD|DWC_MMC_INT_DTO, 512 hz * 10); 513 if (cmd->c_error == 0 && 514 (sc->sc_intr_rint & DWC_MMC_INT_ERROR)) { 515#ifdef DWC_MMC_DEBUG 516 dwc_mmc_print_rint(sc, "exec2", sc->sc_intr_rint); 517#endif 518 cmd->c_error = ETIMEDOUT; 519 } 520 if (cmd->c_error) { 521 goto done; 522 } 523 } 524 525 if (cmd->c_flags & SCF_RSP_PRESENT) { 526 if (cmd->c_flags & SCF_RSP_136) { 527 cmd->c_resp[0] = MMC_READ(sc, DWC_MMC_RESP0_REG); 528 cmd->c_resp[1] = MMC_READ(sc, DWC_MMC_RESP1_REG); 529 cmd->c_resp[2] = MMC_READ(sc, DWC_MMC_RESP2_REG); 530 cmd->c_resp[3] = MMC_READ(sc, DWC_MMC_RESP3_REG); 531 if (cmd->c_flags & SCF_RSP_CRC) { 532 cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | 533 (cmd->c_resp[1] << 24); 534 cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | 535 (cmd->c_resp[2] << 24); 536 cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | 537 (cmd->c_resp[3] << 24); 538 cmd->c_resp[3] = (cmd->c_resp[3] >> 8); 539 } 540 } else { 541 cmd->c_resp[0] = MMC_READ(sc, DWC_MMC_RESP0_REG); 542 } 543 } 544 545done: 546 cmd->c_flags |= SCF_ITSDONE; 547 mutex_exit(&sc->sc_intr_lock); 548 549 ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); 550 ctrl |= DWC_MMC_CTRL_FIFO_RESET; 551 MMC_WRITE(sc, DWC_MMC_CTRL_REG, ctrl); 552} 553 554static void 555dwc_mmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) 556{ 557} 558 559static void 560dwc_mmc_card_intr_ack(sdmmc_chipset_handle_t sch) 561{ 562} 563 564#ifdef DWC_MMC_DEBUG 565static void 566dwc_mmc_print_rint(struct dwc_mmc_softc *sc, const char *tag, uint32_t rint) 567{ 568 char buf[128]; 569 snprintb(buf, sizeof(buf), DWC_MMC_INT_BITS, rint); 570 device_printf(sc->sc_dev, "[%s] rint %s\n", tag, buf); 571} 572#endif 573 574void 575dwc_mmc_dump_regs(void) 576{ 577 static const struct { 578 const char *name; 579 unsigned int reg; 580 } regs[] = { 581 { "CTRL", DWC_MMC_CTRL_REG }, 582 { "PWREN", DWC_MMC_PWREN_REG }, 583 { "CLKDIV", DWC_MMC_CLKDIV_REG }, 584 { "CLKENA", DWC_MMC_CLKENA_REG }, 585 { "TMOUT", DWC_MMC_TMOUT_REG }, 586 { "CTYPE", DWC_MMC_CTYPE_REG }, 587 { "BLKSIZ", DWC_MMC_BLKSIZ_REG }, 588 { "BYTCNT", DWC_MMC_BYTCNT_REG }, 589 { "INTMASK", DWC_MMC_INTMASK_REG }, 590 { "MINTSTS", DWC_MMC_MINTSTS_REG }, 591 { "RINTSTS", DWC_MMC_RINTSTS_REG }, 592 { "STATUS", DWC_MMC_STATUS_REG }, 593 { "CDETECT", DWC_MMC_CDETECT_REG }, 594 { "WRTPRT", DWC_MMC_WRTPRT_REG }, 595 { "USRID", DWC_MMC_USRID_REG }, 596 { "VERID", DWC_MMC_VERID_REG }, 597 { "RST", DWC_MMC_RST_REG }, 598 { "BACK_END_POWER", DWC_MMC_BACK_END_POWER_REG }, 599 }; 600 device_t self = device_find_by_driver_unit("dwcmmc", 0); 601 if (self == NULL) 602 return; 603 struct dwc_mmc_softc *sc = device_private(self); 604 int i; 605 606 for (i = 0; i < __arraycount(regs); i++) { 607 device_printf(sc->sc_dev, "%s: %#x\n", regs[i].name, 608 MMC_READ(sc, regs[i].reg)); 609 } 610} 611