1 1.8 thorpej /* $NetBSD: mvsdio.c,v 1.8 2021/08/07 16:19:13 thorpej Exp $ */ 2 1.1 kiyohara /* 3 1.1 kiyohara * Copyright (c) 2010 KIYOHARA Takashi 4 1.1 kiyohara * All rights reserved. 5 1.1 kiyohara * 6 1.1 kiyohara * Redistribution and use in source and binary forms, with or without 7 1.1 kiyohara * modification, are permitted provided that the following conditions 8 1.1 kiyohara * are met: 9 1.1 kiyohara * 1. Redistributions of source code must retain the above copyright 10 1.1 kiyohara * notice, this list of conditions and the following disclaimer. 11 1.1 kiyohara * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 kiyohara * notice, this list of conditions and the following disclaimer in the 13 1.1 kiyohara * documentation and/or other materials provided with the distribution. 14 1.1 kiyohara * 15 1.1 kiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 kiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 kiyohara * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 kiyohara * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 1.1 kiyohara * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 1.1 kiyohara * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 kiyohara * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 kiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 1.1 kiyohara * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 1.1 kiyohara * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 kiyohara * POSSIBILITY OF SUCH DAMAGE. 26 1.1 kiyohara */ 27 1.1 kiyohara #include <sys/cdefs.h> 28 1.8 thorpej __KERNEL_RCSID(0, "$NetBSD: mvsdio.c,v 1.8 2021/08/07 16:19:13 thorpej Exp $"); 29 1.1 kiyohara 30 1.1 kiyohara #include "opt_mvsdio.h" 31 1.1 kiyohara 32 1.1 kiyohara #include <sys/param.h> 33 1.1 kiyohara #include <sys/bus.h> 34 1.1 kiyohara #include <sys/condvar.h> 35 1.1 kiyohara #include <sys/device.h> 36 1.1 kiyohara #include <sys/errno.h> 37 1.1 kiyohara #include <sys/mutex.h> 38 1.1 kiyohara 39 1.1 kiyohara #include <dev/marvell/marvellreg.h> 40 1.1 kiyohara #include <dev/marvell/marvellvar.h> 41 1.1 kiyohara #include <dev/marvell/mvsdioreg.h> 42 1.1 kiyohara 43 1.1 kiyohara #include <dev/sdmmc/sdmmcvar.h> 44 1.1 kiyohara #include <dev/sdmmc/sdmmcchip.h> 45 1.1 kiyohara 46 1.1 kiyohara //#define MVSDIO_DEBUG 1 47 1.1 kiyohara #ifdef MVSDIO_DEBUG 48 1.1 kiyohara #define DPRINTF(n, x) if (mvsdio_debug >= (n)) printf x 49 1.1 kiyohara int mvsdio_debug = MVSDIO_DEBUG; 50 1.1 kiyohara #else 51 1.1 kiyohara #define DPRINTF(n, x) 52 1.1 kiyohara #endif 53 1.1 kiyohara 54 1.1 kiyohara struct mvsdio_softc { 55 1.1 kiyohara device_t sc_dev; 56 1.1 kiyohara device_t sc_sdmmc; 57 1.1 kiyohara 58 1.1 kiyohara bus_space_tag_t sc_iot; 59 1.1 kiyohara bus_space_handle_t sc_ioh; 60 1.1 kiyohara bus_dma_tag_t sc_dmat; 61 1.1 kiyohara 62 1.1 kiyohara struct kmutex sc_mtx; 63 1.1 kiyohara kcondvar_t sc_cv; 64 1.1 kiyohara 65 1.1 kiyohara struct sdmmc_command *sc_exec_cmd; 66 1.1 kiyohara uint32_t sc_waitintr; 67 1.1 kiyohara }; 68 1.1 kiyohara 69 1.1 kiyohara static int mvsdio_match(device_t, struct cfdata *, void *); 70 1.1 kiyohara static void mvsdio_attach(device_t, device_t, void *); 71 1.1 kiyohara 72 1.1 kiyohara static int mvsdio_intr(void *); 73 1.1 kiyohara 74 1.1 kiyohara static int mvsdio_host_reset(sdmmc_chipset_handle_t); 75 1.1 kiyohara static uint32_t mvsdio_host_ocr(sdmmc_chipset_handle_t); 76 1.1 kiyohara static int mvsdio_host_maxblklen(sdmmc_chipset_handle_t); 77 1.1 kiyohara #ifdef MVSDIO_CARD_DETECT 78 1.1 kiyohara int MVSDIO_CARD_DETECT(sdmmc_chipset_handle_t); 79 1.1 kiyohara #else 80 1.1 kiyohara static int mvsdio_card_detect(sdmmc_chipset_handle_t); 81 1.1 kiyohara #endif 82 1.1 kiyohara #ifdef MVSDIO_WRITE_PROTECT 83 1.1 kiyohara int MVSDIO_WRITE_PROTECT(sdmmc_chipset_handle_t); 84 1.1 kiyohara #else 85 1.1 kiyohara static int mvsdio_write_protect(sdmmc_chipset_handle_t); 86 1.1 kiyohara #endif 87 1.1 kiyohara static int mvsdio_bus_power(sdmmc_chipset_handle_t, uint32_t); 88 1.1 kiyohara static int mvsdio_bus_clock(sdmmc_chipset_handle_t, int); 89 1.1 kiyohara static int mvsdio_bus_width(sdmmc_chipset_handle_t, int); 90 1.1 kiyohara static int mvsdio_bus_rod(sdmmc_chipset_handle_t, int); 91 1.1 kiyohara static void mvsdio_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); 92 1.1 kiyohara static void mvsdio_card_enable_intr(sdmmc_chipset_handle_t, int); 93 1.1 kiyohara static void mvsdio_card_intr_ack(sdmmc_chipset_handle_t); 94 1.1 kiyohara 95 1.5 kiyohara static void mvsdio_wininit(struct mvsdio_softc *, enum marvell_tags *); 96 1.1 kiyohara 97 1.1 kiyohara static struct sdmmc_chip_functions mvsdio_chip_functions = { 98 1.1 kiyohara /* host controller reset */ 99 1.1 kiyohara .host_reset = mvsdio_host_reset, 100 1.1 kiyohara 101 1.1 kiyohara /* host controller capabilities */ 102 1.1 kiyohara .host_ocr = mvsdio_host_ocr, 103 1.1 kiyohara .host_maxblklen = mvsdio_host_maxblklen, 104 1.1 kiyohara 105 1.1 kiyohara /* card detection */ 106 1.1 kiyohara #ifdef MVSDIO_CARD_DETECT 107 1.1 kiyohara .card_detect = MVSDIO_CARD_DETECT, 108 1.1 kiyohara #else 109 1.1 kiyohara .card_detect = mvsdio_card_detect, 110 1.1 kiyohara #endif 111 1.1 kiyohara 112 1.1 kiyohara /* write protect */ 113 1.1 kiyohara #ifdef MVSDIO_WRITE_PROTECT 114 1.1 kiyohara .write_protect = MVSDIO_WRITE_PROTECT, 115 1.1 kiyohara #else 116 1.1 kiyohara .write_protect = mvsdio_write_protect, 117 1.1 kiyohara #endif 118 1.1 kiyohara 119 1.1 kiyohara /* bus power, clock frequency, width, rod */ 120 1.1 kiyohara .bus_power = mvsdio_bus_power, 121 1.1 kiyohara .bus_clock = mvsdio_bus_clock, 122 1.1 kiyohara .bus_width = mvsdio_bus_width, 123 1.1 kiyohara .bus_rod = mvsdio_bus_rod, 124 1.1 kiyohara 125 1.1 kiyohara /* command execution */ 126 1.1 kiyohara .exec_command = mvsdio_exec_command, 127 1.1 kiyohara 128 1.1 kiyohara /* card interrupt */ 129 1.1 kiyohara .card_enable_intr = mvsdio_card_enable_intr, 130 1.1 kiyohara .card_intr_ack = mvsdio_card_intr_ack, 131 1.1 kiyohara }; 132 1.1 kiyohara 133 1.1 kiyohara CFATTACH_DECL_NEW(mvsdio_mbus, sizeof(struct mvsdio_softc), 134 1.1 kiyohara mvsdio_match, mvsdio_attach, NULL, NULL); 135 1.1 kiyohara 136 1.1 kiyohara 137 1.1 kiyohara /* ARGSUSED */ 138 1.1 kiyohara static int 139 1.1 kiyohara mvsdio_match(device_t parent, struct cfdata *match, void *aux) 140 1.1 kiyohara { 141 1.1 kiyohara struct marvell_attach_args *mva = aux; 142 1.1 kiyohara 143 1.1 kiyohara if (strcmp(mva->mva_name, match->cf_name) != 0) 144 1.1 kiyohara return 0; 145 1.1 kiyohara if (mva->mva_offset == MVA_OFFSET_DEFAULT) 146 1.1 kiyohara return 0; 147 1.1 kiyohara 148 1.1 kiyohara mva->mva_size = MVSDIO_SIZE; 149 1.1 kiyohara return 1; 150 1.1 kiyohara } 151 1.1 kiyohara 152 1.1 kiyohara /* ARGSUSED */ 153 1.1 kiyohara static void 154 1.1 kiyohara mvsdio_attach(device_t parent, device_t self, void *aux) 155 1.1 kiyohara { 156 1.1 kiyohara struct mvsdio_softc *sc = device_private(self); 157 1.1 kiyohara struct marvell_attach_args *mva = aux; 158 1.1 kiyohara struct sdmmcbus_attach_args saa; 159 1.1 kiyohara uint32_t nis, eis; 160 1.6 jakllsch uint32_t hps; 161 1.1 kiyohara 162 1.1 kiyohara aprint_naive("\n"); 163 1.1 kiyohara aprint_normal(": Marvell Secure Digital Input/Output Interface\n"); 164 1.1 kiyohara 165 1.1 kiyohara sc->sc_dev = self; 166 1.1 kiyohara sc->sc_iot = mva->mva_iot; 167 1.1 kiyohara if (bus_space_subregion(mva->mva_iot, mva->mva_ioh, mva->mva_offset, 168 1.1 kiyohara mva->mva_size, &sc->sc_ioh)) { 169 1.1 kiyohara aprint_error_dev(self, "Cannot map registers\n"); 170 1.1 kiyohara return; 171 1.1 kiyohara } 172 1.1 kiyohara sc->sc_dmat = mva->mva_dmat; 173 1.1 kiyohara 174 1.1 kiyohara mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_SDMMC); 175 1.1 kiyohara cv_init(&sc->sc_cv, "mvsdio_intr"); 176 1.1 kiyohara 177 1.1 kiyohara sc->sc_exec_cmd = NULL; 178 1.1 kiyohara sc->sc_waitintr = 0; 179 1.1 kiyohara 180 1.1 kiyohara marvell_intr_establish(mva->mva_irq, IPL_SDMMC, mvsdio_intr, sc); 181 1.1 kiyohara 182 1.5 kiyohara mvsdio_wininit(sc, mva->mva_tags); 183 1.1 kiyohara 184 1.1 kiyohara #if BYTE_ORDER == LITTLE_ENDIAN 185 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, HC_BIGENDIAN); 186 1.1 kiyohara #else 187 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, HC_LSBFIRST); 188 1.1 kiyohara #endif 189 1.1 kiyohara nis = 190 1.1 kiyohara NIS_CMDCOMPLETE /* Command Complete */ | 191 1.1 kiyohara NIS_XFERCOMPLETE /* Transfer Complete */ | 192 1.1 kiyohara NIS_BLOCKGAPEV /* Block gap event */ | 193 1.1 kiyohara NIS_DMAINT /* DMA interrupt */ | 194 1.1 kiyohara NIS_CARDINT /* Card interrupt */ | 195 1.1 kiyohara NIS_READWAITON /* Read Wait state is on */ | 196 1.1 kiyohara NIS_SUSPENSEON | 197 1.1 kiyohara NIS_AUTOCMD12COMPLETE /* Auto_cmd12 is comp */| 198 1.1 kiyohara NIS_UNEXPECTEDRESPDET | 199 1.1 kiyohara NIS_ERRINT; /* Error interrupt */ 200 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NIS, nis); 201 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISE, nis); 202 1.1 kiyohara 203 1.1 kiyohara #define NIC_DYNAMIC_CONFIG_INTRS (NIS_CMDCOMPLETE | \ 204 1.1 kiyohara NIS_XFERCOMPLETE | \ 205 1.1 kiyohara NIS_DMAINT | \ 206 1.1 kiyohara NIS_CARDINT | \ 207 1.1 kiyohara NIS_AUTOCMD12COMPLETE) 208 1.1 kiyohara 209 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE, 210 1.1 kiyohara nis & ~NIC_DYNAMIC_CONFIG_INTRS); 211 1.1 kiyohara 212 1.1 kiyohara eis = 213 1.1 kiyohara EIS_CMDTIMEOUTERR /*Command timeout err*/ | 214 1.1 kiyohara EIS_CMDCRCERR /* Command CRC Error */ | 215 1.1 kiyohara EIS_CMDENDBITERR /*Command end bit err*/ | 216 1.1 kiyohara EIS_CMDINDEXERR /*Command Index Error*/ | 217 1.1 kiyohara EIS_DATATIMEOUTERR /* Data timeout error */ | 218 1.1 kiyohara EIS_RDDATACRCERR /* Read data CRC err */ | 219 1.1 kiyohara EIS_RDDATAENDBITERR /*Rd data end bit err*/ | 220 1.1 kiyohara EIS_AUTOCMD12ERR /* Auto CMD12 error */ | 221 1.1 kiyohara EIS_CMDSTARTBITERR /*Cmd start bit error*/ | 222 1.1 kiyohara EIS_XFERSIZEERR /*Tx size mismatched err*/ | 223 1.1 kiyohara EIS_RESPTBITERR /* Response T bit err */ | 224 1.1 kiyohara EIS_CRCENDBITERR /* CRC end bit error */ | 225 1.1 kiyohara EIS_CRCSTARTBITERR /* CRC start bit err */ | 226 1.1 kiyohara EIS_CRCSTATERR; /* CRC status error */ 227 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EIS, eis); 228 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EISE, eis); 229 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EISIE, eis); 230 1.1 kiyohara 231 1.6 jakllsch hps = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HPS16LSB); 232 1.6 jakllsch if ((hps & HPS16LSB_CMDLEVEL) == 0) { 233 1.6 jakllsch aprint_error_dev(sc->sc_dev, 234 1.6 jakllsch "CMD line not idle, HPS 0x%x (bad MPP config?)\n", hps); 235 1.6 jakllsch return; 236 1.6 jakllsch } 237 1.6 jakllsch 238 1.1 kiyohara /* 239 1.1 kiyohara * Attach the generic SD/MMC bus driver. (The bus driver must 240 1.1 kiyohara * not invoke any chipset functions before it is attached.) 241 1.1 kiyohara */ 242 1.1 kiyohara memset(&saa, 0, sizeof(saa)); 243 1.1 kiyohara saa.saa_busname = "sdmmc"; 244 1.1 kiyohara saa.saa_sct = &mvsdio_chip_functions; 245 1.1 kiyohara saa.saa_sch = sc; 246 1.1 kiyohara saa.saa_dmat = sc->sc_dmat; 247 1.2 kiyohara saa.saa_clkmin = 100; /* XXXX: 100 kHz from SheevaPlug LSP */ 248 1.1 kiyohara saa.saa_clkmax = MVSDIO_MAX_CLOCK; 249 1.3 nonaka saa.saa_caps = SMC_CAPS_AUTO_STOP | SMC_CAPS_4BIT_MODE | SMC_CAPS_DMA | 250 1.4 nonaka SMC_CAPS_SD_HIGHSPEED | SMC_CAPS_MMC_HIGHSPEED; 251 1.1 kiyohara #ifndef MVSDIO_CARD_DETECT 252 1.1 kiyohara saa.saa_caps |= SMC_CAPS_POLL_CARD_DET; 253 1.1 kiyohara #endif 254 1.8 thorpej sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL, CFARGS_NONE); 255 1.1 kiyohara } 256 1.1 kiyohara 257 1.1 kiyohara static int 258 1.1 kiyohara mvsdio_intr(void *arg) 259 1.1 kiyohara { 260 1.1 kiyohara struct mvsdio_softc *sc = (struct mvsdio_softc *)arg; 261 1.1 kiyohara struct sdmmc_command *cmd = sc->sc_exec_cmd; 262 1.1 kiyohara uint32_t nis, eis; 263 1.1 kiyohara int handled = 0, error; 264 1.1 kiyohara 265 1.1 kiyohara nis = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NIS); 266 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NIS, nis); 267 1.1 kiyohara 268 1.1 kiyohara DPRINTF(3, ("%s: intr: NIS=0x%x, NISE=0x%x, NISIE=0x%x\n", 269 1.1 kiyohara __func__, nis, 270 1.1 kiyohara bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISE), 271 1.1 kiyohara bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE))); 272 1.1 kiyohara 273 1.1 kiyohara if (__predict_false(nis & NIS_ERRINT)) { 274 1.1 kiyohara sc->sc_exec_cmd = NULL; 275 1.1 kiyohara eis = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EIS); 276 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EIS, eis); 277 1.1 kiyohara 278 1.1 kiyohara DPRINTF(3, (" EIS=0x%x, EISE=0x%x, EISIE=0x%x\n", 279 1.1 kiyohara eis, 280 1.1 kiyohara bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EISE), 281 1.1 kiyohara bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EISIE))); 282 1.1 kiyohara 283 1.1 kiyohara if (eis & (EIS_CMDTIMEOUTERR | EIS_DATATIMEOUTERR)) { 284 1.1 kiyohara error = ETIMEDOUT; /* Timeouts */ 285 1.1 kiyohara DPRINTF(2, (" Command/Data Timeout (0x%x)\n", 286 1.1 kiyohara eis & (EIS_CMDTIMEOUTERR | EIS_DATATIMEOUTERR))); 287 1.1 kiyohara } else { 288 1.1 kiyohara 289 1.1 kiyohara #define CRC_ERROR (EIS_CMDCRCERR | \ 290 1.1 kiyohara EIS_RDDATACRCERR | \ 291 1.1 kiyohara EIS_CRCENDBITERR | \ 292 1.1 kiyohara EIS_CRCSTARTBITERR | \ 293 1.1 kiyohara EIS_CRCSTATERR) 294 1.1 kiyohara if (eis & CRC_ERROR) { 295 1.1 kiyohara error = EIO; /* CRC errors */ 296 1.1 kiyohara aprint_error_dev(sc->sc_dev, 297 1.1 kiyohara "CRC Error (0x%x)\n", eis & CRC_ERROR); 298 1.1 kiyohara } 299 1.1 kiyohara 300 1.1 kiyohara #define COMMAND_ERROR (EIS_CMDENDBITERR | \ 301 1.1 kiyohara EIS_CMDINDEXERR | \ 302 1.1 kiyohara EIS_CMDSTARTBITERR) 303 1.1 kiyohara if (eis & COMMAND_ERROR) { 304 1.1 kiyohara error = EIO; /*Other command errors*/ 305 1.1 kiyohara aprint_error_dev(sc->sc_dev, 306 1.1 kiyohara "Command Error (0x%x)\n", 307 1.1 kiyohara eis & COMMAND_ERROR); 308 1.1 kiyohara } 309 1.1 kiyohara 310 1.1 kiyohara #define MISC_ERROR (EIS_RDDATAENDBITERR | \ 311 1.1 kiyohara EIS_AUTOCMD12ERR | \ 312 1.1 kiyohara EIS_XFERSIZEERR | \ 313 1.1 kiyohara EIS_RESPTBITERR) 314 1.1 kiyohara if (eis & MISC_ERROR) { 315 1.1 kiyohara error = EIO; /* Misc error */ 316 1.1 kiyohara aprint_error_dev(sc->sc_dev, 317 1.1 kiyohara "Misc Error (0x%x)\n", eis & MISC_ERROR); 318 1.1 kiyohara } 319 1.1 kiyohara } 320 1.1 kiyohara 321 1.1 kiyohara if (cmd != NULL) { 322 1.1 kiyohara cmd->c_error = error; 323 1.1 kiyohara cv_signal(&sc->sc_cv); 324 1.1 kiyohara } 325 1.1 kiyohara handled = 1; 326 1.1 kiyohara } else if (cmd != NULL && 327 1.1 kiyohara ((nis & sc->sc_waitintr) || (nis & NIS_UNEXPECTEDRESPDET))) { 328 1.1 kiyohara sc->sc_exec_cmd = NULL; 329 1.1 kiyohara sc->sc_waitintr = 0; 330 1.1 kiyohara if (cmd->c_flags & SCF_RSP_PRESENT) { 331 1.1 kiyohara uint16_t rh[MVSDIO_NRH + 1]; 332 1.1 kiyohara int i, j; 333 1.1 kiyohara 334 1.1 kiyohara if (cmd->c_flags & SCF_RSP_136) { 335 1.1 kiyohara for (i = 0; i < MVSDIO_NRH; i++) 336 1.1 kiyohara rh[i + 1] = bus_space_read_4(sc->sc_iot, 337 1.1 kiyohara sc->sc_ioh, MVSDIO_RH(i)); 338 1.1 kiyohara rh[0] = 0; 339 1.1 kiyohara for (j = 3, i = 1; j >= 0; j--, i += 2) { 340 1.1 kiyohara cmd->c_resp[j] = 341 1.1 kiyohara rh[i - 1] << 30 | 342 1.1 kiyohara rh[i + 0] << 14 | 343 1.1 kiyohara rh[i + 1] >> 2; 344 1.1 kiyohara } 345 1.1 kiyohara cmd->c_resp[3] &= 0x00ffffff; 346 1.1 kiyohara } else { 347 1.1 kiyohara for (i = 0; i < 3; i++) 348 1.1 kiyohara rh[i] = bus_space_read_4(sc->sc_iot, 349 1.1 kiyohara sc->sc_ioh, MVSDIO_RH(i)); 350 1.1 kiyohara cmd->c_resp[0] = 351 1.1 kiyohara ((rh[0] & 0x03ff) << 22) | 352 1.1 kiyohara ((rh[1] ) << 6) | 353 1.1 kiyohara ((rh[2] & 0x003f) << 0); 354 1.1 kiyohara cmd->c_resp[1] = (rh[0] & 0xfc00) >> 10; 355 1.1 kiyohara cmd->c_resp[2] = 0; 356 1.1 kiyohara cmd->c_resp[3] = 0; 357 1.1 kiyohara } 358 1.1 kiyohara } 359 1.1 kiyohara if (nis & NIS_UNEXPECTEDRESPDET) 360 1.1 kiyohara cmd->c_error = EIO; 361 1.1 kiyohara cv_signal(&sc->sc_cv); 362 1.1 kiyohara } 363 1.1 kiyohara 364 1.1 kiyohara if (nis & NIS_CARDINT) 365 1.1 kiyohara if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE) & 366 1.1 kiyohara NIS_CARDINT) { 367 1.1 kiyohara sdmmc_card_intr(sc->sc_sdmmc); 368 1.1 kiyohara handled = 1; 369 1.1 kiyohara } 370 1.1 kiyohara 371 1.1 kiyohara return handled; 372 1.1 kiyohara } 373 1.1 kiyohara 374 1.1 kiyohara static int 375 1.1 kiyohara mvsdio_host_reset(sdmmc_chipset_handle_t sch) 376 1.1 kiyohara { 377 1.1 kiyohara struct mvsdio_softc *sc = (struct mvsdio_softc *)sch; 378 1.1 kiyohara 379 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_SR, SR_SWRESET); 380 1.1 kiyohara return 0; 381 1.1 kiyohara } 382 1.1 kiyohara 383 1.1 kiyohara static uint32_t 384 1.1 kiyohara mvsdio_host_ocr(sdmmc_chipset_handle_t sch) 385 1.1 kiyohara { 386 1.1 kiyohara 387 1.1 kiyohara return MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V; 388 1.1 kiyohara } 389 1.1 kiyohara 390 1.1 kiyohara static int 391 1.1 kiyohara mvsdio_host_maxblklen(sdmmc_chipset_handle_t sch) 392 1.1 kiyohara { 393 1.1 kiyohara 394 1.1 kiyohara return DBS_BLOCKSIZE_MAX; 395 1.1 kiyohara } 396 1.1 kiyohara 397 1.1 kiyohara #ifndef MVSDIO_CARD_DETECT 398 1.1 kiyohara static int 399 1.1 kiyohara mvsdio_card_detect(sdmmc_chipset_handle_t sch) 400 1.1 kiyohara { 401 1.1 kiyohara struct mvsdio_softc *sc __unused = (struct mvsdio_softc *)sch; 402 1.1 kiyohara 403 1.1 kiyohara DPRINTF(2, ("%s: driver lacks card_detect() function.\n", 404 1.1 kiyohara device_xname(sc->sc_dev))); 405 1.1 kiyohara return 1; /* always detect */ 406 1.1 kiyohara } 407 1.1 kiyohara #endif 408 1.1 kiyohara 409 1.1 kiyohara #ifndef MVSDIO_WRITE_PROTECT 410 1.1 kiyohara static int 411 1.1 kiyohara mvsdio_write_protect(sdmmc_chipset_handle_t sch) 412 1.1 kiyohara { 413 1.1 kiyohara 414 1.1 kiyohara /* Nothing */ 415 1.1 kiyohara 416 1.1 kiyohara return 0; 417 1.1 kiyohara } 418 1.1 kiyohara #endif 419 1.1 kiyohara 420 1.1 kiyohara static int 421 1.1 kiyohara mvsdio_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 422 1.1 kiyohara { 423 1.1 kiyohara struct mvsdio_softc *sc = (struct mvsdio_softc *)sch; 424 1.1 kiyohara uint32_t reg; 425 1.1 kiyohara 426 1.1 kiyohara /* Initial state is Open Drain on CMD line. */ 427 1.1 kiyohara mutex_enter(&sc->sc_mtx); 428 1.1 kiyohara reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC); 429 1.1 kiyohara reg &= ~HC_PUSHPULLEN; 430 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, reg); 431 1.1 kiyohara mutex_exit(&sc->sc_mtx); 432 1.1 kiyohara 433 1.1 kiyohara return 0; 434 1.1 kiyohara } 435 1.1 kiyohara 436 1.1 kiyohara static int 437 1.1 kiyohara mvsdio_bus_clock(sdmmc_chipset_handle_t sch, int freq) 438 1.1 kiyohara { 439 1.1 kiyohara struct mvsdio_softc *sc = (struct mvsdio_softc *)sch; 440 1.1 kiyohara uint32_t reg; 441 1.1 kiyohara int m; 442 1.1 kiyohara 443 1.1 kiyohara mutex_enter(&sc->sc_mtx); 444 1.1 kiyohara reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM); 445 1.1 kiyohara 446 1.1 kiyohara /* Just stop the clock. */ 447 1.1 kiyohara if (freq == 0) { 448 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM, 449 1.1 kiyohara reg | TM_STOPCLKEN); 450 1.1 kiyohara goto out; 451 1.1 kiyohara } 452 1.1 kiyohara 453 1.1 kiyohara #define FREQ_TO_M(f) (100000 / (f) - 1) 454 1.1 kiyohara 455 1.1 kiyohara m = FREQ_TO_M(freq); 456 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_CDV, 457 1.1 kiyohara m & CDV_CLKDVDRMVALUE_MASK); 458 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM, 459 1.1 kiyohara reg & ~TM_STOPCLKEN); 460 1.1 kiyohara 461 1.1 kiyohara reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC); 462 1.1 kiyohara if (freq > 25000) 463 1.1 kiyohara reg |= HC_HISPEEDEN; 464 1.1 kiyohara else 465 1.1 kiyohara reg &= ~HC_HISPEEDEN; /* up to 25 MHz */ 466 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, reg); 467 1.1 kiyohara 468 1.1 kiyohara out: 469 1.1 kiyohara mutex_exit(&sc->sc_mtx); 470 1.1 kiyohara 471 1.1 kiyohara return 0; 472 1.1 kiyohara } 473 1.1 kiyohara 474 1.1 kiyohara static int 475 1.1 kiyohara mvsdio_bus_width(sdmmc_chipset_handle_t sch, int width) 476 1.1 kiyohara { 477 1.1 kiyohara struct mvsdio_softc *sc = (struct mvsdio_softc *)sch; 478 1.1 kiyohara uint32_t reg, v; 479 1.1 kiyohara 480 1.1 kiyohara switch (width) { 481 1.1 kiyohara case 1: 482 1.1 kiyohara v = 0; 483 1.1 kiyohara break; 484 1.1 kiyohara 485 1.1 kiyohara case 4: 486 1.1 kiyohara v = HC_DATAWIDTH; 487 1.1 kiyohara break; 488 1.1 kiyohara 489 1.1 kiyohara default: 490 1.1 kiyohara DPRINTF(0, ("%s: unsupported bus width (%d)\n", 491 1.1 kiyohara device_xname(sc->sc_dev), width)); 492 1.1 kiyohara return EINVAL; 493 1.1 kiyohara } 494 1.1 kiyohara 495 1.1 kiyohara mutex_enter(&sc->sc_mtx); 496 1.1 kiyohara reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC); 497 1.1 kiyohara reg &= ~HC_DATAWIDTH; 498 1.1 kiyohara reg |= v; 499 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, reg); 500 1.1 kiyohara mutex_exit(&sc->sc_mtx); 501 1.1 kiyohara 502 1.1 kiyohara return 0; 503 1.1 kiyohara } 504 1.1 kiyohara 505 1.1 kiyohara static int 506 1.1 kiyohara mvsdio_bus_rod(sdmmc_chipset_handle_t sch, int on) 507 1.1 kiyohara { 508 1.1 kiyohara struct mvsdio_softc *sc = (struct mvsdio_softc *)sch; 509 1.1 kiyohara uint32_t reg; 510 1.1 kiyohara 511 1.1 kiyohara /* Change Open-drain/Push-pull. */ 512 1.1 kiyohara mutex_enter(&sc->sc_mtx); 513 1.1 kiyohara reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC); 514 1.1 kiyohara if (on) 515 1.1 kiyohara reg &= ~HC_PUSHPULLEN; 516 1.1 kiyohara else 517 1.1 kiyohara reg |= HC_PUSHPULLEN; 518 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, reg); 519 1.1 kiyohara mutex_exit(&sc->sc_mtx); 520 1.1 kiyohara 521 1.1 kiyohara return 0; 522 1.1 kiyohara } 523 1.1 kiyohara 524 1.1 kiyohara static void 525 1.1 kiyohara mvsdio_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 526 1.1 kiyohara { 527 1.1 kiyohara struct mvsdio_softc *sc = (struct mvsdio_softc *)sch; 528 1.1 kiyohara uint32_t tm, c, hc, aacc, nisie, wait; 529 1.1 kiyohara int blklen; 530 1.1 kiyohara 531 1.1 kiyohara DPRINTF(1, ("%s: start cmd %d arg=%#x data=%p dlen=%d flags=%#x\n", 532 1.1 kiyohara device_xname(sc->sc_dev), cmd->c_opcode, cmd->c_arg, cmd->c_data, 533 1.1 kiyohara cmd->c_datalen, cmd->c_flags)); 534 1.1 kiyohara 535 1.1 kiyohara mutex_enter(&sc->sc_mtx); 536 1.1 kiyohara 537 1.1 kiyohara tm = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM); 538 1.1 kiyohara 539 1.1 kiyohara if (cmd->c_datalen > 0) { 540 1.1 kiyohara bus_dma_segment_t *dm_seg = 541 1.1 kiyohara &cmd->c_dmamap->dm_segs[cmd->c_dmaseg]; 542 1.1 kiyohara bus_addr_t ds_addr = dm_seg->ds_addr + cmd->c_dmaoff; 543 1.1 kiyohara 544 1.1 kiyohara blklen = MIN(cmd->c_datalen, cmd->c_blklen); 545 1.1 kiyohara 546 1.1 kiyohara if (cmd->c_datalen % blklen > 0) { 547 1.1 kiyohara aprint_error_dev(sc->sc_dev, 548 1.1 kiyohara "data not a multiple of %u bytes\n", blklen); 549 1.1 kiyohara cmd->c_error = EINVAL; 550 1.1 kiyohara goto out; 551 1.1 kiyohara } 552 1.1 kiyohara if ((uint32_t)cmd->c_data & 0x3) { 553 1.1 kiyohara aprint_error_dev(sc->sc_dev, 554 1.1 kiyohara "data not 4byte aligned\n"); 555 1.1 kiyohara cmd->c_error = EINVAL; 556 1.1 kiyohara goto out; 557 1.1 kiyohara } 558 1.1 kiyohara 559 1.1 kiyohara /* Set DMA Buffer Address */ 560 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_DMABA16LSB, 561 1.1 kiyohara ds_addr & 0xffff); 562 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_DMABA16MSB, 563 1.1 kiyohara (ds_addr >> 16) & 0xffff); 564 1.1 kiyohara 565 1.1 kiyohara /* Set Data Block Size and Count */ 566 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_DBS, 567 1.1 kiyohara DBS_BLOCKSIZE(blklen)); 568 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_DBC, 569 1.1 kiyohara DBC_BLOCKCOUNT(cmd->c_datalen / blklen)); 570 1.1 kiyohara 571 1.1 kiyohara tm &= ~TM_HOSTXFERMODE; /* Always DMA */ 572 1.1 kiyohara if (cmd->c_flags & SCF_CMD_READ) 573 1.1 kiyohara tm |= TM_DATAXFERTOWARDHOST; 574 1.1 kiyohara else 575 1.1 kiyohara tm &= ~TM_DATAXFERTOWARDHOST; 576 1.1 kiyohara tm |= TM_HWWRDATAEN; 577 1.1 kiyohara wait = NIS_XFERCOMPLETE; 578 1.1 kiyohara } else { 579 1.1 kiyohara tm &= ~TM_HWWRDATAEN; 580 1.1 kiyohara wait = NIS_CMDCOMPLETE; 581 1.1 kiyohara } 582 1.1 kiyohara 583 1.1 kiyohara /* Set Argument in Command */ 584 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_AC16LSB, 585 1.1 kiyohara cmd->c_arg & 0xffff); 586 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_AC16MSB, 587 1.1 kiyohara (cmd->c_arg >> 16) & 0xffff); 588 1.1 kiyohara 589 1.1 kiyohara /* Set Host Control, exclude PushPullEn, DataWidth, HiSpeedEn. */ 590 1.1 kiyohara hc = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC); 591 1.1 kiyohara hc |= (HC_TIMEOUTVALUE_MAX | HC_TIMEOUTEN); 592 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, hc); 593 1.1 kiyohara 594 1.1 kiyohara /* Data Block Gap Control: Resume */ 595 1.1 kiyohara 596 1.1 kiyohara /* Clock Control: SclkMasterEn */ 597 1.1 kiyohara 598 1.1 kiyohara if (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE || 599 1.1 kiyohara cmd->c_opcode == MMC_WRITE_BLOCK_MULTIPLE) { 600 1.1 kiyohara aacc = 0; 601 1.1 kiyohara #if 1 /* XXXX: need? */ 602 1.1 kiyohara if (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE) { 603 1.1 kiyohara struct sdmmc_softc *sdmmc = 604 1.1 kiyohara device_private(sc->sc_sdmmc); 605 1.1 kiyohara struct sdmmc_function *sf = sdmmc->sc_card; 606 1.1 kiyohara 607 1.1 kiyohara aacc = MMC_ARG_RCA(sf->rca); 608 1.1 kiyohara } 609 1.1 kiyohara #endif 610 1.1 kiyohara 611 1.1 kiyohara /* Set Argument in Auto Cmd12 Command */ 612 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_AACC16LSBT, 613 1.1 kiyohara aacc & 0xffff); 614 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_AACC16MSBT, 615 1.1 kiyohara (aacc >> 16) & 0xffff); 616 1.1 kiyohara 617 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_IACCT, 618 1.1 kiyohara IACCT_AUTOCMD12BUSYCHKEN | 619 1.1 kiyohara IACCT_AUTOCMD12INDEXCHKEN | 620 1.1 kiyohara IACCT_AUTOCMD12INDEX); 621 1.1 kiyohara 622 1.1 kiyohara tm |= TM_AUTOCMD12EN; 623 1.1 kiyohara wait = NIS_AUTOCMD12COMPLETE; 624 1.1 kiyohara } else 625 1.1 kiyohara tm &= ~TM_AUTOCMD12EN; 626 1.1 kiyohara 627 1.1 kiyohara tm |= TM_INTCHKEN; 628 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM, tm); 629 1.1 kiyohara 630 1.1 kiyohara c = C_CMDINDEX(cmd->c_opcode); 631 1.1 kiyohara if (cmd->c_flags & SCF_RSP_PRESENT) { 632 1.1 kiyohara if (cmd->c_flags & SCF_RSP_136) 633 1.1 kiyohara c |= C_RESPTYPE_136BR; 634 1.1 kiyohara else if (!(cmd->c_flags & SCF_RSP_BSY)) 635 1.1 kiyohara c |= C_RESPTYPE_48BR; 636 1.1 kiyohara else 637 1.1 kiyohara c |= C_RESPTYPE_48BRCB; 638 1.1 kiyohara c |= C_UNEXPECTEDRESPEN; 639 1.1 kiyohara } else 640 1.1 kiyohara c |= C_RESPTYPE_NR; 641 1.1 kiyohara if (cmd->c_flags & SCF_RSP_CRC) 642 1.1 kiyohara c |= C_CMDCRCCHKEN; 643 1.1 kiyohara if (cmd->c_flags & SCF_RSP_IDX) 644 1.1 kiyohara c |= C_CMDINDEXCHKEN; 645 1.1 kiyohara if (cmd->c_datalen > 0) 646 1.1 kiyohara c |= (C_DATAPRESENT | C_DATACRC16CHKEN); 647 1.1 kiyohara 648 1.1 kiyohara DPRINTF(2, ("%s: TM=0x%x, C=0x%x, HC=0x%x\n", __func__, tm, c, hc)); 649 1.1 kiyohara 650 1.1 kiyohara nisie = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE); 651 1.1 kiyohara nisie &= ~(NIS_CMDCOMPLETE | NIS_XFERCOMPLETE | NIS_AUTOCMD12COMPLETE); 652 1.1 kiyohara nisie |= wait; 653 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE, nisie); 654 1.1 kiyohara 655 1.1 kiyohara /* Execute command */ 656 1.1 kiyohara sc->sc_exec_cmd = cmd; 657 1.1 kiyohara sc->sc_waitintr = wait; 658 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_C, c); 659 1.1 kiyohara 660 1.1 kiyohara /* Wait interrupt for complete or error or timeout */ 661 1.1 kiyohara while (sc->sc_exec_cmd == cmd) 662 1.1 kiyohara cv_wait(&sc->sc_cv, &sc->sc_mtx); 663 1.1 kiyohara 664 1.1 kiyohara out: 665 1.1 kiyohara mutex_exit(&sc->sc_mtx); 666 1.1 kiyohara 667 1.1 kiyohara DPRINTF(1, ("%s: cmd %d done (flags=%08x error=%d)\n", 668 1.1 kiyohara device_xname(sc->sc_dev), 669 1.1 kiyohara cmd->c_opcode, cmd->c_flags, cmd->c_error)); 670 1.1 kiyohara } 671 1.1 kiyohara 672 1.1 kiyohara static void 673 1.1 kiyohara mvsdio_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) 674 1.1 kiyohara { 675 1.1 kiyohara struct mvsdio_softc *sc = (struct mvsdio_softc *)sch; 676 1.1 kiyohara uint32_t reg; 677 1.1 kiyohara 678 1.1 kiyohara mutex_enter(&sc->sc_mtx); 679 1.1 kiyohara reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE); 680 1.1 kiyohara reg |= NIS_CARDINT; 681 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE, reg); 682 1.1 kiyohara mutex_exit(&sc->sc_mtx); 683 1.1 kiyohara } 684 1.1 kiyohara 685 1.1 kiyohara static void 686 1.1 kiyohara mvsdio_card_intr_ack(sdmmc_chipset_handle_t sch) 687 1.1 kiyohara { 688 1.1 kiyohara 689 1.1 kiyohara /* Nothing */ 690 1.1 kiyohara } 691 1.1 kiyohara 692 1.1 kiyohara 693 1.1 kiyohara static void 694 1.5 kiyohara mvsdio_wininit(struct mvsdio_softc *sc, enum marvell_tags *tags) 695 1.1 kiyohara { 696 1.1 kiyohara uint64_t base; 697 1.1 kiyohara uint32_t size; 698 1.1 kiyohara int window, target, attr, rv, i; 699 1.1 kiyohara 700 1.1 kiyohara for (window = 0, i = 0; 701 1.1 kiyohara tags[i] != MARVELL_TAG_UNDEFINED && window < MVSDIO_NWINDOW; i++) { 702 1.1 kiyohara rv = marvell_winparams_by_tag(sc->sc_dev, tags[i], 703 1.1 kiyohara &target, &attr, &base, &size); 704 1.1 kiyohara if (rv != 0 || size == 0) 705 1.1 kiyohara continue; 706 1.1 kiyohara 707 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_WC(window), 708 1.1 kiyohara WC_WINEN | 709 1.1 kiyohara WC_TARGET(target) | 710 1.1 kiyohara WC_ATTR(attr) | 711 1.1 kiyohara WC_SIZE(size)); 712 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_WB(window), 713 1.1 kiyohara WB_BASE(base)); 714 1.1 kiyohara window++; 715 1.1 kiyohara } 716 1.1 kiyohara for (; window < MVSDIO_NWINDOW; window++) 717 1.1 kiyohara bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_WC(window), 0); 718 1.1 kiyohara } 719