1 /*- 2 * Copyright (c) 2012 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Paul Fleischer <paul (at) xpg.dk> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 #include "s3csdi.h" 30 31 #include <arm/s3c2xx0/s3c2440reg.h> 32 33 #include <lib/libsa/stand.h> 34 35 #include <machine/int_mwgwtypes.h> 36 #include <machine/limits.h> 37 38 #include <dev/sdmmc/sdmmcreg.h> 39 40 #define SDI_REG(reg) (*(volatile uint32_t*)(S3C2440_SDI_BASE+reg)) 41 42 //#define SSSDI_DEBUG 43 #ifdef SSSDI_DEBUG 44 #define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) 45 #else 46 #define DPRINTF(s) do {} while (/*CONSTCOND*/0) 47 #endif 48 49 struct s3csdi_softc { 50 int width; 51 }; 52 53 extern int pclk; 54 55 static void sssdi_perform_pio_read(struct sdmmc_command *cmd); 56 //static void sssdi_perform_pio_write(struct sdmmc_command *cmd); 57 58 static struct s3csdi_softc s3csdi_softc; 59 60 int 61 s3csd_match(unsigned int tag) 62 { 63 printf("Found S3C2440 SD/MMC\n"); 64 return 1; 65 } 66 67 void* 68 s3csd_init(unsigned int tag, uint32_t *caps) 69 { 70 uint32_t data; 71 72 *caps = SMC_CAPS_4BIT_MODE; 73 74 DPRINTF(("CLKCON: 0x%X\n", *(volatile uint32_t*)(S3C2440_CLKMAN_BASE + CLKMAN_CLKCON))); 75 76 DPRINTF(("SDI_INT_MASK: 0x%X\n", SDI_REG(SDI_INT_MASK))); 77 78 SDI_REG(SDI_INT_MASK) = 0x0; 79 SDI_REG(SDI_DTIMER) = 0x007FFFFF; 80 81 SDI_REG(SDI_CON) &= ~SDICON_ENCLK; 82 83 SDI_REG(SDI_CON) = SDICON_SD_RESET | SDICON_CTYP_SD; 84 85 /* Set GPG8 to input such that we can check if there is a card present 86 */ 87 data = *(volatile uint32_t*)(S3C2440_GPIO_BASE+GPIO_PGCON); 88 data = GPIO_SET_FUNC(data, 8, 0x00); 89 *(volatile uint32_t*)(S3C2440_GPIO_BASE+GPIO_PGCON) = data; 90 91 /* Check if a card is present */ 92 data = *(volatile uint32_t*)(S3C2440_GPIO_BASE+GPIO_PGDAT); 93 if ( (data & (1<<8)) == (1<<8)) { 94 printf("No card detected\n"); 95 /* Pin 8 is low when no card is inserted */ 96 return 0; 97 } 98 printf("Card detected\n"); 99 100 s3csdi_softc.width = 1; 101 102 /* We have no private data to return, but 0 signals error */ 103 return (void*)0x01; 104 } 105 106 int 107 s3csd_bus_clock(void *priv, int freq) 108 { 109 int div; 110 int clock_set = 0; 111 int control; 112 int clk = pclk/1000; /*Peripheral bus clock in KHz*/ 113 114 /* Round peripheral bus clock down to nearest MHz */ 115 clk = (clk / 1000) * 1000; 116 117 control = SDI_REG(SDI_CON); 118 SDI_REG(SDI_CON) = control & ~SDICON_ENCLK; 119 120 121 /* If the frequency is zero just keep the clock disabled */ 122 if (freq == 0) 123 return 0; 124 125 for (div = 1; div <= 256; div++) { 126 if ( clk / div <= freq) { 127 DPRINTF(("Using divisor %d: %d/%d = %d\n", div, clk, 128 div, clk/div)); 129 clock_set = 1; 130 SDI_REG(SDI_PRE) = div-1; 131 break; 132 } 133 } 134 135 if (clock_set) { 136 SDI_REG(SDI_CON) = control | SDICON_ENCLK; 137 if (div-1 != SDI_REG(SDI_PRE)) { 138 return 1; 139 } 140 141 sdmmc_delay(74000/freq); 142 /* Wait for 74 SDCLK */ 143 /* 1/freq is the length of a clock cycle, 144 so we have to wait 1/freq * 74 . 145 74000 / freq should express the delay in us. 146 */ 147 return 0; 148 } else { 149 return 1; 150 } 151 } 152 153 #define SSSDI_TRANSFER_NONE 0 154 #define SSSDI_TRANSFER_READ 1 155 #define SSSDI_TRANSFER_WRITE 2 156 157 void 158 s3csd_exec_cmd(void *priv, struct sdmmc_command *cmd) 159 { 160 uint32_t cmd_control; 161 int status = 0; 162 uint32_t data_status; 163 int transfer = SSSDI_TRANSFER_NONE; 164 165 DPRINTF(("s3csd_exec_cmd\n")); 166 167 SDI_REG(SDI_DAT_FSTA) = 0xFFFFFFFF; 168 SDI_REG(SDI_DAT_STA) = 0xFFFFFFFF; 169 SDI_REG(SDI_CMD_STA) = 0xFFFFFFFF; 170 171 SDI_REG(SDI_CMD_ARG) = cmd->c_arg; 172 173 cmd_control = (cmd->c_opcode & SDICMDCON_CMD_MASK) | 174 SDICMDCON_HOST_CMD | SDICMDCON_CMST; 175 if (cmd->c_flags & SCF_RSP_PRESENT) 176 cmd_control |= SDICMDCON_WAIT_RSP; 177 if (cmd->c_flags & SCF_RSP_136) 178 cmd_control |= SDICMDCON_LONG_RSP; 179 180 if (cmd->c_datalen > 0 && cmd->c_data != NULL) { 181 /* TODO: Ensure that the above condition matches the semantics 182 of SDICMDCON_WITH_DATA*/ 183 DPRINTF(("DATA, datalen: %d, blk_size: %d, offset: %d\n", cmd->c_datalen, 184 cmd->c_blklen, cmd->c_arg)); 185 cmd_control |= SDICMDCON_WITH_DATA; 186 } 187 188 if (cmd->c_opcode == MMC_STOP_TRANSMISSION) { 189 cmd_control |= SDICMDCON_ABORT_CMD; 190 } 191 192 SDI_REG(SDI_DTIMER) = 0x007FFFFF; 193 SDI_REG(SDI_BSIZE) = cmd->c_blklen; 194 195 if ( (cmd->c_flags & SCF_CMD_READ) && 196 (cmd_control & SDICMDCON_WITH_DATA)) { 197 uint32_t data_control; 198 DPRINTF(("Reading %d bytes\n", cmd->c_datalen)); 199 transfer = SSSDI_TRANSFER_READ; 200 201 data_control = SDIDATCON_DATMODE_RECEIVE | SDIDATCON_RACMD | 202 SDIDATCON_DTST | SDIDATCON_BLKMODE | 203 ((cmd->c_datalen / cmd->c_blklen) & SDIDATCON_BLKNUM_MASK) | 204 SDIDATCON_DATA_WORD; 205 206 207 if (s3csdi_softc.width == 4) { 208 data_control |= SDIDATCON_WIDEBUS; 209 } 210 211 SDI_REG(SDI_DAT_CON) = data_control; 212 } else if (cmd_control & SDICMDCON_WITH_DATA) { 213 /* Write data */ 214 215 uint32_t data_control; 216 DPRINTF(("Writing %d bytes\n", cmd->c_datalen)); 217 DPRINTF(("Requesting %d blocks\n", 218 cmd->c_datalen / cmd->c_blklen)); 219 transfer = SSSDI_TRANSFER_WRITE; 220 data_control = SDIDATCON_DATMODE_TRANSMIT | SDIDATCON_BLKMODE | 221 SDIDATCON_TARSP | SDIDATCON_DTST | 222 ((cmd->c_datalen / cmd->c_blklen) & SDIDATCON_BLKNUM_MASK) | 223 SDIDATCON_DATA_WORD; 224 225 /* if (sc->width == 4) { 226 data_control |= SDIDATCON_WIDEBUS; 227 }*/ 228 229 SDI_REG(SDI_DAT_CON) = data_control; 230 } 231 232 DPRINTF(("SID_CMD_CON: 0x%X\n", cmd_control)); 233 /* Send command to SDI */ 234 SDI_REG(SDI_CMD_CON) = cmd_control; 235 DPRINTF(("Status before cmd sent: 0x%X\n", SDI_REG(SDI_CMD_STA))); 236 DPRINTF(("Waiting for command being sent\n")); 237 while( !(SDI_REG(SDI_CMD_STA) & SDICMDSTA_CMD_SENT)); 238 DPRINTF(("Command has been sent\n")); 239 240 //SDI_REG(SDI_CMD_STA) |= SDICMDSTA_CMD_SENT; 241 242 if (!(cmd_control & SDICMDCON_WAIT_RSP)) { 243 SDI_REG(SDI_CMD_STA) |= SDICMDSTA_CMD_SENT; 244 cmd->c_flags |= SCF_ITSDONE; 245 goto out; 246 } 247 248 DPRINTF(("waiting for response\n")); 249 while(1) { 250 status = SDI_REG(SDI_CMD_STA); 251 if (status & SDICMDSTA_RSP_FIN) { 252 break; 253 } 254 if (status & SDICMDSTA_CMD_TIMEOUT) { 255 break; 256 } 257 } 258 259 DPRINTF(("Status: 0x%X\n", status)); 260 if (status & SDICMDSTA_CMD_TIMEOUT) { 261 cmd->c_error = ETIMEDOUT; 262 DPRINTF(("Timeout waiting for response\n")); 263 goto out; 264 } 265 DPRINTF(("Got Response\n")); 266 267 if (cmd->c_flags & SCF_RSP_136 ) { 268 uint32_t w[4]; 269 270 /* We store the response least significant word first */ 271 w[0] = SDI_REG(SDI_RSP3); 272 w[1] = SDI_REG(SDI_RSP2); 273 w[2] = SDI_REG(SDI_RSP1); 274 w[3] = SDI_REG(SDI_RSP0); 275 276 /* The sdmmc subsystem expects that the response is delivered 277 without the lower 8 bits (CRC + '1' bit) */ 278 cmd->c_resp[0] = (w[0] >> 8) | ((w[1] & 0xFF) << 24); 279 cmd->c_resp[1] = (w[1] >> 8) | ((w[2] & 0XFF) << 24); 280 cmd->c_resp[2] = (w[2] >> 8) | ((w[3] & 0XFF) << 24); 281 cmd->c_resp[3] = (w[3] >> 8); 282 283 } else { 284 cmd->c_resp[0] = SDI_REG(SDI_RSP0); 285 cmd->c_resp[1] = SDI_REG(SDI_RSP1); 286 } 287 288 DPRINTF(("Response: %X %X %X %X\n", 289 cmd->c_resp[0], 290 cmd->c_resp[1], 291 cmd->c_resp[2], 292 cmd->c_resp[3])); 293 294 status = SDI_REG(SDI_DAT_CNT); 295 296 DPRINTF(("Remaining bytes of current block: %d\n", 297 SDIDATCNT_BLK_CNT(status))); 298 DPRINTF(("Remaining Block Number : %d\n", 299 SDIDATCNT_BLK_NUM_CNT(status))); 300 301 data_status = SDI_REG(SDI_DAT_STA); 302 303 DPRINTF(("SDI Data Status Register Before xfer: 0x%X\n", data_status)); 304 305 if (data_status & SDIDATSTA_DATA_TIMEOUT) { 306 cmd->c_error = ETIMEDOUT; 307 DPRINTF(("Timeout waiting for data\n")); 308 goto out; 309 } 310 311 312 if (transfer == SSSDI_TRANSFER_READ) { 313 DPRINTF(("Waiting for transfer to complete\n")); 314 315 sssdi_perform_pio_read(cmd); 316 } else if (transfer == SSSDI_TRANSFER_WRITE) { 317 318 /* DPRINTF(("PIO WRITE\n")); 319 sssdi_perform_pio_write(sc, cmd); 320 321 if (cmd->c_error == ETIMEDOUT) 322 goto out;*/ 323 } 324 325 326 /* Response has been received, and any data transfer needed has been 327 performed */ 328 cmd->c_flags |= SCF_ITSDONE; 329 330 out: 331 332 data_status = SDI_REG(SDI_DAT_STA); 333 DPRINTF(("SDI Data Status Register after execute: 0x%X\n", data_status)); 334 335 /* Clear status register. Their are cleared on the 336 next sssdi_exec_command */ 337 SDI_REG(SDI_CMD_STA) = 0xFFFFFFFF; 338 SDI_REG(SDI_DAT_CON) = 0x0; 339 } 340 341 void 342 sssdi_perform_pio_read(struct sdmmc_command *cmd) 343 { 344 uint32_t status; 345 uint32_t fifo_status; 346 int count; 347 uint32_t written; 348 uint8_t *dest = (uint8_t*)cmd->c_data; 349 int i; 350 351 written = 0; 352 353 while (written < cmd->c_datalen ) { 354 /* Wait until the FIFO is full or has the final data. 355 In the latter case it might not get filled. */ 356 //status = sssdi_wait_intr(sc, SDI_FIFO_RX_FULL | SDI_FIFO_RX_LAST, 1000); 357 //printf("Waiting for FIFO (got %d / %d)\n", written, cmd->c_datalen); 358 do { 359 status = SDI_REG(SDI_DAT_FSTA); 360 } while( !(status & SDIDATFSTA_RF_FULL) && !(status & SDIDATFSTA_RF_LAST)); 361 //printf("Done\n"); 362 363 fifo_status = SDI_REG(SDI_DAT_FSTA); 364 count = SDIDATFSTA_FFCNT(fifo_status); 365 366 //printf("Writing %d bytes to %p\n", count, dest); 367 for(i=0; i<count; i+=4) { 368 uint32_t buf; 369 370 buf = SDI_REG(SDI_DAT_LI_W); 371 *dest = (buf & 0xFF); dest++; 372 *dest = (buf >> 8) & 0xFF; dest++; 373 *dest = (buf >> 16) & 0xFF; dest++; 374 *dest = (buf >> 24) & 0xFF; dest++; 375 written += 4; 376 } 377 } 378 } 379 380 #if 0 381 void 382 sssdi_perform_pio_write(struct sdmmc_command *cmd) 383 { 384 uint32_t status; 385 uint32_t fifo_status; 386 int count; 387 uint32_t written; 388 uint32_t *dest = (uint32_t*)cmd->c_data; 389 390 written = 0; 391 392 while (written < cmd->c_datalen ) { 393 /* Wait until the FIFO is full or has the final data. 394 In the latter case it might not get filled. */ 395 DPRINTF(("Waiting for FIFO to become empty\n")); 396 status = sssdi_wait_intr(sc, SDI_FIFO_TX_EMPTY, 1000); 397 398 fifo_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_FSTA); 399 DPRINTF(("PIO Write FIFO Status: 0x%X\n", fifo_status)); 400 count = 64-SDIDATFSTA_FFCNT(fifo_status); 401 402 status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_CNT); 403 DPRINTF(("Remaining bytes of current block: %d\n", 404 SDIDATCNT_BLK_CNT(status))); 405 DPRINTF(("Remaining Block Number : %d\n", 406 SDIDATCNT_BLK_NUM_CNT(status))); 407 408 409 status = bus_space_read_4(sc->iot,sc->ioh, SDI_DAT_STA); 410 DPRINTF(("PIO Write Data Status: 0x%X\n", status)); 411 412 if (status & SDIDATSTA_DATA_TIMEOUT) { 413 cmd->c_error = ETIMEDOUT; 414 /* Acknowledge the timeout*/ 415 bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_STA, 416 SDIDATSTA_DATA_TIMEOUT); 417 printf("%s: Data timeout\n", device_xname(sc->dev)); 418 break; 419 } 420 421 DPRINTF(("Filling FIFO with %d bytes\n", count)); 422 for(int i=0; i<count; i+=4) { 423 bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_LI_W, *dest); 424 written += 4; 425 dest++; 426 } 427 } 428 } 429 #endif 430 431 int 432 s3csd_host_ocr(void *priv) 433 { 434 return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 435 } 436 437 int 438 s3csd_bus_power(void *priv, int ocr) 439 { 440 return 0; 441 } 442 443 int 444 s3csd_bus_width(void *priv, int width) 445 { 446 s3csdi_softc.width = width; 447 return 0; 448 } 449 450 int 451 s3csd_get_max_bus_clock(void *priv) 452 { 453 return pclk / 1; 454 } 455