1 /* $NetBSD: ssumci.c,v 1.6 2023/12/20 14:50:01 thorpej Exp $ */ 2 3 /*- 4 * Copyright (C) 2010 NONAKA Kimihiro <nonaka (at) netbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * driver to access MMC/SD card 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: ssumci.c,v 1.6 2023/12/20 14:50:01 thorpej Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/device.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/proc.h> 40 #include <sys/bus.h> 41 #include <sys/intr.h> 42 43 #include <sh3/devreg.h> 44 #include <sh3/pfcreg.h> 45 #include <sh3/scireg.h> 46 47 #include <dev/sdmmc/sdmmcvar.h> 48 #include <dev/sdmmc/sdmmcchip.h> 49 50 #include <machine/autoconf.h> 51 52 #include <evbsh3/t_sh7706lan/t_sh7706lanvar.h> 53 54 #ifdef SSUMCI_DEBUG 55 int ssumci_debug = 1; 56 #define DPRINTF(n,s) do { if ((n) <= ssumci_debug) printf s; } while (0) 57 #else 58 #define DPRINTF(n,s) do {} while (0) 59 #endif 60 61 static int ssumci_host_reset(sdmmc_chipset_handle_t); 62 static uint32_t ssumci_host_ocr(sdmmc_chipset_handle_t); 63 static int ssumci_host_maxblklen(sdmmc_chipset_handle_t); 64 static int ssumci_card_detect(sdmmc_chipset_handle_t); 65 static int ssumci_write_protect(sdmmc_chipset_handle_t); 66 static int ssumci_bus_power(sdmmc_chipset_handle_t, uint32_t); 67 static int ssumci_bus_clock(sdmmc_chipset_handle_t, int); 68 static int ssumci_bus_width(sdmmc_chipset_handle_t, int); 69 static void ssumci_exec_command(sdmmc_chipset_handle_t, 70 struct sdmmc_command *); 71 72 static struct sdmmc_chip_functions ssumci_chip_functions = { 73 /* host controller reset */ 74 .host_reset = ssumci_host_reset, 75 76 /* host controller capabilities */ 77 .host_ocr = ssumci_host_ocr, 78 .host_maxblklen = ssumci_host_maxblklen, 79 80 /* card detection */ 81 .card_detect = ssumci_card_detect, 82 83 /* write protect */ 84 .write_protect = ssumci_write_protect, 85 86 /* bus power, clock frequency, width */ 87 .bus_power = ssumci_bus_power, 88 .bus_clock = ssumci_bus_clock, 89 .bus_width = ssumci_bus_width, 90 91 /* command execution */ 92 .exec_command = ssumci_exec_command, 93 94 /* card interrupt */ 95 .card_enable_intr = NULL, 96 .card_intr_ack = NULL, 97 }; 98 99 static void ssumci_spi_initialize(sdmmc_chipset_handle_t); 100 101 static struct sdmmc_spi_chip_functions ssumci_spi_chip_functions = { 102 .initialize = ssumci_spi_initialize, 103 }; 104 105 #define CSR_SET_1(reg,set,mask) \ 106 do { \ 107 uint8_t _r; \ 108 _r = _reg_read_1((reg)); \ 109 _r &= ~(mask); \ 110 _r |= (set); \ 111 _reg_write_1((reg), _r); \ 112 } while (/*CONSTCOND*/0) 113 114 #define CSR_SET_2(reg,set,mask) \ 115 do { \ 116 uint16_t _r; \ 117 _r = _reg_read_2((reg)); \ 118 _r &= ~(mask); \ 119 _r |= (set); \ 120 _reg_write_2((reg), _r); \ 121 } while (/*CONSTCOND*/0) 122 123 #define CSR_CLR_1(reg,clr) \ 124 do { \ 125 uint8_t _r; \ 126 _r = _reg_read_1((reg)); \ 127 _r &= ~(clr); \ 128 _reg_write_1((reg), _r); \ 129 } while (/*CONSTCOND*/0) 130 131 #define CSR_CLR_2(reg,clr) \ 132 do { \ 133 uint16_t _r; \ 134 _r = _reg_read_2((reg)); \ 135 _r &= ~(clr); \ 136 _reg_write_2((reg), _r); \ 137 } while (/*CONSTCOND*/0) 138 139 #define SCPCR_CLK_MASK 0x000C 140 #define SCPCR_CLK_IN 0x000C 141 #define SCPCR_CLK_OUT 0x0004 142 #define SCPDR_CLK 0x02 143 #define SCPCR_DAT_MASK 0x0003 144 #define SCPCR_DAT_IN 0x0003 145 #define SCPCR_DAT_OUT 0x0001 146 #define SCPDR_DAT 0x01 147 #define SCPCR_CMD_MASK 0x0030 148 #define SCPCR_CMD_IN 0x0030 149 #define SCPCR_CMD_OUT 0x0010 150 #define SCPDR_CMD 0x04 151 #define SCPCR_CS_MASK 0x000C 152 #define SCPCR_CS_OUT 0x0004 153 #define SCPDR_CS 0x02 154 #define SCPCR_EJECT 0x00C0 155 #define SCPDR_EJECT 0x08 156 157 #define MMC_TIME_OVER 20000 158 159 struct ssumci_softc { 160 device_t sc_dev; 161 device_t sc_sdmmc; 162 }; 163 164 static int ssumci_match(device_t, cfdata_t, void *); 165 static void ssumci_attach(device_t, device_t, void *); 166 167 CFATTACH_DECL_NEW(ssumci, sizeof(struct ssumci_softc), 168 ssumci_match, ssumci_attach, NULL, NULL); 169 170 static void ssumci_cmd_cfgread(struct ssumci_softc *, struct sdmmc_command *); 171 static void ssumci_cmd_read(struct ssumci_softc *, struct sdmmc_command *); 172 static void ssumci_cmd_write(struct ssumci_softc *, struct sdmmc_command *); 173 174 #define SSUMCI_SPIDR 0xb0008000 175 #define SSUMCI_SPISR 0xb0008002 176 #define SSUMCI_SPIBR 0xb0008004 177 178 static inline void 179 ssumci_wait(void) 180 { 181 182 while (_reg_read_1(SSUMCI_SPISR) == 0x00) 183 continue; 184 } 185 186 static inline uint8_t 187 ssumci_getc(void) 188 { 189 190 ssumci_wait(); 191 return _reg_read_1(SSUMCI_SPIBR); 192 } 193 194 static inline void 195 ssumci_putc(uint8_t v) 196 { 197 198 _reg_write_1(SSUMCI_SPIDR, v); 199 ssumci_wait(); 200 } 201 202 /*ARGSUSED*/ 203 static int 204 ssumci_match(device_t parent, cfdata_t cf, void *aux) 205 { 206 struct mainbus_attach_args *maa = (struct mainbus_attach_args *)aux; 207 208 if (strcmp(maa->ma_name, "ssumci") != 0) 209 return 0; 210 if (!IS_SH7706LSR) 211 return 0; 212 return 1; 213 } 214 215 /*ARGSUSED*/ 216 static void 217 ssumci_attach(device_t parent, device_t self, void *aux) 218 { 219 struct ssumci_softc *sc = device_private(self); 220 struct sdmmcbus_attach_args saa; 221 222 sc->sc_dev = self; 223 224 aprint_naive("\n"); 225 aprint_normal(": SPI MMC controller\n"); 226 227 /* setup */ 228 CSR_SET_2(SH7709_SCPCR, SCPCR_CS_OUT, SCPCR_CS_MASK); 229 230 /* 231 * Attach the generic SD/MMC bus driver. (The bus driver must 232 * not invoke any chipset functions before it is attached.) 233 */ 234 memset(&saa, 0, sizeof(saa)); 235 saa.saa_busname = "sdmmc"; 236 saa.saa_sct = &ssumci_chip_functions; 237 saa.saa_spi_sct = &ssumci_spi_chip_functions; 238 saa.saa_sch = sc; 239 saa.saa_clkmin = 400; 240 saa.saa_clkmax = 400; 241 saa.saa_caps = SMC_CAPS_SPI_MODE 242 | SMC_CAPS_SINGLE_ONLY 243 | SMC_CAPS_POLL_CARD_DET; 244 245 sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL, CFARGS_NONE); 246 if (sc->sc_sdmmc == NULL) 247 aprint_error_dev(sc->sc_dev, "couldn't attach bus\n"); 248 } 249 250 /* 251 * Reset the host controller. Called during initialization, when 252 * cards are removed, upon resume, and during error recovery. 253 */ 254 /*ARGSUSED*/ 255 static int 256 ssumci_host_reset(sdmmc_chipset_handle_t sch) 257 { 258 259 return 0; 260 } 261 262 /*ARGSUSED*/ 263 static uint32_t 264 ssumci_host_ocr(sdmmc_chipset_handle_t sch) 265 { 266 267 return MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V; 268 } 269 270 /*ARGSUSED*/ 271 static int 272 ssumci_host_maxblklen(sdmmc_chipset_handle_t sch) 273 { 274 275 return 512; 276 } 277 278 /*ARGSUSED*/ 279 static int 280 ssumci_card_detect(sdmmc_chipset_handle_t sch) 281 { 282 uint8_t reg; 283 int s; 284 285 s = splsdmmc(); 286 CSR_SET_2(SH7709_SCPCR, SCPCR_EJECT, 0); 287 reg = _reg_read_1(SH7709_SCPDR); 288 splx(s); 289 290 return !(reg & SCPDR_EJECT); 291 } 292 293 /*ARGSUSED*/ 294 static int 295 ssumci_write_protect(sdmmc_chipset_handle_t sch) 296 { 297 298 return 0; /* non-protect */ 299 } 300 301 /* 302 * Set or change SD bus voltage and enable or disable SD bus power. 303 * Return zero on success. 304 */ 305 /*ARGSUSED*/ 306 static int 307 ssumci_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 308 { 309 310 if ((ocr & (MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) == 0) 311 return 1; 312 313 /*XXX???*/ 314 return 0; 315 } 316 317 /* 318 * Set or change MMCLK frequency or disable the MMC clock. 319 * Return zero on success. 320 */ 321 /*ARGSUSED*/ 322 static int 323 ssumci_bus_clock(sdmmc_chipset_handle_t sch, int freq) 324 { 325 326 return 0; 327 } 328 329 /*ARGSUSED*/ 330 static int 331 ssumci_bus_width(sdmmc_chipset_handle_t sch, int width) 332 { 333 334 if (width != 1) 335 return 1; 336 return 0; 337 } 338 339 /*ARGSUSED*/ 340 static void 341 ssumci_spi_initialize(sdmmc_chipset_handle_t sch) 342 { 343 int i, s; 344 345 s = splsdmmc(); 346 CSR_SET_1(SH7709_SCPDR, SCPDR_CS, 0); 347 for (i = 0; i < 10; i++) { 348 ssumci_putc(0xff); 349 } 350 CSR_CLR_1(SH7709_SCPDR, SCPDR_CS); 351 splx(s); 352 } 353 354 static void 355 ssumci_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 356 { 357 struct ssumci_softc *sc = (struct ssumci_softc *)sch; 358 uint16_t resp; 359 int timo; 360 int s; 361 362 DPRINTF(1,("%s: start cmd %d arg=%#x data=%p dlen=%d flags=%#x\n", 363 device_xname(sc->sc_dev), cmd->c_opcode, cmd->c_arg, cmd->c_data, 364 cmd->c_datalen, cmd->c_flags)); 365 366 s = splsdmmc(); 367 368 ssumci_putc(0xff); 369 ssumci_putc(0x40 | (cmd->c_opcode & 0x3f)); 370 ssumci_putc((cmd->c_arg >> 24) & 0xff); 371 ssumci_putc((cmd->c_arg >> 16) & 0xff); 372 ssumci_putc((cmd->c_arg >> 8) & 0xff); 373 ssumci_putc((cmd->c_arg >> 0) & 0xff); 374 ssumci_putc((cmd->c_opcode == MMC_GO_IDLE_STATE) ? 0x95 : 375 (cmd->c_opcode == SD_SEND_IF_COND) ? 0x87 : 0); /* CRC */ 376 377 for (timo = MMC_TIME_OVER; timo > 0; timo--) { 378 resp = ssumci_getc(); 379 if (!(resp & 0x80) && timo <= (MMC_TIME_OVER - 2)) 380 break; 381 } 382 if (timo == 0) { 383 DPRINTF(1,(sc->sc_dev, "response timeout\n")); 384 cmd->c_error = ETIMEDOUT; 385 goto out; 386 } 387 388 if (ISSET(cmd->c_flags, SCF_RSP_SPI_S2)) { 389 resp |= (uint16_t) ssumci_getc() << 8; 390 } else if (ISSET(cmd->c_flags, SCF_RSP_SPI_B4)) { 391 cmd->c_resp[1] = (uint32_t) ssumci_getc() << 24; 392 cmd->c_resp[1] |= (uint32_t) ssumci_getc() << 16; 393 cmd->c_resp[1] |= (uint32_t) ssumci_getc() << 8; 394 cmd->c_resp[1] |= (uint32_t) ssumci_getc(); 395 DPRINTF(1, ("R3 resp: %#x\n", cmd->c_resp[1])); 396 } 397 cmd->c_resp[0] = resp; 398 if (resp != 0 && resp != R1_SPI_IDLE) { 399 DPRINTF(1,("response error: %#x\n", resp)); 400 cmd->c_error = EIO; 401 goto out; 402 } 403 DPRINTF(1, ("R1 resp: %#x\n", resp)); 404 405 if (cmd->c_datalen > 0) { 406 if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 407 /* XXX: swap in this place? */ 408 if (cmd->c_opcode == MMC_SEND_CID || 409 cmd->c_opcode == MMC_SEND_CSD) { 410 sdmmc_response res; 411 uint32_t *p = cmd->c_data; 412 413 ssumci_cmd_cfgread(sc, cmd); 414 res[0] = be32toh(p[3]); 415 res[1] = be32toh(p[2]); 416 res[2] = be32toh(p[1]); 417 res[3] = be32toh(p[0]); 418 memcpy(p, &res, sizeof(res)); 419 } else { 420 ssumci_cmd_read(sc, cmd); 421 } 422 } else { 423 ssumci_cmd_write(sc, cmd); 424 } 425 } else { 426 ssumci_wait(); 427 } 428 429 out: 430 SET(cmd->c_flags, SCF_ITSDONE); 431 splx(s); 432 433 DPRINTF(1,("%s: cmd %d done (flags=%#x error=%d)\n", 434 device_xname(sc->sc_dev), cmd->c_opcode, cmd->c_flags, cmd->c_error)); 435 } 436 437 static void 438 ssumci_cmd_cfgread(struct ssumci_softc *sc, struct sdmmc_command *cmd) 439 { 440 u_char *data = cmd->c_data; 441 int timo; 442 int c; 443 int i; 444 445 /* wait data token */ 446 for (timo = MMC_TIME_OVER; timo > 0; timo--) { 447 c = ssumci_getc(); 448 if (c != 0xff) 449 break; 450 } 451 if (timo == 0) { 452 aprint_error_dev(sc->sc_dev, "cfg read timeout\n"); 453 cmd->c_error = ETIMEDOUT; 454 return; 455 } 456 if (c != 0xfe) { 457 aprint_error_dev(sc->sc_dev, "cfg read error (data=%#x)\n", c); 458 cmd->c_error = EIO; 459 return; 460 } 461 462 /* data read */ 463 data[0] = '\0'; /* XXXFIXME!!! */ 464 for (i = 1 /* XXXFIXME!!!*/ ; i < cmd->c_datalen; i++) { 465 data[i] = ssumci_getc(); 466 } 467 468 (void) ssumci_getc(); 469 (void) ssumci_getc(); 470 ssumci_wait(); 471 472 #ifdef SSUMCI_DEBUG 473 sdmmc_dump_data(NULL, cmd->c_data, cmd->c_datalen); 474 #endif 475 } 476 477 static void 478 ssumci_cmd_read(struct ssumci_softc *sc, struct sdmmc_command *cmd) 479 { 480 u_char *data = cmd->c_data; 481 int timo; 482 int c; 483 int i; 484 485 /* wait data token */ 486 for (timo = MMC_TIME_OVER; timo > 0; timo--) { 487 c = ssumci_getc(); 488 if (c != 0xff) 489 break; 490 } 491 if (timo == 0) { 492 aprint_error_dev(sc->sc_dev, "read timeout\n"); 493 cmd->c_error = ETIMEDOUT; 494 return; 495 } 496 if (c != 0xfe) { 497 aprint_error_dev(sc->sc_dev, "read error (data=%#x)\n", c); 498 cmd->c_error = EIO; 499 return; 500 } 501 502 /* data read */ 503 for (i = 0; i < cmd->c_datalen; i++) { 504 data[i] = ssumci_getc(); 505 } 506 507 /* ignore CRC */ 508 (void) ssumci_getc(); 509 (void) ssumci_getc(); 510 ssumci_wait(); 511 512 #ifdef SSUMCI_DEBUG 513 sdmmc_dump_data(NULL, cmd->c_data, cmd->c_datalen); 514 #endif 515 } 516 517 static void 518 ssumci_cmd_write(struct ssumci_softc *sc, struct sdmmc_command *cmd) 519 { 520 u_char *data = cmd->c_data; 521 int timo; 522 int c; 523 int i; 524 525 ssumci_wait(); 526 ssumci_putc(0xfe); 527 528 /* data write */ 529 for (i = 0; i < cmd->c_datalen; i++) { 530 ssumci_putc(data[i]); 531 } 532 533 /* dummy CRC */ 534 ssumci_putc(0); 535 ssumci_putc(0); 536 ssumci_putc(0xff); 537 if ((_reg_read_1(SSUMCI_SPIDR) & 0x0f) != 5) { 538 aprint_error_dev(sc->sc_dev, "write error\n"); 539 cmd->c_error = EIO; 540 return; 541 } 542 543 for (timo = 0x7fffffff; timo > 0; timo--) { 544 ssumci_putc(0xff); 545 c = _reg_read_1(SSUMCI_SPIDR); 546 if (c == 0xff) 547 break; 548 } 549 if (timo == 0) { 550 aprint_error_dev(sc->sc_dev, "write timeout\n"); 551 cmd->c_error = ETIMEDOUT; 552 } 553 } 554