1 1.8 skrll /* $NetBSD: s3c2440_sdi.c,v 1.8 2022/09/27 06:36:43 skrll Exp $ */ 2 1.1 nisimura /*- 3 1.1 nisimura * Copyright (c) 2012 The NetBSD Foundation, Inc. 4 1.1 nisimura * All rights reserved. 5 1.1 nisimura * 6 1.1 nisimura * This code is derived from software contributed to The NetBSD Foundation 7 1.1 nisimura * by Paul Fleischer <paul (at) xpg.dk> 8 1.1 nisimura * 9 1.1 nisimura * Redistribution and use in source and binary forms, with or without 10 1.1 nisimura * modification, are permitted provided that the following conditions 11 1.1 nisimura * are met: 12 1.1 nisimura * 1. Redistributions of source code must retain the above copyright 13 1.1 nisimura * notice, this list of conditions and the following disclaimer. 14 1.1 nisimura * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 nisimura * notice, this list of conditions and the following disclaimer in the 16 1.1 nisimura * documentation and/or other materials provided with the distribution. 17 1.1 nisimura * 18 1.1 nisimura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 1.1 nisimura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 1.1 nisimura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 1.1 nisimura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 1.1 nisimura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 1.1 nisimura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 1.1 nisimura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 1.1 nisimura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 1.1 nisimura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 1.1 nisimura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 1.1 nisimura * POSSIBILITY OF SUCH DAMAGE. 29 1.1 nisimura */ 30 1.1 nisimura #include <sys/cdefs.h> 31 1.8 skrll __KERNEL_RCSID(0, "$NetBSD: s3c2440_sdi.c,v 1.8 2022/09/27 06:36:43 skrll Exp $"); 32 1.1 nisimura 33 1.1 nisimura #include <sys/param.h> 34 1.1 nisimura #include <sys/kernel.h> 35 1.1 nisimura #include <sys/systm.h> 36 1.1 nisimura #include <sys/conf.h> 37 1.1 nisimura 38 1.1 nisimura #include <sys/mutex.h> 39 1.1 nisimura #include <sys/condvar.h> 40 1.1 nisimura 41 1.1 nisimura #include <sys/bus.h> 42 1.1 nisimura #include <machine/cpu.h> 43 1.1 nisimura 44 1.1 nisimura #include <arm/s3c2xx0/s3c24x0var.h> 45 1.1 nisimura #include <arm/s3c2xx0/s3c2440var.h> 46 1.1 nisimura #include <arm/s3c2xx0/s3c24x0reg.h> 47 1.1 nisimura #include <arm/s3c2xx0/s3c2440reg.h> 48 1.1 nisimura #include <arm/s3c2xx0/s3c2440_dma.h> 49 1.1 nisimura 50 1.1 nisimura //#include <arm/s3c2xx0/s3c2440_sdi.h> 51 1.1 nisimura 52 1.1 nisimura #include <dev/sdmmc/sdmmcchip.h> 53 1.1 nisimura #include <dev/sdmmc/sdmmcvar.h> 54 1.1 nisimura 55 1.1 nisimura #include <uvm/uvm_extern.h> 56 1.1 nisimura /*#define SSSDI_DEBUG*/ 57 1.1 nisimura #ifdef SSSDI_DEBUG 58 1.1 nisimura #define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) 59 1.1 nisimura #else 60 1.1 nisimura #define DPRINTF(s) do {} while (/*CONSTCOND*/0) 61 1.1 nisimura #endif 62 1.1 nisimura 63 1.1 nisimura struct sssdi_softc { 64 1.1 nisimura device_t dev; 65 1.1 nisimura 66 1.1 nisimura bus_space_tag_t iot; 67 1.1 nisimura 68 1.1 nisimura bus_space_handle_t ioh; 69 1.1 nisimura bus_space_handle_t card_ioh; /* Card detect I/O*/ 70 1.1 nisimura 71 1.1 nisimura device_t sdmmc; 72 1.1 nisimura 73 1.1 nisimura uint32_t caps; 74 1.1 nisimura 75 1.1 nisimura int width; /* Transfer width */ 76 1.1 nisimura void *sc_ih; /* SSSDI Interrupt handler */ 77 1.1 nisimura 78 1.1 nisimura struct kmutex intr_mtx; 79 1.1 nisimura struct kcondvar intr_cv; 80 1.1 nisimura uint32_t intr_status; /* Set by the interrupt handler */ 81 1.1 nisimura 82 1.1 nisimura dmac_xfer_t sc_xfer; 83 1.1 nisimura 84 1.1 nisimura bus_dma_segment_t sc_dr; 85 1.1 nisimura }; 86 1.1 nisimura 87 1.1 nisimura /* Basic driver stuff */ 88 1.2 chs static int sssdi_match(device_t, cfdata_t, void *); 89 1.2 chs static void sssdi_attach(device_t, device_t, void *); 90 1.1 nisimura 91 1.1 nisimura CFATTACH_DECL_NEW(sssdi, sizeof(struct sssdi_softc), sssdi_match, sssdi_attach, 92 1.1 nisimura NULL, NULL); 93 1.1 nisimura 94 1.1 nisimura /* SD/MMC chip functions */ 95 1.1 nisimura static int sssdi_host_reset(sdmmc_chipset_handle_t); 96 1.1 nisimura static uint32_t sssdi_host_ocr(sdmmc_chipset_handle_t); 97 1.1 nisimura static int sssdi_maxblklen(sdmmc_chipset_handle_t); 98 1.1 nisimura static int sssdi_card_detect(sdmmc_chipset_handle_t); 99 1.1 nisimura static int sssdi_write_protect(sdmmc_chipset_handle_t); 100 1.1 nisimura static int sssdi_bus_power(sdmmc_chipset_handle_t, uint32_t); 101 1.1 nisimura static int sssdi_bus_clock(sdmmc_chipset_handle_t, int); 102 1.1 nisimura static int sssdi_bus_width(sdmmc_chipset_handle_t, int); 103 1.1 nisimura static int sssdi_bus_rod(sdmmc_chipset_handle_t, int); 104 1.1 nisimura static void sssdi_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); 105 1.1 nisimura static void sssdi_card_enable_intr(sdmmc_chipset_handle_t, int); 106 1.1 nisimura static void sssdi_card_intr_ack(sdmmc_chipset_handle_t); 107 1.1 nisimura 108 1.1 nisimura /* Interrupt Handlers */ 109 1.1 nisimura int sssdi_intr(void *arg); 110 1.1 nisimura int sssdi_intr_card(void *arg); 111 1.1 nisimura 112 1.1 nisimura /* Interrupt helper functions */ 113 1.1 nisimura static void sssdi_enable_intr(struct sssdi_softc *, uint32_t ); 114 1.1 nisimura void sssdi_disable_intr(struct sssdi_softc *sc, uint32_t i); 115 1.1 nisimura void sssdi_clear_intr(struct sssdi_softc *sc); 116 1.1 nisimura static int sssdi_wait_intr(struct sssdi_softc *sc, uint32_t mask, int timeout); 117 1.1 nisimura 118 1.1 nisimura /* Programmed I/O transfer helpers */ 119 1.1 nisimura void sssdi_perform_pio_read(struct sssdi_softc *sc, struct sdmmc_command *cmd); 120 1.1 nisimura void sssdi_perform_pio_write(struct sssdi_softc *sc, struct sdmmc_command *cmd); 121 1.1 nisimura 122 1.1 nisimura /* Interrupt helper defines */ 123 1.1 nisimura #define SDI_CMD_SENT SDIINTMASK_CMD_SENT 124 1.1 nisimura #define SDI_CMD_TIMEOUT SDIINTMASK_CMD_TIMEOUT 125 1.1 nisimura #define SDI_RESP_FIN SDIINTMASK_RESP 126 1.1 nisimura #define SDI_FIFO_RX_FULL SDIINTMASK_RF_FULL 127 1.1 nisimura #define SDI_FIFO_RX_LAST SDIINTMASK_RF_LAST 128 1.1 nisimura #define SDI_FIFO_TX_EMPTY SDIINTMASK_TF_EMPTY 129 1.1 nisimura #define SDI_DATA_FIN SDIINTMASK_DATA_FIN 130 1.1 nisimura #define SDI_DATA_TIMEOUT SDIINTMASK_DATA_TIMEOUT 131 1.1 nisimura 132 1.1 nisimura /* Constants */ 133 1.1 nisimura #define SDI_DMA_WAIT_TIME 5000 /* ms */ 134 1.1 nisimura #define SDI_CMD_WAIT_TIME 5000 /* ms */ 135 1.1 nisimura 136 1.1 nisimura /* SDMMC function structure */ 137 1.1 nisimura struct sdmmc_chip_functions sssdi_functions = { 138 1.1 nisimura /* host controller reset */ 139 1.4 christos .host_reset = sssdi_host_reset, 140 1.1 nisimura 141 1.1 nisimura /* host capabilities */ 142 1.4 christos .host_ocr = sssdi_host_ocr, 143 1.4 christos .host_maxblklen = sssdi_maxblklen, 144 1.1 nisimura 145 1.1 nisimura /* card detection */ 146 1.4 christos .card_detect = sssdi_card_detect, 147 1.1 nisimura 148 1.1 nisimura /* write protect */ 149 1.4 christos .write_protect = sssdi_write_protect, 150 1.1 nisimura 151 1.1 nisimura /* bus power, clock frequency and width */ 152 1.4 christos .bus_power = sssdi_bus_power, 153 1.4 christos .bus_clock = sssdi_bus_clock, 154 1.4 christos .bus_width = sssdi_bus_width, 155 1.4 christos .bus_rod = sssdi_bus_rod, 156 1.1 nisimura 157 1.1 nisimura /* command execution */ 158 1.4 christos .exec_command = sssdi_exec_command, 159 1.1 nisimura 160 1.1 nisimura /* card interrupt */ 161 1.4 christos .card_enable_intr = sssdi_card_enable_intr, 162 1.4 christos .card_intr_ack = sssdi_card_intr_ack, 163 1.1 nisimura }; 164 1.1 nisimura 165 1.1 nisimura int 166 1.2 chs sssdi_match(device_t parent, cfdata_t match, void *aux) 167 1.1 nisimura { 168 1.1 nisimura /* struct s3c2xx0_attach_args *sa = aux;*/ 169 1.1 nisimura 170 1.1 nisimura /* Not sure how to match here, maybe CPU type? */ 171 1.1 nisimura return 1; 172 1.1 nisimura } 173 1.1 nisimura 174 1.1 nisimura void 175 1.2 chs sssdi_attach(device_t parent, device_t self, void *aux) 176 1.1 nisimura { 177 1.1 nisimura struct sssdi_softc *sc = device_private(self); 178 1.1 nisimura struct s3c2xx0_attach_args *sa = (struct s3c2xx0_attach_args *)aux; 179 1.1 nisimura struct sdmmcbus_attach_args saa; 180 1.1 nisimura bus_space_tag_t iot = sa->sa_iot; 181 1.1 nisimura uint32_t data; 182 1.1 nisimura 183 1.1 nisimura sc->dev = self; 184 1.1 nisimura sc->iot = iot; 185 1.1 nisimura 186 1.1 nisimura if (bus_space_map(iot, S3C2440_SDI_BASE, S3C2440_SDI_SIZE, 0, &sc->ioh) ) { 187 1.1 nisimura printf(": failed to map registers"); 188 1.1 nisimura return; 189 1.1 nisimura } 190 1.1 nisimura 191 1.1 nisimura if (bus_space_map(iot, S3C2440_GPIO_BASE, S3C2440_GPIO_SIZE, 0, &sc->card_ioh) ) { 192 1.1 nisimura printf(": failed to map GPIO memory for card detection"); 193 1.1 nisimura return; 194 1.1 nisimura } 195 1.1 nisimura 196 1.1 nisimura /* Set GPG8 to EINT[16], as it is the card detect line. */ 197 1.1 nisimura data = bus_space_read_4(sc->iot, sc->card_ioh, GPIO_PGCON); 198 1.1 nisimura data = GPIO_SET_FUNC(data, 8, 0x2); 199 1.1 nisimura bus_space_write_4(sc->iot, sc->card_ioh, GPIO_PGCON, data); 200 1.1 nisimura 201 1.1 nisimura /* Set GPH8 to input, as it is used to detect write protection. */ 202 1.1 nisimura data = bus_space_read_4(sc->iot, sc->card_ioh, GPIO_PHCON); 203 1.1 nisimura data = GPIO_SET_FUNC(data, 8, 0x00); 204 1.1 nisimura bus_space_write_4(sc->iot, sc->card_ioh, GPIO_PHCON, data); 205 1.1 nisimura 206 1.1 nisimura mutex_init(&sc->intr_mtx, MUTEX_DEFAULT, IPL_SDMMC); 207 1.1 nisimura 208 1.1 nisimura cv_init(&sc->intr_cv, "s3c2440_sdiintr"); 209 1.1 nisimura sc->intr_status = 0; 210 1.1 nisimura sc->caps = SMC_CAPS_4BIT_MODE | SMC_CAPS_DMA | SMC_CAPS_MULTI_SEG_DMA; 211 1.1 nisimura 212 1.1 nisimura memset(&saa, 0, sizeof(saa)); 213 1.1 nisimura saa.saa_busname = "sdmmc"; 214 1.1 nisimura saa.saa_sct = &sssdi_functions; 215 1.1 nisimura saa.saa_sch = sc; 216 1.1 nisimura saa.saa_dmat = sa->sa_dmat; 217 1.1 nisimura saa.saa_clkmin = s3c2xx0_softc->sc_pclk / 256; 218 1.1 nisimura saa.saa_clkmax = s3c2xx0_softc->sc_pclk / 1; /* PCLK/1 or PCLK/2 depending on how the spec is read */ 219 1.1 nisimura saa.saa_caps = sc->caps; 220 1.1 nisimura 221 1.1 nisimura /* Attach our interrupt handler */ 222 1.1 nisimura sc->sc_ih = s3c24x0_intr_establish(S3C2410_INT_SDI, IPL_SDMMC, IST_EDGE_RISING, sssdi_intr, sc); 223 1.1 nisimura 224 1.1 nisimura /* Attach interrupt handler to detect change in card status */ 225 1.1 nisimura s3c2440_extint_establish(16, IPL_SDMMC, IST_EDGE_BOTH, sssdi_intr_card, sc); 226 1.1 nisimura 227 1.1 nisimura data = bus_space_read_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_clkman_ioh, CLKMAN_CLKCON); 228 1.1 nisimura bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_clkman_ioh, CLKMAN_CLKCON, data | CLKCON_SDI); 229 1.1 nisimura 230 1.1 nisimura (void) sssdi_host_reset(sc); 231 1.1 nisimura 232 1.1 nisimura printf("\n"); 233 1.1 nisimura 234 1.1 nisimura /* Attach to the generic SD/MMC bus */ 235 1.1 nisimura /* Is it a good idea to get the private parts of sdmmc ? */ 236 1.7 thorpej sc->sdmmc = config_found(sc->dev, &saa, NULL, CFARGS_NONE); 237 1.1 nisimura 238 1.5 chs sc->sc_xfer = s3c2440_dmac_allocate_xfer(); 239 1.1 nisimura sc->sc_dr.ds_addr = S3C2440_SDI_BASE+SDI_DAT_LI_W; 240 1.1 nisimura sc->sc_dr.ds_len = 4; 241 1.1 nisimura } 242 1.1 nisimura 243 1.1 nisimura int 244 1.1 nisimura sssdi_host_reset(sdmmc_chipset_handle_t sch) 245 1.1 nisimura { 246 1.1 nisimura struct sssdi_softc *sc = (struct sssdi_softc*)sch; 247 1.1 nisimura 248 1.1 nisimura /* Note that we do not enable the clock just yet. */ 249 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_CON, SDICON_SD_RESET | 250 1.1 nisimura SDICON_CTYP_SD | SDICON_RCV_IO_INT); 251 1.1 nisimura /* bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_STA, SDICMDSTA_RSP_CRC | SDICMDSTA_CMD_SENT | 252 1.1 nisimura SDICMDSTA_CMD_TIMEOUT | SDICMDSTA_RSP_FIN);*/ 253 1.1 nisimura 254 1.1 nisimura sssdi_clear_intr(sc); 255 1.1 nisimura sssdi_enable_intr(sc, SDI_CMD_SENT | SDI_CMD_TIMEOUT | SDI_DATA_TIMEOUT 256 1.1 nisimura | SDI_RESP_FIN); 257 1.1 nisimura 258 1.1 nisimura return 0; 259 1.1 nisimura } 260 1.1 nisimura 261 1.1 nisimura uint32_t 262 1.1 nisimura sssdi_host_ocr(sdmmc_chipset_handle_t sch) 263 1.1 nisimura { 264 1.1 nisimura /* This really ought to be made configurable, I guess... */ 265 1.1 nisimura return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 266 1.1 nisimura } 267 1.1 nisimura 268 1.1 nisimura int 269 1.1 nisimura sssdi_maxblklen(sdmmc_chipset_handle_t sch) 270 1.1 nisimura { 271 1.1 nisimura /* The S3C2440 user's manual mentions 4095 as a maximum */ 272 1.1 nisimura return 4095; 273 1.1 nisimura } 274 1.1 nisimura 275 1.1 nisimura int 276 1.1 nisimura sssdi_card_detect(sdmmc_chipset_handle_t sch) 277 1.1 nisimura { 278 1.1 nisimura struct sssdi_softc *sc = (struct sssdi_softc*)sch; 279 1.1 nisimura uint32_t data; 280 1.1 nisimura 281 1.1 nisimura DPRINTF(("sssdi_card_detect\n")); 282 1.1 nisimura 283 1.1 nisimura data = bus_space_read_4(sc->iot, sc->card_ioh, GPIO_PGDAT); 284 1.1 nisimura 285 1.1 nisimura /* GPIO Port G, pin 8 is high when card is inserted. */ 286 1.1 nisimura if ( (data & (1<<8)) == 0) { 287 1.1 nisimura return 1; /* Card Present */ 288 1.1 nisimura } else { 289 1.1 nisimura return 0; /* No Card */ 290 1.1 nisimura } 291 1.1 nisimura } 292 1.1 nisimura 293 1.1 nisimura int 294 1.1 nisimura sssdi_write_protect(sdmmc_chipset_handle_t sch) 295 1.1 nisimura { 296 1.1 nisimura struct sssdi_softc *sc = (struct sssdi_softc*)sch; 297 1.1 nisimura uint32_t data; 298 1.1 nisimura 299 1.1 nisimura data = bus_space_read_4(sc->iot, sc->card_ioh, GPIO_PHDAT); 300 1.1 nisimura 301 1.1 nisimura 302 1.1 nisimura /* If GPIO Port H Pin 8 is high, the card is write protected. */ 303 1.1 nisimura if ( (data & (1<<8)) ) { 304 1.1 nisimura return 1; /* Write protected */ 305 1.1 nisimura } else { 306 1.1 nisimura return 0; /* Writable */ 307 1.1 nisimura } 308 1.1 nisimura } 309 1.1 nisimura 310 1.1 nisimura int 311 1.1 nisimura sssdi_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 312 1.1 nisimura { 313 1.1 nisimura /* Do nothing, we can't adjust the bus power */ 314 1.1 nisimura return 0; 315 1.1 nisimura } 316 1.1 nisimura 317 1.1 nisimura int 318 1.1 nisimura sssdi_bus_clock(sdmmc_chipset_handle_t sch, int freq) 319 1.1 nisimura { 320 1.1 nisimura struct sssdi_softc *sc = (struct sssdi_softc*)sch; 321 1.1 nisimura int div; 322 1.1 nisimura int clock_set = 0; 323 1.1 nisimura int control; 324 1.1 nisimura int pclk = s3c2xx0_softc->sc_pclk/1000; /*Peripheral bus clock in KHz*/ 325 1.1 nisimura 326 1.1 nisimura /* Round peripheral bus clock down to nearest MHz */ 327 1.1 nisimura pclk = (pclk / 1000) * 1000; 328 1.1 nisimura 329 1.1 nisimura control = bus_space_read_4(sc->iot, sc->ioh, SDI_CON); 330 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_CON, control & ~SDICON_ENCLK); 331 1.1 nisimura 332 1.1 nisimura DPRINTF(("sssdi_bus_clock (freq: %d KHz)\n", freq)); 333 1.1 nisimura 334 1.1 nisimura /* If the frequency is zero just keep the clock disabled */ 335 1.1 nisimura if (freq == 0) 336 1.1 nisimura return 0; 337 1.1 nisimura 338 1.1 nisimura for (div = 1; div <= 256; div++) { 339 1.1 nisimura if ( pclk / div <= freq) { 340 1.1 nisimura DPRINTF(("Using divisor %d: %d/%d = %d\n", div, pclk, 341 1.1 nisimura div, pclk/div)); 342 1.1 nisimura clock_set = 1; 343 1.1 nisimura bus_space_write_1(sc->iot, sc->ioh, SDI_PRE, div-1); 344 1.1 nisimura break; 345 1.1 nisimura } 346 1.1 nisimura } 347 1.1 nisimura 348 1.1 nisimura if (clock_set) { 349 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, 350 1.1 nisimura SDI_CON, control | SDICON_ENCLK); 351 1.1 nisimura if (div-1 == bus_space_read_4(sc->iot, sc->ioh, SDI_PRE)) { 352 1.1 nisimura /* Clock successfully set, TODO: how do we fail?! */ 353 1.1 nisimura } 354 1.1 nisimura 355 1.1 nisimura /* We do not need to wait here, as the sdmmc code will do that 356 1.1 nisimura for us. */ 357 1.1 nisimura return 0; 358 1.1 nisimura } else { 359 1.1 nisimura return 1; 360 1.1 nisimura } 361 1.1 nisimura } 362 1.1 nisimura 363 1.1 nisimura int 364 1.1 nisimura sssdi_bus_width(sdmmc_chipset_handle_t sch, int width) 365 1.1 nisimura { 366 1.1 nisimura struct sssdi_softc *sc = (struct sssdi_softc*)sch; 367 1.1 nisimura 368 1.1 nisimura sc->width = width; 369 1.1 nisimura return 0; 370 1.1 nisimura } 371 1.1 nisimura 372 1.1 nisimura int 373 1.1 nisimura sssdi_bus_rod(sdmmc_chipset_handle_t sch, int on) 374 1.1 nisimura { 375 1.1 nisimura return -1; 376 1.1 nisimura } 377 1.1 nisimura 378 1.1 nisimura #define SSSDI_TRANSFER_NONE 0 379 1.1 nisimura #define SSSDI_TRANSFER_READ 1 380 1.1 nisimura #define SSSDI_TRANSFER_WRITE 2 381 1.1 nisimura 382 1.1 nisimura void 383 1.1 nisimura sssdi_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 384 1.1 nisimura { 385 1.1 nisimura struct sssdi_softc *sc = (struct sssdi_softc*)sch; 386 1.1 nisimura uint32_t cmd_control; 387 1.1 nisimura int status = 0; 388 1.3 skrll #ifdef SSSDI_DEBUG 389 1.1 nisimura uint32_t data_status; 390 1.3 skrll #endif 391 1.1 nisimura int transfer = SSSDI_TRANSFER_NONE; 392 1.1 nisimura dmac_xfer_t xfer; 393 1.1 nisimura 394 1.1 nisimura /* Reset all status registers prior to sending a command */ 395 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_FSTA, 0xFFFFFFFF); 396 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_STA, 0xFFFFFFFF); 397 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_STA, 0xFFFFFFFF); 398 1.1 nisimura 399 1.1 nisimura /* Set the argument */ 400 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_ARG, cmd->c_arg); 401 1.1 nisimura 402 1.1 nisimura /* Prepare the value for the command control register */ 403 1.1 nisimura cmd_control = (cmd->c_opcode & SDICMDCON_CMD_MASK) | 404 1.1 nisimura SDICMDCON_HOST_CMD | SDICMDCON_CMST; 405 1.1 nisimura if (cmd->c_flags & SCF_RSP_PRESENT) 406 1.1 nisimura cmd_control |= SDICMDCON_WAIT_RSP; 407 1.1 nisimura if (cmd->c_flags & SCF_RSP_136) 408 1.1 nisimura cmd_control |= SDICMDCON_LONG_RSP; 409 1.1 nisimura 410 1.1 nisimura if (cmd->c_datalen > 0 && cmd->c_data != NULL) { 411 1.1 nisimura /* TODO: Ensure that the above condition matches the semantics 412 1.1 nisimura of SDICMDCON_WITH_DATA*/ 413 1.1 nisimura DPRINTF(("DATA, datalen: %d, blk_size: %d\n", cmd->c_datalen, 414 1.1 nisimura cmd->c_blklen)); 415 1.1 nisimura cmd_control |= SDICMDCON_WITH_DATA; 416 1.1 nisimura } 417 1.1 nisimura 418 1.1 nisimura /* Unfortunately we have to set the ABORT_CMD bit when using CMD12 and 419 1.1 nisimura CMD52. 420 1.1 nisimura CMD12 is MMC_STOP_TRANSMISSION. I currently do not know what CMD52 421 1.1 nisimura is, but it is related to SDIO. 422 1.1 nisimura */ 423 1.1 nisimura if (cmd->c_opcode == MMC_STOP_TRANSMISSION) { 424 1.1 nisimura cmd_control |= SDICMDCON_ABORT_CMD; 425 1.1 nisimura } 426 1.1 nisimura 427 1.1 nisimura /* Prepare SDI for data transfer */ 428 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_BSIZE, cmd->c_blklen); 429 1.1 nisimura 430 1.1 nisimura /* Set maximum transfer timeout */ 431 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DTIMER, 0x007FFFFF); 432 1.1 nisimura 433 1.1 nisimura /* Set the timeout as low as possible to trigger timeouts for debugging purposes */ 434 1.1 nisimura /*bus_space_write_4(sc->iot, sc->ioh, SDI_DTIMER, 0x00005000);*/ 435 1.1 nisimura 436 1.1 nisimura if ( (cmd->c_flags & SCF_CMD_READ) && 437 1.1 nisimura (cmd_control & SDICMDCON_WITH_DATA)) { 438 1.1 nisimura uint32_t data_control; 439 1.1 nisimura DPRINTF(("Reading %d bytes\n", cmd->c_datalen)); 440 1.1 nisimura transfer = SSSDI_TRANSFER_READ; 441 1.1 nisimura 442 1.1 nisimura data_control = SDIDATCON_DATMODE_RECEIVE | SDIDATCON_RACMD | 443 1.1 nisimura SDIDATCON_DTST | SDIDATCON_BLKMODE | 444 1.1 nisimura ((cmd->c_datalen / cmd->c_blklen) & SDIDATCON_BLKNUM_MASK) | 445 1.1 nisimura SDIDATCON_DATA_WORD; 446 1.1 nisimura 447 1.1 nisimura if (sc->caps & SMC_CAPS_DMA) { 448 1.1 nisimura data_control |= SDIDATCON_ENDMA; 449 1.1 nisimura xfer = sc->sc_xfer; 450 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_bus_type = DMAC_BUS_TYPE_PERIPHERAL; 451 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_increment = FALSE; 452 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_nsegs = 1; 453 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_dma_segs = &sc->sc_dr; 454 1.1 nisimura 455 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_bus_type = DMAC_BUS_TYPE_SYSTEM; 456 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_increment = TRUE; 457 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_nsegs = cmd->c_dmamap->dm_nsegs; 458 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_dma_segs = cmd->c_dmamap->dm_segs; 459 1.1 nisimura 460 1.1 nisimura /* Let the SD/MMC peripheral control the DMA transfer */ 461 1.1 nisimura xfer->dx_peripheral = DMAC_PERIPH_SDI; 462 1.1 nisimura xfer->dx_xfer_width = DMAC_XFER_WIDTH_32BIT; 463 1.1 nisimura } 464 1.1 nisimura if (sc->width == 4) { 465 1.1 nisimura data_control |= SDIDATCON_WIDEBUS; 466 1.1 nisimura } 467 1.1 nisimura 468 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_CON, data_control); 469 1.1 nisimura } else if (cmd_control & SDICMDCON_WITH_DATA) { 470 1.1 nisimura /* Write data */ 471 1.1 nisimura 472 1.1 nisimura uint32_t data_control; 473 1.1 nisimura DPRINTF(("Writing %d bytes\n", cmd->c_datalen)); 474 1.1 nisimura DPRINTF(("Requesting %d blocks\n", 475 1.1 nisimura cmd->c_datalen / cmd->c_blklen)); 476 1.1 nisimura transfer = SSSDI_TRANSFER_WRITE; 477 1.1 nisimura data_control = SDIDATCON_DATMODE_TRANSMIT | SDIDATCON_BLKMODE | 478 1.1 nisimura SDIDATCON_TARSP | SDIDATCON_DTST | 479 1.1 nisimura ((cmd->c_datalen / cmd->c_blklen) & SDIDATCON_BLKNUM_MASK) | 480 1.1 nisimura SDIDATCON_DATA_WORD; 481 1.1 nisimura 482 1.1 nisimura if (sc->caps & SMC_CAPS_DMA) { 483 1.1 nisimura data_control |= SDIDATCON_ENDMA; 484 1.1 nisimura xfer = sc->sc_xfer; 485 1.1 nisimura 486 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_bus_type = DMAC_BUS_TYPE_PERIPHERAL; 487 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_increment = FALSE; 488 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_nsegs = 1; 489 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_dma_segs = &sc->sc_dr; 490 1.1 nisimura 491 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_bus_type = DMAC_BUS_TYPE_SYSTEM; 492 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_increment = TRUE; 493 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_nsegs = cmd->c_dmamap->dm_nsegs; 494 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_dma_segs = cmd->c_dmamap->dm_segs; 495 1.1 nisimura 496 1.1 nisimura /* Let the SD/MMC peripheral control the DMA transfer */ 497 1.1 nisimura xfer->dx_peripheral = DMAC_PERIPH_SDI; 498 1.1 nisimura xfer->dx_xfer_width = DMAC_XFER_WIDTH_32BIT; 499 1.1 nisimura } 500 1.1 nisimura if (sc->width == 4) { 501 1.1 nisimura data_control |= SDIDATCON_WIDEBUS; 502 1.1 nisimura } 503 1.1 nisimura 504 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_CON, data_control); 505 1.1 nisimura } 506 1.1 nisimura 507 1.1 nisimura /* Send command to SDI */ 508 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_CON, cmd_control); 509 1.1 nisimura 510 1.1 nisimura /* Wait for command sent acknowledgement, timeout set to 5000ms */ 511 1.1 nisimura status = sssdi_wait_intr(sc, SDI_CMD_SENT | SDI_CMD_TIMEOUT, mstohz(SDI_CMD_WAIT_TIME)); 512 1.1 nisimura 513 1.1 nisimura if (status & SDI_CMD_TIMEOUT) { 514 1.1 nisimura DPRINTF(("Timeout waiting for command acknowledgement\n")); 515 1.1 nisimura cmd->c_error = ETIMEDOUT; 516 1.1 nisimura goto out; 517 1.1 nisimura } else if (status & SDICMDSTA_CMD_SENT) { 518 1.1 nisimura /* Interrupt handler has acknowledged already, we do not need 519 1.1 nisimura to do anything further here */ 520 1.1 nisimura } 521 1.1 nisimura 522 1.1 nisimura if (!(cmd_control & SDICMDCON_WAIT_RSP)) { 523 1.1 nisimura cmd->c_flags |= SCF_ITSDONE; 524 1.1 nisimura goto out; 525 1.1 nisimura } 526 1.1 nisimura 527 1.1 nisimura DPRINTF(("waiting for response\n")); 528 1.1 nisimura 529 1.1 nisimura status = sssdi_wait_intr(sc, SDI_RESP_FIN | SDI_DATA_TIMEOUT, 100); 530 1.1 nisimura if (status & SDI_CMD_TIMEOUT || status & SDI_DATA_TIMEOUT) { 531 1.1 nisimura cmd->c_error = ETIMEDOUT; 532 1.1 nisimura DPRINTF(("Timeout waiting for response\n")); 533 1.1 nisimura goto out; 534 1.1 nisimura } 535 1.1 nisimura DPRINTF(("Got Response\n")); 536 1.1 nisimura 537 1.1 nisimura 538 1.1 nisimura if (cmd->c_flags & SCF_RSP_136 ) { 539 1.1 nisimura uint32_t w[4]; 540 1.1 nisimura 541 1.1 nisimura /* We store the response least significant word first */ 542 1.1 nisimura w[0] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP3); 543 1.1 nisimura w[1] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP2); 544 1.1 nisimura w[2] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP1); 545 1.1 nisimura w[3] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP0); 546 1.1 nisimura 547 1.1 nisimura /* The sdmmc subsystem expects that the response is delivered 548 1.1 nisimura without the lower 8 bits (CRC + '1' bit) */ 549 1.1 nisimura cmd->c_resp[0] = (w[0] >> 8) | ((w[1] & 0xFF) << 24); 550 1.1 nisimura cmd->c_resp[1] = (w[1] >> 8) | ((w[2] & 0XFF) << 24); 551 1.1 nisimura cmd->c_resp[2] = (w[2] >> 8) | ((w[3] & 0XFF) << 24); 552 1.1 nisimura cmd->c_resp[3] = (w[3] >> 8); 553 1.1 nisimura 554 1.1 nisimura } else { 555 1.1 nisimura cmd->c_resp[0] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP0); 556 1.1 nisimura cmd->c_resp[1] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP1); 557 1.1 nisimura } 558 1.1 nisimura 559 1.1 nisimura DPRINTF(("Response: %X %X %X %X\n", 560 1.1 nisimura cmd->c_resp[0], 561 1.1 nisimura cmd->c_resp[1], 562 1.1 nisimura cmd->c_resp[2], 563 1.1 nisimura cmd->c_resp[3])); 564 1.1 nisimura 565 1.1 nisimura status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_CNT); 566 1.1 nisimura 567 1.1 nisimura DPRINTF(("Remaining bytes of current block: %d\n", 568 1.1 nisimura SDIDATCNT_BLK_CNT(status))); 569 1.1 nisimura DPRINTF(("Remaining Block Number : %d\n", 570 1.1 nisimura SDIDATCNT_BLK_NUM_CNT(status))); 571 1.1 nisimura 572 1.3 skrll #ifdef SSSDI_DEBUG 573 1.1 nisimura data_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_STA); 574 1.1 nisimura printf("SDI Data Status Register Before xfer: 0x%X\n", data_status); 575 1.1 nisimura #endif 576 1.1 nisimura if (transfer == SSSDI_TRANSFER_READ) { 577 1.1 nisimura DPRINTF(("Waiting for transfer to complete\n")); 578 1.1 nisimura 579 1.1 nisimura if (sc->sc_xfer != NULL ) { 580 1.1 nisimura int dma_error = 0; 581 1.1 nisimura /* It might not be very efficient to delay the start of 582 1.1 nisimura the DMA transfer until now, but it works :-). 583 1.1 nisimura */ 584 1.1 nisimura s3c2440_dmac_start_xfer(sc->sc_xfer); 585 1.1 nisimura 586 1.1 nisimura /* Wait until the transfer has completed, timeout is 587 1.1 nisimura 500ms */ 588 1.1 nisimura dma_error = s3c2440_dmac_wait_xfer(sc->sc_xfer, mstohz(SDI_DMA_WAIT_TIME)); 589 1.1 nisimura if (dma_error != 0) { 590 1.1 nisimura //s3c2440_dma_xfer_abort(sc->dma_xfer, mstohz(100)); /* XXX: Handle timeout during abort */ 591 1.1 nisimura cmd->c_error = dma_error; 592 1.1 nisimura DPRINTF(("DMA xfer failed: %d\n", dma_error)); 593 1.1 nisimura goto out; 594 1.1 nisimura } 595 1.1 nisimura } else { 596 1.1 nisimura DPRINTF(("PIO READ\n")); 597 1.1 nisimura sssdi_perform_pio_read(sc, cmd); 598 1.1 nisimura } 599 1.1 nisimura } else if (transfer == SSSDI_TRANSFER_WRITE) { 600 1.1 nisimura DPRINTF(("Waiting for WRITE transfer to complete\n")); 601 1.1 nisimura 602 1.1 nisimura if (sc->sc_xfer != NULL) { 603 1.1 nisimura int dma_error = 0; 604 1.1 nisimura s3c2440_dmac_start_xfer(sc->sc_xfer); 605 1.1 nisimura 606 1.1 nisimura dma_error = s3c2440_dmac_wait_xfer(sc->sc_xfer, mstohz(SDI_DMA_WAIT_TIME)); 607 1.1 nisimura if (dma_error != 0) { 608 1.1 nisimura //s3c2440_dma_xfer_abort(sc->dma_xfer, mstohz(100)); /* XXX: Handle timeout during abort*/ 609 1.1 nisimura cmd->c_error = dma_error; 610 1.1 nisimura DPRINTF(("DMA xfer failed: %d\n", dma_error)); 611 1.1 nisimura goto out; 612 1.1 nisimura } 613 1.1 nisimura } else { 614 1.1 nisimura DPRINTF(("PIO WRITE\n")); 615 1.1 nisimura sssdi_perform_pio_write(sc, cmd); 616 1.1 nisimura } 617 1.1 nisimura 618 1.1 nisimura if (cmd->c_error == ETIMEDOUT) 619 1.1 nisimura goto out; 620 1.1 nisimura 621 1.1 nisimura DPRINTF(("Waiting for transfer to complete\n")); 622 1.1 nisimura status = sssdi_wait_intr(sc, SDI_DATA_FIN | SDI_DATA_TIMEOUT, 1000); 623 1.1 nisimura if (status & SDI_CMD_TIMEOUT || status & SDI_DATA_TIMEOUT) { 624 1.1 nisimura cmd->c_error = ETIMEDOUT; 625 1.1 nisimura DPRINTF(("Timeout waiting for data to complete\n")); 626 1.1 nisimura goto out; 627 1.1 nisimura } 628 1.1 nisimura DPRINTF(("Done\n")); 629 1.1 nisimura 630 1.1 nisimura } 631 1.1 nisimura 632 1.1 nisimura 633 1.1 nisimura /* Response has been received, and any data transfer needed has been 634 1.1 nisimura performed */ 635 1.1 nisimura cmd->c_flags |= SCF_ITSDONE; 636 1.1 nisimura 637 1.1 nisimura out: 638 1.1 nisimura 639 1.1 nisimura #ifdef SSSDI_DEBUG 640 1.1 nisimura data_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_STA); 641 1.1 nisimura printf("SDI Data Status Register after execute: 0x%X\n", data_status); 642 1.1 nisimura #endif 643 1.1 nisimura 644 1.1 nisimura /* Clear status register. Their are cleared on the 645 1.1 nisimura next sssdi_exec_command */ 646 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_STA, 0xFFFFFFFF); 647 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_CON, 0x0); 648 1.1 nisimura } 649 1.1 nisimura 650 1.1 nisimura void sssdi_perform_pio_read(struct sssdi_softc *sc, struct sdmmc_command *cmd) 651 1.1 nisimura { 652 1.1 nisimura uint32_t fifo_status; 653 1.1 nisimura int count; 654 1.1 nisimura uint32_t written; 655 1.1 nisimura uint32_t *dest = (uint32_t*)cmd->c_data; 656 1.1 nisimura 657 1.1 nisimura written = 0; 658 1.1 nisimura 659 1.1 nisimura while (written < cmd->c_datalen ) { 660 1.1 nisimura /* Wait until the FIFO is full or has the final data. 661 1.1 nisimura In the latter case it might not get filled. */ 662 1.3 skrll sssdi_wait_intr(sc, SDI_FIFO_RX_FULL | SDI_FIFO_RX_LAST, 1000); 663 1.1 nisimura 664 1.1 nisimura fifo_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_FSTA); 665 1.1 nisimura count = SDIDATFSTA_FFCNT(fifo_status); 666 1.1 nisimura 667 1.1 nisimura for(int i=0; i<count; i+=4) { 668 1.1 nisimura uint32_t buf; 669 1.1 nisimura 670 1.1 nisimura buf = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_LI_W); 671 1.1 nisimura *dest = buf; 672 1.1 nisimura written += 4; 673 1.1 nisimura dest++; 674 1.1 nisimura } 675 1.1 nisimura } 676 1.1 nisimura } 677 1.1 nisimura 678 1.1 nisimura void 679 1.1 nisimura sssdi_perform_pio_write(struct sssdi_softc *sc, struct sdmmc_command *cmd) 680 1.1 nisimura { 681 1.1 nisimura uint32_t status; 682 1.1 nisimura uint32_t fifo_status; 683 1.1 nisimura int count; 684 1.1 nisimura uint32_t written; 685 1.1 nisimura uint32_t *dest = (uint32_t*)cmd->c_data; 686 1.1 nisimura 687 1.1 nisimura written = 0; 688 1.1 nisimura 689 1.1 nisimura while (written < cmd->c_datalen ) { 690 1.1 nisimura /* Wait until the FIFO is full or has the final data. 691 1.1 nisimura In the latter case it might not get filled. */ 692 1.1 nisimura DPRINTF(("Waiting for FIFO to become empty\n")); 693 1.1 nisimura status = sssdi_wait_intr(sc, SDI_FIFO_TX_EMPTY, 1000); 694 1.1 nisimura 695 1.1 nisimura fifo_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_FSTA); 696 1.1 nisimura DPRINTF(("PIO Write FIFO Status: 0x%X\n", fifo_status)); 697 1.1 nisimura count = 64-SDIDATFSTA_FFCNT(fifo_status); 698 1.1 nisimura 699 1.1 nisimura status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_CNT); 700 1.1 nisimura DPRINTF(("Remaining bytes of current block: %d\n", 701 1.1 nisimura SDIDATCNT_BLK_CNT(status))); 702 1.1 nisimura DPRINTF(("Remaining Block Number : %d\n", 703 1.1 nisimura SDIDATCNT_BLK_NUM_CNT(status))); 704 1.1 nisimura 705 1.1 nisimura 706 1.1 nisimura status = bus_space_read_4(sc->iot,sc->ioh, SDI_DAT_STA); 707 1.1 nisimura DPRINTF(("PIO Write Data Status: 0x%X\n", status)); 708 1.1 nisimura 709 1.1 nisimura if (status & SDIDATSTA_DATA_TIMEOUT) { 710 1.1 nisimura cmd->c_error = ETIMEDOUT; 711 1.1 nisimura /* Acknowledge the timeout*/ 712 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_STA, 713 1.1 nisimura SDIDATSTA_DATA_TIMEOUT); 714 1.1 nisimura printf("%s: Data timeout\n", device_xname(sc->dev)); 715 1.1 nisimura break; 716 1.1 nisimura } 717 1.1 nisimura 718 1.1 nisimura DPRINTF(("Filling FIFO with %d bytes\n", count)); 719 1.1 nisimura for(int i=0; i<count; i+=4) { 720 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_LI_W, *dest); 721 1.1 nisimura written += 4; 722 1.1 nisimura dest++; 723 1.1 nisimura } 724 1.1 nisimura } 725 1.1 nisimura } 726 1.1 nisimura 727 1.1 nisimura 728 1.1 nisimura void 729 1.1 nisimura sssdi_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) 730 1.1 nisimura { 731 1.1 nisimura printf("sssdi_card_enable_intr not implemented\n"); 732 1.1 nisimura } 733 1.1 nisimura 734 1.1 nisimura void 735 1.1 nisimura sssdi_card_intr_ack(sdmmc_chipset_handle_t sch) 736 1.1 nisimura { 737 1.1 nisimura printf("sssdi_card_intr_ack not implemented\n"); 738 1.1 nisimura } 739 1.1 nisimura 740 1.1 nisimura int 741 1.1 nisimura sssdi_intr(void *arg) 742 1.1 nisimura { 743 1.1 nisimura struct sssdi_softc *sc = (struct sssdi_softc*)arg; 744 1.1 nisimura uint32_t status; 745 1.1 nisimura uint32_t ack_status; 746 1.1 nisimura 747 1.1 nisimura /* Start by dealing with Command Status */ 748 1.1 nisimura ack_status = 0; 749 1.1 nisimura status = bus_space_read_4(sc->iot, sc->ioh, SDI_CMD_STA); 750 1.1 nisimura 751 1.1 nisimura if (status & SDICMDSTA_CMD_TIMEOUT) { 752 1.1 nisimura ack_status |= SDICMDSTA_CMD_TIMEOUT; 753 1.1 nisimura sc->intr_status |= SDI_CMD_TIMEOUT; 754 1.1 nisimura /*sssdi_disable_intr(sc, SDI_CMD_TIMEOUT);*/ 755 1.1 nisimura } 756 1.1 nisimura if (status & SDICMDSTA_CMD_SENT) { 757 1.1 nisimura ack_status |= SDICMDSTA_CMD_SENT; 758 1.1 nisimura sc->intr_status |= SDI_CMD_SENT; 759 1.1 nisimura /* sssdi_disable_intr(sc, SDI_CMD_SENT);*/ 760 1.1 nisimura } 761 1.1 nisimura if (status & SDICMDSTA_RSP_FIN) { 762 1.1 nisimura ack_status |= SDICMDSTA_RSP_FIN; 763 1.1 nisimura sc->intr_status |= SDI_RESP_FIN; 764 1.1 nisimura /* sssdi_disable_intr(sc, SDI_RESP_FIN);*/ 765 1.1 nisimura } 766 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_STA, ack_status); 767 1.1 nisimura 768 1.1 nisimura /* Next: FIFO Status */ 769 1.1 nisimura ack_status = 0; 770 1.1 nisimura status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_FSTA); 771 1.1 nisimura if (status & SDIDATFSTA_RF_FULL) { 772 1.1 nisimura ack_status |= SDIDATFSTA_RF_FULL; 773 1.1 nisimura sc->intr_status |= SDI_FIFO_RX_FULL; 774 1.1 nisimura sssdi_disable_intr(sc, SDI_FIFO_RX_FULL); 775 1.1 nisimura } 776 1.1 nisimura if (status & SDIDATFSTA_RF_LAST) { 777 1.1 nisimura ack_status |= SDIDATFSTA_RF_LAST | SDIDATFSTA_RESET; 778 1.1 nisimura sc->intr_status |= SDI_FIFO_RX_LAST; 779 1.1 nisimura sssdi_disable_intr(sc, SDI_FIFO_RX_LAST); 780 1.1 nisimura } 781 1.1 nisimura if (status & SDIDATFSTA_TF_EMPTY) { 782 1.1 nisimura ack_status |= SDIDATFSTA_TF_EMPTY; 783 1.1 nisimura sc->intr_status |= SDI_FIFO_TX_EMPTY; 784 1.1 nisimura sssdi_disable_intr(sc, SDI_FIFO_TX_EMPTY); 785 1.1 nisimura } 786 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_FSTA, ack_status); 787 1.1 nisimura 788 1.1 nisimura ack_status = 0; 789 1.1 nisimura status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_STA); 790 1.1 nisimura if (status & SDIDATSTA_DATA_FIN) { 791 1.1 nisimura DPRINTF(("sssdi_intr: DATA FINISHED\n")); 792 1.1 nisimura ack_status |= SDIDATSTA_DATA_FIN; 793 1.1 nisimura sc->intr_status |= SDI_DATA_FIN; 794 1.1 nisimura sssdi_disable_intr(sc, SDI_DATA_FIN); 795 1.1 nisimura } 796 1.1 nisimura if (status & SDIDATSTA_DATA_TIMEOUT) { 797 1.1 nisimura printf("sssdi_intr: DATA TIMEOUT\n"); 798 1.1 nisimura ack_status |= SDIDATSTA_DATA_TIMEOUT; 799 1.1 nisimura sc->intr_status |= SDI_DATA_TIMEOUT; 800 1.1 nisimura /* Data timeout interrupt is always enabled, thus 801 1.1 nisimura we do not disable it when we have received one. */ 802 1.1 nisimura /*sssdi_disable_intr(sc, SDI_DATA_TIMEOUT);*/ 803 1.1 nisimura 804 1.1 nisimura if (sc->sc_xfer != NULL) { 805 1.1 nisimura s3c2440_dmac_abort_xfer(sc->sc_xfer); 806 1.1 nisimura } 807 1.1 nisimura } 808 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_STA, ack_status); 809 1.1 nisimura 810 1.1 nisimura mutex_enter(&sc->intr_mtx); 811 1.1 nisimura cv_broadcast(&sc->intr_cv); 812 1.1 nisimura mutex_exit(&sc->intr_mtx); 813 1.1 nisimura 814 1.1 nisimura return 1; 815 1.1 nisimura } 816 1.1 nisimura 817 1.1 nisimura int 818 1.1 nisimura sssdi_intr_card(void *arg) 819 1.1 nisimura { 820 1.1 nisimura struct sssdi_softc *sc = (struct sssdi_softc*)arg; 821 1.1 nisimura 822 1.1 nisimura /* TODO: If card was removed then abort any current command */ 823 1.1 nisimura 824 1.1 nisimura sdmmc_needs_discover(sc->sdmmc); 825 1.1 nisimura 826 1.1 nisimura return 1; /* handled */ 827 1.1 nisimura } 828 1.1 nisimura 829 1.1 nisimura static void 830 1.1 nisimura sssdi_enable_intr(struct sssdi_softc *sc, uint32_t i) 831 1.1 nisimura { 832 1.1 nisimura uint32_t v = bus_space_read_4(sc->iot, sc->ioh, SDI_INT_MASK); 833 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_INT_MASK, v | i ); 834 1.1 nisimura } 835 1.1 nisimura 836 1.1 nisimura void 837 1.1 nisimura sssdi_disable_intr(struct sssdi_softc *sc, uint32_t i) 838 1.1 nisimura { 839 1.1 nisimura uint32_t v = bus_space_read_4(sc->iot, sc->ioh, SDI_INT_MASK); 840 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_INT_MASK, v & ~i ); 841 1.1 nisimura } 842 1.1 nisimura 843 1.1 nisimura void 844 1.1 nisimura sssdi_clear_intr(struct sssdi_softc *sc) 845 1.1 nisimura { 846 1.1 nisimura bus_space_write_4(sc->iot, sc->ioh, SDI_INT_MASK, 0x0); 847 1.1 nisimura } 848 1.1 nisimura 849 1.1 nisimura static int 850 1.1 nisimura sssdi_wait_intr(struct sssdi_softc *sc, uint32_t mask, int timeout) 851 1.1 nisimura { 852 1.1 nisimura uint32_t status; 853 1.1 nisimura 854 1.1 nisimura /* Wait until the command has been sent */ 855 1.1 nisimura mutex_enter(&sc->intr_mtx); 856 1.1 nisimura sssdi_enable_intr(sc, mask); 857 1.1 nisimura status = sc->intr_status & mask; 858 1.1 nisimura while(status == 0) { 859 1.1 nisimura 860 1.1 nisimura if (cv_timedwait(&sc->intr_cv, &sc->intr_mtx, timeout) == 861 1.1 nisimura EWOULDBLOCK ) { 862 1.1 nisimura DPRINTF(("Timed out waiting for interrupt from SDI controller\n")); 863 1.1 nisimura status |= SDI_CMD_TIMEOUT; 864 1.1 nisimura break; 865 1.1 nisimura } 866 1.1 nisimura 867 1.1 nisimura status = sc->intr_status & mask; 868 1.1 nisimura } 869 1.1 nisimura 870 1.1 nisimura sc->intr_status &= ~status; 871 1.1 nisimura mutex_exit(&sc->intr_mtx); 872 1.1 nisimura 873 1.1 nisimura return status; 874 1.1 nisimura } 875