1 /* $NetBSD: pl181.c,v 1.1 2015/01/27 16:33:26 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 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 <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: pl181.c,v 1.1 2015/01/27 16:33:26 jmcneill Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/device.h> 35 #include <sys/intr.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 39 #include <dev/sdmmc/sdmmcvar.h> 40 #include <dev/sdmmc/sdmmcchip.h> 41 #include <dev/sdmmc/sdmmc_ioreg.h> 42 43 #include <dev/ic/pl181reg.h> 44 #include <dev/ic/pl181var.h> 45 46 static int plmmc_host_reset(sdmmc_chipset_handle_t); 47 static uint32_t plmmc_host_ocr(sdmmc_chipset_handle_t); 48 static int plmmc_host_maxblklen(sdmmc_chipset_handle_t); 49 static int plmmc_card_detect(sdmmc_chipset_handle_t); 50 static int plmmc_write_protect(sdmmc_chipset_handle_t); 51 static int plmmc_bus_power(sdmmc_chipset_handle_t, uint32_t); 52 static int plmmc_bus_clock(sdmmc_chipset_handle_t, int); 53 static int plmmc_bus_width(sdmmc_chipset_handle_t, int); 54 static int plmmc_bus_rod(sdmmc_chipset_handle_t, int); 55 static void plmmc_exec_command(sdmmc_chipset_handle_t, 56 struct sdmmc_command *); 57 static void plmmc_card_enable_intr(sdmmc_chipset_handle_t, int); 58 static void plmmc_card_intr_ack(sdmmc_chipset_handle_t); 59 60 static int plmmc_wait_status(struct plmmc_softc *, uint32_t, int); 61 static int plmmc_pio_wait(struct plmmc_softc *, 62 struct sdmmc_command *); 63 static int plmmc_pio_transfer(struct plmmc_softc *, 64 struct sdmmc_command *); 65 66 static struct sdmmc_chip_functions plmmc_chip_functions = { 67 .host_reset = plmmc_host_reset, 68 .host_ocr = plmmc_host_ocr, 69 .host_maxblklen = plmmc_host_maxblklen, 70 .card_detect = plmmc_card_detect, 71 .write_protect = plmmc_write_protect, 72 .bus_power = plmmc_bus_power, 73 .bus_clock = plmmc_bus_clock, 74 .bus_width = plmmc_bus_width, 75 .bus_rod = plmmc_bus_rod, 76 .exec_command = plmmc_exec_command, 77 .card_enable_intr = plmmc_card_enable_intr, 78 .card_intr_ack = plmmc_card_intr_ack, 79 }; 80 81 #define MMCI_WRITE(sc, reg, val) \ 82 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 83 #define MMCI_READ(sc, reg) \ 84 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 85 86 void 87 plmmc_init(struct plmmc_softc *sc) 88 { 89 struct sdmmcbus_attach_args saa; 90 91 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO); 92 cv_init(&sc->sc_intr_cv, "plmmcirq"); 93 94 #ifdef PLMMC_DEBUG 95 device_printf(sc->sc_dev, "PeriphID %#x %#x %#x %#x\n", 96 MMCI_READ(sc, MMCI_PERIPH_ID0_REG), 97 MMCI_READ(sc, MMCI_PERIPH_ID1_REG), 98 MMCI_READ(sc, MMCI_PERIPH_ID2_REG), 99 MMCI_READ(sc, MMCI_PERIPH_ID3_REG)); 100 device_printf(sc->sc_dev, "PCellID %#x %#x %#x %#x\n", 101 MMCI_READ(sc, MMCI_PCELL_ID0_REG), 102 MMCI_READ(sc, MMCI_PCELL_ID1_REG), 103 MMCI_READ(sc, MMCI_PCELL_ID2_REG), 104 MMCI_READ(sc, MMCI_PCELL_ID3_REG)); 105 #endif 106 107 plmmc_bus_clock(sc, 400); 108 MMCI_WRITE(sc, MMCI_POWER_REG, 0); 109 delay(10000); 110 MMCI_WRITE(sc, MMCI_POWER_REG, MMCI_POWER_CTRL_POWERUP); 111 delay(10000); 112 MMCI_WRITE(sc, MMCI_POWER_REG, MMCI_POWER_CTRL_POWERON); 113 plmmc_host_reset(sc); 114 115 memset(&saa, 0, sizeof(saa)); 116 saa.saa_busname = "sdmmc"; 117 saa.saa_sct = &plmmc_chip_functions; 118 saa.saa_sch = sc; 119 saa.saa_clkmin = 400; 120 saa.saa_clkmax = sc->sc_clock_freq / 1000; 121 saa.saa_caps = 0; 122 123 sc->sc_sdmmc_dev = config_found(sc->sc_dev, &saa, NULL); 124 } 125 126 int 127 plmmc_intr(void *priv) 128 { 129 struct plmmc_softc *sc = priv; 130 uint32_t status; 131 132 mutex_enter(&sc->sc_intr_lock); 133 status = MMCI_READ(sc, MMCI_STATUS_REG); 134 #ifdef PLMMC_DEBUG 135 printf("%s: MMCI_STATUS_REG = %#x\n", __func__, status); 136 #endif 137 if (!status) { 138 mutex_exit(&sc->sc_intr_lock); 139 return 0; 140 } 141 142 sc->sc_intr_status |= status; 143 cv_broadcast(&sc->sc_intr_cv); 144 145 mutex_exit(&sc->sc_intr_lock); 146 147 return 1; 148 } 149 150 static int 151 plmmc_wait_status(struct plmmc_softc *sc, uint32_t mask, int timeout) 152 { 153 int retry, error; 154 155 KASSERT(mutex_owned(&sc->sc_intr_lock)); 156 157 if (sc->sc_intr_status & mask) 158 return 0; 159 160 retry = timeout / hz; 161 if (sc->sc_ih == NULL) 162 retry *= 1000; 163 164 while (retry > 0) { 165 if (sc->sc_ih == NULL) { 166 sc->sc_intr_status |= MMCI_READ(sc, MMCI_STATUS_REG); 167 if (sc->sc_intr_status & mask) 168 return 0; 169 delay(10000); 170 } else { 171 error = cv_timedwait(&sc->sc_intr_cv, 172 &sc->sc_intr_lock, hz); 173 if (error && error != EWOULDBLOCK) { 174 device_printf(sc->sc_dev, 175 "cv_timedwait returned %d\n", error); 176 return error; 177 } 178 if (sc->sc_intr_status & mask) 179 return 0; 180 } 181 --retry; 182 } 183 184 device_printf(sc->sc_dev, "%s timeout, MMCI_STATUS_REG = %#x\n", 185 __func__, MMCI_READ(sc, MMCI_STATUS_REG)); 186 187 return ETIMEDOUT; 188 } 189 190 static int 191 plmmc_pio_wait(struct plmmc_softc *sc, struct sdmmc_command *cmd) 192 { 193 uint32_t bit = (cmd->c_flags & SCF_CMD_READ) ? 194 MMCI_INT_RX_DATA_AVAIL : MMCI_INT_TX_FIFO_EMPTY; 195 196 MMCI_WRITE(sc, MMCI_CLEAR_REG, bit); 197 const int error = plmmc_wait_status(sc, 198 bit | MMCI_INT_DATA_END | MMCI_INT_DATA_BLOCK_END, hz*2); 199 sc->sc_intr_status &= ~bit; 200 201 return error; 202 } 203 204 static int 205 plmmc_pio_transfer(struct plmmc_softc *sc, struct sdmmc_command *cmd) 206 { 207 uint32_t *datap = (uint32_t *)cmd->c_data; 208 int i; 209 210 cmd->c_resid = cmd->c_datalen; 211 for (i = 0; i < (cmd->c_datalen >> 2); i++) { 212 if (plmmc_pio_wait(sc, cmd)) 213 return ETIMEDOUT; 214 if (cmd->c_flags & SCF_CMD_READ) { 215 datap[i] = MMCI_READ(sc, MMCI_FIFO_REG); 216 } else { 217 MMCI_WRITE(sc, MMCI_FIFO_REG, datap[i]); 218 } 219 cmd->c_resid -= 4; 220 } 221 222 return 0; 223 } 224 225 static int 226 plmmc_host_reset(sdmmc_chipset_handle_t sch) 227 { 228 struct plmmc_softc *sc = sch; 229 230 MMCI_WRITE(sc, MMCI_MASK0_REG, 0); 231 MMCI_WRITE(sc, MMCI_MASK1_REG, 0); 232 MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff); 233 234 return 0; 235 } 236 237 static uint32_t 238 plmmc_host_ocr(sdmmc_chipset_handle_t sch) 239 { 240 return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 241 } 242 243 static int 244 plmmc_host_maxblklen(sdmmc_chipset_handle_t sch) 245 { 246 return 2048; 247 } 248 249 static int 250 plmmc_card_detect(sdmmc_chipset_handle_t sch) 251 { 252 return 1; 253 } 254 255 static int 256 plmmc_write_protect(sdmmc_chipset_handle_t sch) 257 { 258 return 0; 259 } 260 261 static int 262 plmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 263 { 264 return 0; 265 } 266 267 static int 268 plmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) 269 { 270 struct plmmc_softc *sc = sch; 271 u_int pll_freq, clk_div; 272 uint32_t clock; 273 274 clock = MMCI_CLOCK_PWRSAVE; 275 if (freq) { 276 pll_freq = sc->sc_clock_freq / 1000; 277 clk_div = (howmany(pll_freq, freq) >> 1) - 1; 278 clock |= __SHIFTIN(clk_div, MMCI_CLOCK_CLKDIV); 279 clock |= MMCI_CLOCK_ENABLE; 280 } 281 MMCI_WRITE(sc, MMCI_CLOCK_REG, clock); 282 283 return 0; 284 } 285 286 static int 287 plmmc_bus_width(sdmmc_chipset_handle_t sch, int width) 288 { 289 return 0; 290 } 291 292 static int 293 plmmc_bus_rod(sdmmc_chipset_handle_t sch, int on) 294 { 295 struct plmmc_softc *sc = sch; 296 uint32_t power; 297 298 299 power = MMCI_READ(sc, MMCI_POWER_REG); 300 if (on) { 301 power |= MMCI_POWER_ROD; 302 } else { 303 power &= ~MMCI_POWER_ROD; 304 } 305 MMCI_WRITE(sc, MMCI_POWER_REG, power); 306 307 return 0; 308 } 309 310 static void 311 plmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 312 { 313 struct plmmc_softc *sc = sch; 314 uint32_t cmdval = MMCI_COMMAND_ENABLE; 315 316 #ifdef PLMMC_DEBUG 317 device_printf(sc->sc_dev, "opcode %d flags %#x datalen %d\n", 318 cmd->c_opcode, cmd->c_flags, cmd->c_datalen); 319 #endif 320 321 mutex_enter(&sc->sc_intr_lock); 322 323 MMCI_WRITE(sc, MMCI_COMMAND_REG, 0); 324 MMCI_WRITE(sc, MMCI_MASK0_REG, 0); 325 MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff); 326 MMCI_WRITE(sc, MMCI_MASK0_REG, 327 MMCI_INT_CMD_TIMEOUT | MMCI_INT_DATA_TIMEOUT | 328 MMCI_INT_RX_DATA_AVAIL | MMCI_INT_TX_FIFO_EMPTY | 329 MMCI_INT_DATA_END | MMCI_INT_DATA_BLOCK_END | 330 MMCI_INT_CMD_RESP_END | MMCI_INT_CMD_SENT); 331 332 sc->sc_intr_status = 0; 333 334 if (cmd->c_flags & SCF_RSP_PRESENT) 335 cmdval |= MMCI_COMMAND_RESPONSE; 336 if (cmd->c_flags & SCF_RSP_136) 337 cmdval |= MMCI_COMMAND_LONGRSP; 338 339 if (cmd->c_datalen > 0) { 340 unsigned int nblks = cmd->c_datalen / cmd->c_blklen; 341 if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0) 342 ++nblks; 343 344 const uint32_t dir = (cmd->c_flags & SCF_CMD_READ) ? 1 : 0; 345 const uint32_t blksize = ffs(cmd->c_blklen) - 1; 346 347 MMCI_WRITE(sc, MMCI_DATA_TIMER_REG, 0xffffffff); 348 MMCI_WRITE(sc, MMCI_DATA_LENGTH_REG, nblks * cmd->c_blklen); 349 MMCI_WRITE(sc, MMCI_DATA_CTRL_REG, 350 __SHIFTIN(dir, MMCI_DATA_CTRL_DIRECTION) | 351 __SHIFTIN(blksize, MMCI_DATA_CTRL_BLOCKSIZE) | 352 MMCI_DATA_CTRL_ENABLE); 353 } 354 355 MMCI_WRITE(sc, MMCI_ARGUMENT_REG, cmd->c_arg); 356 MMCI_WRITE(sc, MMCI_COMMAND_REG, cmdval | cmd->c_opcode); 357 358 if (cmd->c_datalen > 0) { 359 cmd->c_error = plmmc_pio_transfer(sc, cmd); 360 if (cmd->c_error) { 361 device_printf(sc->sc_dev, 362 "error (%d) waiting for xfer\n", cmd->c_error); 363 goto done; 364 } 365 } 366 367 if (cmd->c_flags & SCF_RSP_PRESENT) { 368 cmd->c_error = plmmc_wait_status(sc, 369 MMCI_INT_CMD_RESP_END|MMCI_INT_CMD_TIMEOUT, hz * 2); 370 if (cmd->c_error == 0 && 371 (sc->sc_intr_status & MMCI_INT_CMD_TIMEOUT)) { 372 cmd->c_error = ETIMEDOUT; 373 } 374 if (cmd->c_error) { 375 #ifdef PLMMC_DEBUG 376 device_printf(sc->sc_dev, 377 "error (%d) waiting for resp\n", cmd->c_error); 378 #endif 379 goto done; 380 } 381 382 if (cmd->c_flags & SCF_RSP_136) { 383 cmd->c_resp[3] = MMCI_READ(sc, MMCI_RESP0_REG); 384 cmd->c_resp[2] = MMCI_READ(sc, MMCI_RESP1_REG); 385 cmd->c_resp[1] = MMCI_READ(sc, MMCI_RESP2_REG); 386 cmd->c_resp[0] = MMCI_READ(sc, MMCI_RESP3_REG); 387 if (cmd->c_flags & SCF_RSP_CRC) { 388 cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | 389 (cmd->c_resp[1] << 24); 390 cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | 391 (cmd->c_resp[2] << 24); 392 cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | 393 (cmd->c_resp[3] << 24); 394 cmd->c_resp[3] = (cmd->c_resp[3] >> 8); 395 } 396 } else { 397 cmd->c_resp[0] = MMCI_READ(sc, MMCI_RESP0_REG); 398 } 399 } 400 401 done: 402 cmd->c_flags |= SCF_ITSDONE; 403 MMCI_WRITE(sc, MMCI_COMMAND_REG, 0); 404 MMCI_WRITE(sc, MMCI_MASK0_REG, 0); 405 MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff); 406 MMCI_WRITE(sc, MMCI_DATA_CNT_REG, 0); 407 408 #ifdef PLMMC_DEBUG 409 device_printf(sc->sc_dev, "MMCI_STATUS_REG = %#x\n", 410 MMCI_READ(sc, MMCI_STATUS_REG)); 411 #endif 412 mutex_exit(&sc->sc_intr_lock); 413 } 414 415 static void 416 plmmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) 417 { 418 } 419 420 static void 421 plmmc_card_intr_ack(sdmmc_chipset_handle_t sch) 422 { 423 } 424