1 1.9 thorpej /* $NetBSD: pl181.c,v 1.9 2021/08/07 16:19:12 thorpej Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jmcneill * SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill #include <sys/cdefs.h> 30 1.9 thorpej __KERNEL_RCSID(0, "$NetBSD: pl181.c,v 1.9 2021/08/07 16:19:12 thorpej Exp $"); 31 1.1 jmcneill 32 1.1 jmcneill #include <sys/param.h> 33 1.1 jmcneill #include <sys/bus.h> 34 1.1 jmcneill #include <sys/device.h> 35 1.1 jmcneill #include <sys/intr.h> 36 1.1 jmcneill #include <sys/systm.h> 37 1.1 jmcneill #include <sys/kernel.h> 38 1.1 jmcneill 39 1.1 jmcneill #include <dev/sdmmc/sdmmcvar.h> 40 1.1 jmcneill #include <dev/sdmmc/sdmmcchip.h> 41 1.1 jmcneill #include <dev/sdmmc/sdmmc_ioreg.h> 42 1.1 jmcneill 43 1.1 jmcneill #include <dev/ic/pl181reg.h> 44 1.1 jmcneill #include <dev/ic/pl181var.h> 45 1.1 jmcneill 46 1.4 jmcneill /* 47 1.4 jmcneill * Data length register is 16 bits for a maximum of 65535 bytes. Round 48 1.4 jmcneill * maximum transfer size down to the nearest sector. 49 1.4 jmcneill */ 50 1.4 jmcneill #define PLMMC_MAXXFER rounddown(65535, SDMMC_SECTOR_SIZE) 51 1.4 jmcneill 52 1.5 jmcneill /* 53 1.5 jmcneill * PL181 FIFO is 16 words deep (64 bytes) 54 1.5 jmcneill */ 55 1.5 jmcneill #define PL181_FIFO_DEPTH 64 56 1.5 jmcneill 57 1.5 jmcneill /* 58 1.5 jmcneill * Data transfer IRQ status bits 59 1.5 jmcneill */ 60 1.5 jmcneill #define PLMMC_INT_DATA_MASK \ 61 1.5 jmcneill (MMCI_INT_DATA_TIMEOUT|MMCI_INT_DATA_CRC_FAIL| \ 62 1.5 jmcneill MMCI_INT_TX_FIFO_EMPTY|MMCI_INT_TX_FIFO_HALF_EMPTY| \ 63 1.5 jmcneill MMCI_INT_RX_FIFO_FULL|MMCI_INT_RX_FIFO_HALF_FULL| \ 64 1.5 jmcneill MMCI_INT_DATA_END|MMCI_INT_DATA_BLOCK_END) 65 1.5 jmcneill #define PLMMC_INT_CMD_MASK \ 66 1.5 jmcneill (MMCI_INT_CMD_TIMEOUT|MMCI_INT_CMD_RESP_END) 67 1.5 jmcneill 68 1.1 jmcneill static int plmmc_host_reset(sdmmc_chipset_handle_t); 69 1.1 jmcneill static uint32_t plmmc_host_ocr(sdmmc_chipset_handle_t); 70 1.1 jmcneill static int plmmc_host_maxblklen(sdmmc_chipset_handle_t); 71 1.1 jmcneill static int plmmc_card_detect(sdmmc_chipset_handle_t); 72 1.1 jmcneill static int plmmc_write_protect(sdmmc_chipset_handle_t); 73 1.1 jmcneill static int plmmc_bus_power(sdmmc_chipset_handle_t, uint32_t); 74 1.1 jmcneill static int plmmc_bus_clock(sdmmc_chipset_handle_t, int); 75 1.1 jmcneill static int plmmc_bus_width(sdmmc_chipset_handle_t, int); 76 1.1 jmcneill static int plmmc_bus_rod(sdmmc_chipset_handle_t, int); 77 1.1 jmcneill static void plmmc_exec_command(sdmmc_chipset_handle_t, 78 1.1 jmcneill struct sdmmc_command *); 79 1.1 jmcneill static void plmmc_card_enable_intr(sdmmc_chipset_handle_t, int); 80 1.1 jmcneill static void plmmc_card_intr_ack(sdmmc_chipset_handle_t); 81 1.1 jmcneill 82 1.5 jmcneill static int plmmc_wait_cmd(struct plmmc_softc *); 83 1.1 jmcneill static int plmmc_pio_transfer(struct plmmc_softc *, 84 1.4 jmcneill struct sdmmc_command *, int); 85 1.1 jmcneill 86 1.1 jmcneill static struct sdmmc_chip_functions plmmc_chip_functions = { 87 1.1 jmcneill .host_reset = plmmc_host_reset, 88 1.1 jmcneill .host_ocr = plmmc_host_ocr, 89 1.1 jmcneill .host_maxblklen = plmmc_host_maxblklen, 90 1.1 jmcneill .card_detect = plmmc_card_detect, 91 1.1 jmcneill .write_protect = plmmc_write_protect, 92 1.1 jmcneill .bus_power = plmmc_bus_power, 93 1.1 jmcneill .bus_clock = plmmc_bus_clock, 94 1.1 jmcneill .bus_width = plmmc_bus_width, 95 1.1 jmcneill .bus_rod = plmmc_bus_rod, 96 1.1 jmcneill .exec_command = plmmc_exec_command, 97 1.1 jmcneill .card_enable_intr = plmmc_card_enable_intr, 98 1.1 jmcneill .card_intr_ack = plmmc_card_intr_ack, 99 1.1 jmcneill }; 100 1.1 jmcneill 101 1.1 jmcneill #define MMCI_WRITE(sc, reg, val) \ 102 1.1 jmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 103 1.5 jmcneill #define MMCI_WRITE_MULTI(sc, reg, datap, cnt) \ 104 1.5 jmcneill bus_space_write_multi_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (datap), (cnt)) 105 1.1 jmcneill #define MMCI_READ(sc, reg) \ 106 1.1 jmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 107 1.5 jmcneill #define MMCI_READ_MULTI(sc, reg, datap, cnt) \ 108 1.5 jmcneill bus_space_read_multi_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (datap), (cnt)) 109 1.1 jmcneill 110 1.1 jmcneill void 111 1.1 jmcneill plmmc_init(struct plmmc_softc *sc) 112 1.1 jmcneill { 113 1.1 jmcneill struct sdmmcbus_attach_args saa; 114 1.1 jmcneill 115 1.5 jmcneill mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO); 116 1.1 jmcneill cv_init(&sc->sc_intr_cv, "plmmcirq"); 117 1.1 jmcneill 118 1.1 jmcneill #ifdef PLMMC_DEBUG 119 1.1 jmcneill device_printf(sc->sc_dev, "PeriphID %#x %#x %#x %#x\n", 120 1.1 jmcneill MMCI_READ(sc, MMCI_PERIPH_ID0_REG), 121 1.1 jmcneill MMCI_READ(sc, MMCI_PERIPH_ID1_REG), 122 1.1 jmcneill MMCI_READ(sc, MMCI_PERIPH_ID2_REG), 123 1.1 jmcneill MMCI_READ(sc, MMCI_PERIPH_ID3_REG)); 124 1.1 jmcneill device_printf(sc->sc_dev, "PCellID %#x %#x %#x %#x\n", 125 1.1 jmcneill MMCI_READ(sc, MMCI_PCELL_ID0_REG), 126 1.1 jmcneill MMCI_READ(sc, MMCI_PCELL_ID1_REG), 127 1.1 jmcneill MMCI_READ(sc, MMCI_PCELL_ID2_REG), 128 1.1 jmcneill MMCI_READ(sc, MMCI_PCELL_ID3_REG)); 129 1.1 jmcneill #endif 130 1.1 jmcneill 131 1.1 jmcneill plmmc_bus_clock(sc, 400); 132 1.1 jmcneill MMCI_WRITE(sc, MMCI_POWER_REG, 0); 133 1.1 jmcneill delay(10000); 134 1.1 jmcneill MMCI_WRITE(sc, MMCI_POWER_REG, MMCI_POWER_CTRL_POWERUP); 135 1.1 jmcneill delay(10000); 136 1.1 jmcneill MMCI_WRITE(sc, MMCI_POWER_REG, MMCI_POWER_CTRL_POWERON); 137 1.1 jmcneill plmmc_host_reset(sc); 138 1.1 jmcneill 139 1.1 jmcneill memset(&saa, 0, sizeof(saa)); 140 1.1 jmcneill saa.saa_busname = "sdmmc"; 141 1.1 jmcneill saa.saa_sct = &plmmc_chip_functions; 142 1.1 jmcneill saa.saa_sch = sc; 143 1.1 jmcneill saa.saa_clkmin = 400; 144 1.3 jmcneill saa.saa_clkmax = sc->sc_max_freq > 0 ? 145 1.3 jmcneill sc->sc_max_freq / 1000 : sc->sc_clock_freq / 1000; 146 1.4 jmcneill saa.saa_caps = SMC_CAPS_4BIT_MODE; 147 1.1 jmcneill 148 1.9 thorpej sc->sc_sdmmc_dev = config_found(sc->sc_dev, &saa, NULL, CFARGS_NONE); 149 1.1 jmcneill } 150 1.1 jmcneill 151 1.5 jmcneill static int 152 1.5 jmcneill plmmc_intr_xfer(struct plmmc_softc *sc, struct sdmmc_command *cmd) 153 1.1 jmcneill { 154 1.5 jmcneill uint32_t len; 155 1.5 jmcneill 156 1.5 jmcneill if (cmd == NULL) { 157 1.5 jmcneill device_printf(sc->sc_dev, "TX/RX interrupt with no active transfer\n"); 158 1.5 jmcneill return EINVAL; 159 1.5 jmcneill } 160 1.5 jmcneill 161 1.5 jmcneill if (cmd->c_buf == NULL) { 162 1.5 jmcneill return EINVAL; 163 1.5 jmcneill } 164 1.1 jmcneill 165 1.5 jmcneill const uint32_t fifo_cnt = 166 1.5 jmcneill __SHIFTOUT(MMCI_READ(sc, MMCI_FIFO_CNT_REG), MMCI_FIFO_CNT) * 4; 167 1.5 jmcneill if (fifo_cnt > sc->sc_fifo_resid) { 168 1.5 jmcneill device_printf(sc->sc_dev, "FIFO counter is out of sync with active transfer\n"); 169 1.5 jmcneill return EIO; 170 1.1 jmcneill } 171 1.1 jmcneill 172 1.5 jmcneill if (cmd->c_flags & SCF_CMD_READ) 173 1.5 jmcneill len = sc->sc_fifo_resid - fifo_cnt; 174 1.5 jmcneill else 175 1.6 riastrad len = uimin(sc->sc_fifo_resid, PL181_FIFO_DEPTH); 176 1.5 jmcneill 177 1.5 jmcneill if (len == 0) 178 1.5 jmcneill return 0; 179 1.1 jmcneill 180 1.5 jmcneill if (cmd->c_flags & SCF_CMD_READ) 181 1.5 jmcneill MMCI_READ_MULTI(sc, MMCI_FIFO_REG, (uint32_t *)cmd->c_buf, len / 4); 182 1.5 jmcneill else 183 1.5 jmcneill MMCI_WRITE_MULTI(sc, MMCI_FIFO_REG, (uint32_t *)cmd->c_buf, len / 4); 184 1.5 jmcneill 185 1.5 jmcneill sc->sc_fifo_resid -= len; 186 1.5 jmcneill cmd->c_resid -= len; 187 1.5 jmcneill cmd->c_buf += len; 188 1.1 jmcneill 189 1.5 jmcneill return 0; 190 1.1 jmcneill } 191 1.1 jmcneill 192 1.5 jmcneill int 193 1.5 jmcneill plmmc_intr(void *priv) 194 1.1 jmcneill { 195 1.5 jmcneill struct plmmc_softc *sc = priv; 196 1.5 jmcneill uint32_t status, mask; 197 1.5 jmcneill int retry = 100000; 198 1.1 jmcneill 199 1.5 jmcneill mutex_enter(&sc->sc_lock); 200 1.1 jmcneill 201 1.5 jmcneill while (--retry > 0) { 202 1.5 jmcneill status = MMCI_READ(sc, MMCI_STATUS_REG); 203 1.5 jmcneill #ifdef PLMMC_DEBUG 204 1.5 jmcneill printf("%s: MMCI_STATUS_REG = %#x\n", __func__, status); 205 1.5 jmcneill #endif 206 1.5 jmcneill if ((status & sc->sc_status_mask) == 0) 207 1.5 jmcneill break; 208 1.5 jmcneill MMCI_WRITE(sc, MMCI_CLEAR_REG, status); 209 1.5 jmcneill sc->sc_intr_status |= status; 210 1.5 jmcneill 211 1.5 jmcneill if (status & MMCI_INT_CMD_TIMEOUT) 212 1.5 jmcneill break; 213 1.5 jmcneill 214 1.5 jmcneill if (status & (MMCI_INT_DATA_TIMEOUT|MMCI_INT_DATA_CRC_FAIL)) { 215 1.5 jmcneill device_printf(sc->sc_dev, 216 1.5 jmcneill "data xfer error, status %08x\n", status); 217 1.5 jmcneill break; 218 1.5 jmcneill } 219 1.1 jmcneill 220 1.5 jmcneill if (status & (MMCI_INT_TX_FIFO_EMPTY|MMCI_INT_TX_FIFO_HALF_EMPTY| 221 1.5 jmcneill MMCI_INT_RX_FIFO_FULL|MMCI_INT_RX_FIFO_HALF_FULL| 222 1.5 jmcneill MMCI_INT_DATA_END|MMCI_INT_DATA_BLOCK_END)) { 223 1.5 jmcneill 224 1.5 jmcneill /* Data transfer in progress */ 225 1.5 jmcneill if (plmmc_intr_xfer(sc, sc->sc_cmd) == 0 && 226 1.5 jmcneill sc->sc_fifo_resid == 0) { 227 1.5 jmcneill /* Disable data IRQs */ 228 1.5 jmcneill mask = MMCI_READ(sc, MMCI_MASK0_REG); 229 1.5 jmcneill mask &= ~PLMMC_INT_DATA_MASK; 230 1.5 jmcneill MMCI_WRITE(sc, MMCI_MASK0_REG, mask); 231 1.5 jmcneill /* Ignore data status bits after transfer */ 232 1.5 jmcneill sc->sc_status_mask &= ~PLMMC_INT_DATA_MASK; 233 1.1 jmcneill } 234 1.1 jmcneill } 235 1.5 jmcneill 236 1.5 jmcneill if (status & MMCI_INT_CMD_RESP_END) 237 1.5 jmcneill cv_broadcast(&sc->sc_intr_cv); 238 1.5 jmcneill } 239 1.5 jmcneill if (retry == 0) { 240 1.5 jmcneill device_printf(sc->sc_dev, "intr handler stuck, fifo resid %d, status %08x\n", 241 1.5 jmcneill sc->sc_fifo_resid, MMCI_READ(sc, MMCI_STATUS_REG)); 242 1.1 jmcneill } 243 1.1 jmcneill 244 1.5 jmcneill cv_broadcast(&sc->sc_intr_cv); 245 1.5 jmcneill mutex_exit(&sc->sc_lock); 246 1.1 jmcneill 247 1.5 jmcneill return 1; 248 1.1 jmcneill } 249 1.1 jmcneill 250 1.1 jmcneill static int 251 1.5 jmcneill plmmc_wait_cmd(struct plmmc_softc *sc) 252 1.1 jmcneill { 253 1.5 jmcneill int error = 0; 254 1.5 jmcneill 255 1.5 jmcneill KASSERT(mutex_owned(&sc->sc_lock)); 256 1.1 jmcneill 257 1.5 jmcneill while (error == 0) { 258 1.5 jmcneill if (sc->sc_intr_status & MMCI_INT_CMD_TIMEOUT) { 259 1.5 jmcneill error = ETIMEDOUT; 260 1.5 jmcneill break; 261 1.5 jmcneill } else if (sc->sc_intr_status & MMCI_INT_CMD_RESP_END) { 262 1.5 jmcneill break; 263 1.5 jmcneill } 264 1.5 jmcneill 265 1.5 jmcneill error = cv_timedwait(&sc->sc_intr_cv, &sc->sc_lock, hz * 2); 266 1.5 jmcneill if (error != 0) 267 1.5 jmcneill break; 268 1.5 jmcneill } 269 1.1 jmcneill 270 1.1 jmcneill return error; 271 1.1 jmcneill } 272 1.1 jmcneill 273 1.1 jmcneill static int 274 1.4 jmcneill plmmc_pio_transfer(struct plmmc_softc *sc, struct sdmmc_command *cmd, 275 1.4 jmcneill int xferlen) 276 1.1 jmcneill { 277 1.5 jmcneill int error = 0; 278 1.1 jmcneill 279 1.5 jmcneill while (sc->sc_fifo_resid > 0 && error == 0) { 280 1.5 jmcneill error = cv_timedwait(&sc->sc_intr_cv, 281 1.5 jmcneill &sc->sc_lock, hz * 5); 282 1.5 jmcneill if (error != 0) 283 1.5 jmcneill break; 284 1.5 jmcneill 285 1.5 jmcneill if (sc->sc_intr_status & MMCI_INT_DATA_TIMEOUT) 286 1.5 jmcneill error = ETIMEDOUT; 287 1.5 jmcneill else if (sc->sc_intr_status & MMCI_INT_DATA_CRC_FAIL) 288 1.5 jmcneill error = EIO; 289 1.1 jmcneill } 290 1.1 jmcneill 291 1.5 jmcneill return error; 292 1.1 jmcneill } 293 1.7 skrll 294 1.1 jmcneill static int 295 1.1 jmcneill plmmc_host_reset(sdmmc_chipset_handle_t sch) 296 1.1 jmcneill { 297 1.1 jmcneill struct plmmc_softc *sc = sch; 298 1.1 jmcneill 299 1.1 jmcneill MMCI_WRITE(sc, MMCI_MASK0_REG, 0); 300 1.1 jmcneill MMCI_WRITE(sc, MMCI_MASK1_REG, 0); 301 1.1 jmcneill MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff); 302 1.1 jmcneill 303 1.1 jmcneill return 0; 304 1.1 jmcneill } 305 1.1 jmcneill 306 1.1 jmcneill static uint32_t 307 1.1 jmcneill plmmc_host_ocr(sdmmc_chipset_handle_t sch) 308 1.1 jmcneill { 309 1.1 jmcneill return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 310 1.1 jmcneill } 311 1.1 jmcneill 312 1.1 jmcneill static int 313 1.1 jmcneill plmmc_host_maxblklen(sdmmc_chipset_handle_t sch) 314 1.1 jmcneill { 315 1.1 jmcneill return 2048; 316 1.1 jmcneill } 317 1.1 jmcneill 318 1.1 jmcneill static int 319 1.1 jmcneill plmmc_card_detect(sdmmc_chipset_handle_t sch) 320 1.1 jmcneill { 321 1.1 jmcneill return 1; 322 1.1 jmcneill } 323 1.1 jmcneill 324 1.1 jmcneill static int 325 1.1 jmcneill plmmc_write_protect(sdmmc_chipset_handle_t sch) 326 1.1 jmcneill { 327 1.1 jmcneill return 0; 328 1.1 jmcneill } 329 1.1 jmcneill 330 1.1 jmcneill static int 331 1.1 jmcneill plmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 332 1.1 jmcneill { 333 1.1 jmcneill return 0; 334 1.1 jmcneill } 335 1.1 jmcneill 336 1.1 jmcneill static int 337 1.1 jmcneill plmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) 338 1.1 jmcneill { 339 1.1 jmcneill struct plmmc_softc *sc = sch; 340 1.1 jmcneill u_int pll_freq, clk_div; 341 1.1 jmcneill uint32_t clock; 342 1.1 jmcneill 343 1.1 jmcneill clock = MMCI_CLOCK_PWRSAVE; 344 1.1 jmcneill if (freq) { 345 1.1 jmcneill pll_freq = sc->sc_clock_freq / 1000; 346 1.1 jmcneill clk_div = (howmany(pll_freq, freq) >> 1) - 1; 347 1.1 jmcneill clock |= __SHIFTIN(clk_div, MMCI_CLOCK_CLKDIV); 348 1.1 jmcneill clock |= MMCI_CLOCK_ENABLE; 349 1.1 jmcneill } 350 1.1 jmcneill MMCI_WRITE(sc, MMCI_CLOCK_REG, clock); 351 1.1 jmcneill 352 1.1 jmcneill return 0; 353 1.1 jmcneill } 354 1.1 jmcneill 355 1.1 jmcneill static int 356 1.1 jmcneill plmmc_bus_width(sdmmc_chipset_handle_t sch, int width) 357 1.1 jmcneill { 358 1.1 jmcneill return 0; 359 1.1 jmcneill } 360 1.1 jmcneill 361 1.1 jmcneill static int 362 1.1 jmcneill plmmc_bus_rod(sdmmc_chipset_handle_t sch, int on) 363 1.1 jmcneill { 364 1.1 jmcneill struct plmmc_softc *sc = sch; 365 1.1 jmcneill uint32_t power; 366 1.1 jmcneill 367 1.1 jmcneill 368 1.1 jmcneill power = MMCI_READ(sc, MMCI_POWER_REG); 369 1.1 jmcneill if (on) { 370 1.1 jmcneill power |= MMCI_POWER_ROD; 371 1.1 jmcneill } else { 372 1.1 jmcneill power &= ~MMCI_POWER_ROD; 373 1.1 jmcneill } 374 1.1 jmcneill MMCI_WRITE(sc, MMCI_POWER_REG, power); 375 1.1 jmcneill 376 1.1 jmcneill return 0; 377 1.1 jmcneill } 378 1.1 jmcneill 379 1.1 jmcneill static void 380 1.4 jmcneill plmmc_do_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 381 1.1 jmcneill { 382 1.1 jmcneill struct plmmc_softc *sc = sch; 383 1.1 jmcneill uint32_t cmdval = MMCI_COMMAND_ENABLE; 384 1.1 jmcneill 385 1.5 jmcneill KASSERT(mutex_owned(&sc->sc_lock)); 386 1.4 jmcneill 387 1.6 riastrad const int xferlen = uimin(cmd->c_resid, PLMMC_MAXXFER); 388 1.4 jmcneill 389 1.5 jmcneill sc->sc_cmd = cmd; 390 1.5 jmcneill sc->sc_fifo_resid = xferlen; 391 1.5 jmcneill sc->sc_status_mask = ~0U; 392 1.5 jmcneill sc->sc_intr_status = 0; 393 1.5 jmcneill 394 1.1 jmcneill #ifdef PLMMC_DEBUG 395 1.4 jmcneill device_printf(sc->sc_dev, 396 1.4 jmcneill "opcode %d flags %#x datalen %d resid %d xferlen %d\n", 397 1.4 jmcneill cmd->c_opcode, cmd->c_flags, cmd->c_datalen, cmd->c_resid, xferlen); 398 1.1 jmcneill #endif 399 1.1 jmcneill 400 1.1 jmcneill MMCI_WRITE(sc, MMCI_COMMAND_REG, 0); 401 1.1 jmcneill MMCI_WRITE(sc, MMCI_MASK0_REG, 0); 402 1.1 jmcneill MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff); 403 1.5 jmcneill MMCI_WRITE(sc, MMCI_MASK0_REG, PLMMC_INT_DATA_MASK | PLMMC_INT_CMD_MASK); 404 1.1 jmcneill 405 1.1 jmcneill if (cmd->c_flags & SCF_RSP_PRESENT) 406 1.1 jmcneill cmdval |= MMCI_COMMAND_RESPONSE; 407 1.1 jmcneill if (cmd->c_flags & SCF_RSP_136) 408 1.1 jmcneill cmdval |= MMCI_COMMAND_LONGRSP; 409 1.1 jmcneill 410 1.4 jmcneill uint32_t arg = cmd->c_arg; 411 1.4 jmcneill 412 1.4 jmcneill if (xferlen > 0) { 413 1.4 jmcneill unsigned int nblks = xferlen / cmd->c_blklen; 414 1.4 jmcneill if (nblks == 0 || (xferlen % cmd->c_blklen) != 0) 415 1.1 jmcneill ++nblks; 416 1.1 jmcneill 417 1.1 jmcneill const uint32_t dir = (cmd->c_flags & SCF_CMD_READ) ? 1 : 0; 418 1.1 jmcneill const uint32_t blksize = ffs(cmd->c_blklen) - 1; 419 1.1 jmcneill 420 1.1 jmcneill MMCI_WRITE(sc, MMCI_DATA_TIMER_REG, 0xffffffff); 421 1.1 jmcneill MMCI_WRITE(sc, MMCI_DATA_LENGTH_REG, nblks * cmd->c_blklen); 422 1.1 jmcneill MMCI_WRITE(sc, MMCI_DATA_CTRL_REG, 423 1.1 jmcneill __SHIFTIN(dir, MMCI_DATA_CTRL_DIRECTION) | 424 1.1 jmcneill __SHIFTIN(blksize, MMCI_DATA_CTRL_BLOCKSIZE) | 425 1.1 jmcneill MMCI_DATA_CTRL_ENABLE); 426 1.4 jmcneill 427 1.4 jmcneill /* Adjust blkno if necessary */ 428 1.4 jmcneill u_int blkoff = 429 1.4 jmcneill (cmd->c_datalen - cmd->c_resid) / SDMMC_SECTOR_SIZE; 430 1.4 jmcneill if (!ISSET(cmd->c_flags, SCF_XFER_SDHC)) 431 1.4 jmcneill blkoff <<= SDMMC_SECTOR_SIZE_SB; 432 1.4 jmcneill arg += blkoff; 433 1.1 jmcneill } 434 1.1 jmcneill 435 1.4 jmcneill MMCI_WRITE(sc, MMCI_ARGUMENT_REG, arg); 436 1.1 jmcneill MMCI_WRITE(sc, MMCI_COMMAND_REG, cmdval | cmd->c_opcode); 437 1.1 jmcneill 438 1.4 jmcneill if (xferlen > 0) { 439 1.4 jmcneill cmd->c_error = plmmc_pio_transfer(sc, cmd, xferlen); 440 1.1 jmcneill if (cmd->c_error) { 441 1.5 jmcneill #ifdef PLMMC_DEBUG 442 1.5 jmcneill device_printf(sc->sc_dev, 443 1.5 jmcneill "MMCI_STATUS_REG = %08x\n", MMCI_READ(sc, MMCI_STATUS_REG)); 444 1.5 jmcneill #endif 445 1.1 jmcneill device_printf(sc->sc_dev, 446 1.1 jmcneill "error (%d) waiting for xfer\n", cmd->c_error); 447 1.1 jmcneill goto done; 448 1.1 jmcneill } 449 1.1 jmcneill } 450 1.1 jmcneill 451 1.4 jmcneill if ((cmd->c_flags & SCF_RSP_PRESENT) && cmd->c_resid == 0) { 452 1.5 jmcneill cmd->c_error = plmmc_wait_cmd(sc); 453 1.1 jmcneill if (cmd->c_error) { 454 1.1 jmcneill #ifdef PLMMC_DEBUG 455 1.1 jmcneill device_printf(sc->sc_dev, 456 1.1 jmcneill "error (%d) waiting for resp\n", cmd->c_error); 457 1.1 jmcneill #endif 458 1.1 jmcneill goto done; 459 1.1 jmcneill } 460 1.1 jmcneill 461 1.1 jmcneill if (cmd->c_flags & SCF_RSP_136) { 462 1.1 jmcneill cmd->c_resp[3] = MMCI_READ(sc, MMCI_RESP0_REG); 463 1.1 jmcneill cmd->c_resp[2] = MMCI_READ(sc, MMCI_RESP1_REG); 464 1.1 jmcneill cmd->c_resp[1] = MMCI_READ(sc, MMCI_RESP2_REG); 465 1.1 jmcneill cmd->c_resp[0] = MMCI_READ(sc, MMCI_RESP3_REG); 466 1.1 jmcneill if (cmd->c_flags & SCF_RSP_CRC) { 467 1.1 jmcneill cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | 468 1.1 jmcneill (cmd->c_resp[1] << 24); 469 1.1 jmcneill cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | 470 1.1 jmcneill (cmd->c_resp[2] << 24); 471 1.1 jmcneill cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | 472 1.1 jmcneill (cmd->c_resp[3] << 24); 473 1.1 jmcneill cmd->c_resp[3] = (cmd->c_resp[3] >> 8); 474 1.1 jmcneill } 475 1.1 jmcneill } else { 476 1.1 jmcneill cmd->c_resp[0] = MMCI_READ(sc, MMCI_RESP0_REG); 477 1.1 jmcneill } 478 1.1 jmcneill } 479 1.1 jmcneill 480 1.1 jmcneill done: 481 1.5 jmcneill sc->sc_cmd = NULL; 482 1.5 jmcneill 483 1.1 jmcneill MMCI_WRITE(sc, MMCI_COMMAND_REG, 0); 484 1.1 jmcneill MMCI_WRITE(sc, MMCI_MASK0_REG, 0); 485 1.1 jmcneill MMCI_WRITE(sc, MMCI_CLEAR_REG, 0xffffffff); 486 1.1 jmcneill MMCI_WRITE(sc, MMCI_DATA_CNT_REG, 0); 487 1.1 jmcneill 488 1.1 jmcneill #ifdef PLMMC_DEBUG 489 1.5 jmcneill device_printf(sc->sc_dev, "status = %#x\n", sc->sc_intr_status); 490 1.1 jmcneill #endif 491 1.4 jmcneill } 492 1.4 jmcneill 493 1.4 jmcneill static void 494 1.4 jmcneill plmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 495 1.4 jmcneill { 496 1.4 jmcneill struct plmmc_softc *sc = sch; 497 1.4 jmcneill 498 1.4 jmcneill #ifdef PLMMC_DEBUG 499 1.4 jmcneill device_printf(sc->sc_dev, "opcode %d flags %#x data %p datalen %d\n", 500 1.4 jmcneill cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen); 501 1.4 jmcneill #endif 502 1.4 jmcneill 503 1.5 jmcneill mutex_enter(&sc->sc_lock); 504 1.4 jmcneill cmd->c_resid = cmd->c_datalen; 505 1.4 jmcneill cmd->c_buf = cmd->c_data; 506 1.4 jmcneill do { 507 1.4 jmcneill plmmc_do_command(sch, cmd); 508 1.4 jmcneill 509 1.4 jmcneill if (cmd->c_resid > 0 && cmd->c_error == 0) { 510 1.4 jmcneill /* 511 1.4 jmcneill * Multi block transfer and there is still data 512 1.4 jmcneill * remaining. Send a stop cmd between transfers. 513 1.4 jmcneill */ 514 1.4 jmcneill struct sdmmc_command stop_cmd; 515 1.4 jmcneill memset(&stop_cmd, 0, sizeof(stop_cmd)); 516 1.4 jmcneill stop_cmd.c_opcode = MMC_STOP_TRANSMISSION; 517 1.4 jmcneill stop_cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1B | 518 1.4 jmcneill SCF_RSP_SPI_R1B; 519 1.4 jmcneill plmmc_do_command(sch, &stop_cmd); 520 1.4 jmcneill } 521 1.4 jmcneill } while (cmd->c_resid > 0 && cmd->c_error == 0); 522 1.4 jmcneill cmd->c_flags |= SCF_ITSDONE; 523 1.5 jmcneill mutex_exit(&sc->sc_lock); 524 1.1 jmcneill } 525 1.1 jmcneill 526 1.1 jmcneill static void 527 1.1 jmcneill plmmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) 528 1.1 jmcneill { 529 1.1 jmcneill } 530 1.1 jmcneill 531 1.1 jmcneill static void 532 1.1 jmcneill plmmc_card_intr_ack(sdmmc_chipset_handle_t sch) 533 1.1 jmcneill { 534 1.1 jmcneill } 535