Lines Matching +full:mmc +full:- +full:slot
1 /*-
2 * Copyright (c) 2012-2025 Patrick Kelsey. All rights reserved.
33 * Group. This Simplified Specification is provided on a non-confidential
36 * Association, SD Group, SD-3C LLC or other third parties.
42 * is provided "AS-IS" without any representations or warranties of any
43 * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
45 * right of the SD Group, SD-3C LLC, the SD Card Association or any third
48 * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
49 * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
51 * information, know-how or other confidential information to any third party.
57 * This is an implementation of mmcbr that communicates with SD/MMC cards in
59 * MMC/SD stack (and allow for maximal reuse of the same), the behavior of
60 * the SD-bus command set is emulated as much as possible, where required.
63 * duration that the MMC host is acquired.
66 * per-card via sysctl (e.g. sysctl dev.mmcspi.0.use_crc=0).
69 * - Card presence detection
70 * - Card power control
71 * - Detection of lock switch state on cards that have them
72 * - Yielding the CPU during long card busy cycles
89 #include <dev/mmc/bridge.h>
90 #include <dev/mmc/mmcreg.h>
91 #include <dev/mmc/mmcbrvar.h>
154 { "mmc-spi-slot", 1 },
159 struct mmc_command *mmc_cmd; /* command passed from mmc layer */
174 unsigned char mmc_rsp_type; /* MMC reponse type to translate to */
187 device_t dev; /* mmc device for slot */
190 struct mtx mtx; /* slot mutex */
192 uint32_t last_opcode; /* last opcode requested by mmc layer */
193 uint32_t last_flags; /* last flags requested by mmc layer */
202 device_t dev; /* this mmc bridge device */
204 struct mmcspi_slot slot; member
214 #define MMCSPI_LOCK_SLOT(_slot) mtx_lock(&(_slot)->mtx)
215 #define MMCSPI_UNLOCK_SLOT(_slot) mtx_unlock(&(_slot)->mtx)
216 #define MMCSPI_SLOT_LOCK_INIT(_slot) mtx_init(&(_slot)->mtx, \
217 "SD slot mtx", "mmcspi", MTX_DEF)
218 #define MMCSPI_SLOT_LOCK_DESTROY(_slot) mtx_destroy(&(_slot)->mtx);
219 #define MMCSPI_ASSERT_SLOT_LOCKED(_slot) mtx_assert(&(_slot)->mtx, \
221 #define MMCSPI_ASSERT_SLOT_UNLOCKED(_slot) mtx_assert(&(_slot)->mtx, \
346 mmcspi_slot_init(device_t brdev, struct mmcspi_slot *slot) in mmcspi_slot_init() argument
354 slot->sc = sc; in mmcspi_slot_init()
355 slot->dev = NULL; /* will get real value when card is added */ in mmcspi_slot_init()
356 slot->bus_busy = false; in mmcspi_slot_init()
357 slot->host.f_min = 100000; /* this should be as low as we need to go in mmcspi_slot_init()
359 slot->host.caps = 0; in mmcspi_slot_init()
361 slot->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; in mmcspi_slot_init()
363 MMCSPI_SLOT_LOCK_INIT(slot); in mmcspi_slot_init()
369 mmcspi_slot_fini(device_t brdev, struct mmcspi_slot *slot) in mmcspi_slot_fini() argument
373 MMCSPI_SLOT_LOCK_DESTROY(slot); in mmcspi_slot_fini()
379 mmcspi_card_add(struct mmcspi_slot *slot) in mmcspi_card_add() argument
384 brdev = slot->sc->dev; in mmcspi_card_add()
388 child = device_add_child(brdev, "mmc", DEVICE_UNIT_ANY); in mmcspi_card_add()
390 MMCSPI_LOCK_SLOT(slot); in mmcspi_card_add()
391 slot->dev = child; in mmcspi_card_add()
392 device_set_ivars(slot->dev, slot); in mmcspi_card_add()
393 MMCSPI_UNLOCK_SLOT(slot); in mmcspi_card_add()
395 device_probe_and_attach(slot->dev); in mmcspi_card_add()
401 mmcspi_card_delete(struct mmcspi_slot *slot) in mmcspi_card_delete() argument
406 brdev = slot->sc->dev; in mmcspi_card_delete()
410 MMCSPI_LOCK_SLOT(slot); in mmcspi_card_delete()
411 dev = slot->dev; in mmcspi_card_delete()
412 slot->dev = NULL; in mmcspi_card_delete()
413 MMCSPI_UNLOCK_SLOT(slot); in mmcspi_card_delete()
426 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) in mmcspi_probe()
429 device_set_desc(dev, "MMC SPI mode controller"); in mmcspi_probe()
449 sc->dev = dev; in mmcspi_attach()
450 sc->busdev = device_get_parent(dev); in mmcspi_attach()
451 sc->use_crc = 1; in mmcspi_attach()
454 &sc->use_crc, sizeof(sc->use_crc), "Enable/disable crc checking"); in mmcspi_attach()
460 mmcspi_slot_init(dev, &sc->slot); in mmcspi_attach()
463 mmcspi_card_add(&sc->slot); in mmcspi_attach()
480 mmcspi_card_delete(&sc->slot); in mmcspi_detach()
482 mmcspi_slot_fini(dev, &sc->slot); in mmcspi_detach()
524 struct mmcspi_slot *slot; in mmcspi_read_ivar() local
528 slot = device_get_ivars(child); in mmcspi_read_ivar()
535 *result = slot->host.ios.bus_mode; in mmcspi_read_ivar()
538 *result = slot->host.ios.bus_width; in mmcspi_read_ivar()
541 *result = slot->host.ios.chip_select; in mmcspi_read_ivar()
544 *result = slot->host.ios.clock; in mmcspi_read_ivar()
547 *result = slot->host.f_min; in mmcspi_read_ivar()
550 *result = slot->host.f_max; in mmcspi_read_ivar()
553 *result = slot->host.host_ocr; in mmcspi_read_ivar()
556 *result = slot->host.mode; in mmcspi_read_ivar()
559 *result = slot->host.ocr; in mmcspi_read_ivar()
562 *result = slot->host.ios.power_mode; in mmcspi_read_ivar()
565 *result = slot->host.ios.vdd; in mmcspi_read_ivar()
568 *result = slot->host.ios.vccq; in mmcspi_read_ivar()
571 *result = slot->host.caps; in mmcspi_read_ivar()
574 *result = slot->host.ios.timing; in mmcspi_read_ivar()
592 struct mmcspi_slot *slot; in mmcspi_write_ivar() local
596 slot = device_get_ivars(child); in mmcspi_write_ivar()
602 slot->host.ios.bus_mode = value; in mmcspi_write_ivar()
605 slot->host.ios.bus_width = value; in mmcspi_write_ivar()
608 slot->host.ios.clock = value; in mmcspi_write_ivar()
611 slot->host.ios.chip_select = value; in mmcspi_write_ivar()
614 slot->host.mode = value; in mmcspi_write_ivar()
617 slot->host.ocr = value; in mmcspi_write_ivar()
620 slot->host.ios.power_mode = value; in mmcspi_write_ivar()
623 slot->host.ios.vdd = value; in mmcspi_write_ivar()
626 slot->host.ios.vccq = value; in mmcspi_write_ivar()
629 slot->host.ios.timing = value; in mmcspi_write_ivar()
664 err = SPIBUS_TRANSFER(sc->busdev, sc->dev, &spi_cmd); in mmcspi_do_spi_read()
702 err = SPIBUS_TRANSFER(sc->busdev, sc->dev, &spi_cmd); in mmcspi_do_spi_write()
761 struct mmcspi_slot *slot; in mmcspi_update_ios() local
767 slot = device_get_ivars(reqdev); in mmcspi_update_ios()
769 if (power_up == slot->host.ios.power_mode) { in mmcspi_update_ios()
779 * XXX Power-on portion of implementation of card power in mmcspi_update_ios()
805 SPIBUS_TRANSFER(sc->busdev, sc->dev, &spi_cmd); in mmcspi_update_ios()
813 slot->last_opcode = 0xffffffff; in mmcspi_update_ios()
814 slot->last_flags = 0; in mmcspi_update_ios()
815 memset(slot->last_ocr, 0, MMCSPI_OCR_LEN); in mmcspi_update_ios()
816 slot->crc_enabled = 0; in mmcspi_update_ios()
817 slot->crc_init_done = 0; in mmcspi_update_ios()
820 if (power_off == slot->host.ios.power_mode) { in mmcspi_update_ios()
822 * XXX Power-off portion of implementation of card power in mmcspi_update_ios()
844 (src[i + 1] >> (8 - shift)); in mmcspi_shift_copy()
872 * that are not byte-aligned, as some cards send non-byte-aligned in mmcspi_get_response_token()
875 * command used to terminate multi-block reads: in mmcspi_get_response_token()
901 } else if (i < len + offset - 1) { in mmcspi_get_response_token()
904 * for a non-aligned response. in mmcspi_get_response_token()
955 remaining = i - offset + (shift ? 1 : 0); in mmcspi_get_response_token()
998 struct mmcspi_slot *slot; in mmcspi_set_up_command() local
1010 slot = &sc->slot; in mmcspi_set_up_command()
1011 use_crc = slot->crc_enabled; in mmcspi_set_up_command()
1013 opcode = mmc_cmd->opcode; in mmcspi_set_up_command()
1014 arg = mmc_cmd->arg; in mmcspi_set_up_command()
1015 flags = mmc_cmd->flags; in mmcspi_set_up_command()
1016 retries = mmc_cmd->retries; in mmcspi_set_up_command()
1115 * Handle SD_SEND_RELATIVE_ADDR as MMC_SEND_STATUS - in mmcspi_set_up_command()
1152 mmcspi_cmd->mmc_cmd = mmc_cmd; in mmcspi_set_up_command()
1153 mmcspi_cmd->opcode = opcode; in mmcspi_set_up_command()
1154 mmcspi_cmd->arg = arg; in mmcspi_set_up_command()
1155 mmcspi_cmd->flags = flags; in mmcspi_set_up_command()
1156 mmcspi_cmd->retries = retries; in mmcspi_set_up_command()
1157 mmcspi_cmd->use_crc = use_crc; in mmcspi_set_up_command()
1158 mmcspi_cmd->error_mask = MMCSPI_R1_ERR_MASK; in mmcspi_set_up_command()
1159 if (!mmcspi_cmd->use_crc) in mmcspi_set_up_command()
1160 mmcspi_cmd->error_mask &= ~MMCSPI_R1_CRC_ERR; in mmcspi_set_up_command()
1161 mmcspi_cmd->rsp_type = rsp_type; in mmcspi_set_up_command()
1162 mmcspi_cmd->rsp_len = rsp_len; in mmcspi_set_up_command()
1163 mmcspi_cmd->mmc_rsp_type = mmc_rsp_type; in mmcspi_set_up_command()
1165 memset(&mmcspi_cmd->ldata, 0, sizeof(struct mmc_data)); in mmcspi_set_up_command()
1166 mmcspi_cmd->ldata.len = ldata_len; in mmcspi_set_up_command()
1168 mmcspi_cmd->ldata.data = sc->slot.ldata_buf; in mmcspi_set_up_command()
1169 mmcspi_cmd->ldata.flags = MMC_DATA_READ; in mmcspi_set_up_command()
1171 mmcspi_cmd->data = &mmcspi_cmd->ldata; in mmcspi_set_up_command()
1173 mmcspi_cmd->data = mmc_cmd->data; in mmcspi_set_up_command()
1189 opcode = cmd->opcode; in mmcspi_send_cmd()
1190 arg = cmd->arg; in mmcspi_send_cmd()
1193 cmd->flags & MMC_CMD_IS_APP ? "AC": "C", opcode, arg); in mmcspi_send_cmd()
1211 if (cmd->use_crc) in mmcspi_send_cmd()
1219 * Some cards have garbage on the bus in the first byte slot after in mmcspi_send_cmd()
1241 cmd->rsp_len, MMCSPI_RSP_R1B == cmd->rsp_type, rspbuf); in mmcspi_send_cmd()
1244 if (rspbuf[0] & cmd->error_mask & MMCSPI_R1_CRC_ERR) in mmcspi_send_cmd()
1246 else if (rspbuf[0] & cmd->error_mask) in mmcspi_send_cmd()
1280 * (MMCSPI_POLL_LEN - 3 - len) bytes from the spi bus, but only in in mmcspi_read_block()
1317 non_token_bytes = MMCSPI_POLL_LEN - i - 1; in mmcspi_read_block()
1319 crc_captured = non_token_bytes - data_captured; in mmcspi_read_block()
1329 len - data_captured, crc_captured); in mmcspi_read_block()
1334 len - data_captured); in mmcspi_read_block()
1349 MMCSPI_DATA_CRC_LEN - crc_captured); in mmcspi_read_block()
1352 MMCSPI_DATA_CRC_LEN - crc_captured); in mmcspi_read_block()
1362 * allow a passing crc-7 check to override a failing crc-16 check in mmcspi_read_block()
1393 crc7 = data[len - 1] >> 1; in mmcspi_read_block()
1394 computed_crc7 = update_crc7(CRC7_INITIAL, data, len - 1); in mmcspi_read_block()
1462 * caller's retry-on-crc-error mechanism, effectively in mmcspi_send_stop()
1486 data = cmd->data; in mmcspi_read_phase()
1487 data8 = (uint8_t *)data->data; in mmcspi_read_phase()
1490 if (data->len < MMCSPI_DATA_BLOCK_LEN) { in mmcspi_read_phase()
1492 len = data->len; in mmcspi_read_phase()
1494 num_blocks = data->len / MMCSPI_DATA_BLOCK_LEN; in mmcspi_read_phase()
1500 * The CID and CSD data blocks contain both a trailing crc-7 in mmcspi_read_phase()
1501 * inside the data block and the standard crc-16 following in mmcspi_read_phase()
1505 * send CID and CSD data blocks with correct crc-7 values in mmcspi_read_phase()
1506 * but incorrect crc-16 values. read_block will accept in mmcspi_read_phase()
1507 * those responses as valid as long as the crc-7 is correct. in mmcspi_read_phase()
1515 cmd->use_crc, cmd->use_crc && ((MMC_SEND_CID == cmd->opcode) in mmcspi_read_phase()
1516 || (MMC_SEND_CSD == cmd->opcode))); in mmcspi_read_phase()
1526 /* multi-block read commands require a stop */ in mmcspi_read_phase()
1528 err = mmcspi_send_stop(dev, cmd->retries); in mmcspi_read_phase()
1602 data = cmd->data; in mmcspi_write_phase()
1604 data8 = (uint8_t *)data->data; in mmcspi_write_phase()
1606 num_blocks = data->len / MMCSPI_DATA_BLOCK_LEN; in mmcspi_write_phase()
1609 num_blocks > 1, cmd->use_crc, &status); in mmcspi_write_phase()
1624 mmcspi_send_stop(dev, cmd->retries); in mmcspi_write_phase()
1644 /* successful multi-block write commands require a stop token */ in mmcspi_write_phase()
1652 * looking for not busy, avoiding a premature not-busy in mmcspi_write_phase()
1684 mmc_cmd = cmd->mmc_cmd; in mmcspi_translate_response()
1685 mmc_rsp_type = cmd->mmc_rsp_type; in mmcspi_translate_response()
1686 ldata = cmd->ldata.data; in mmcspi_translate_response()
1691 cmd->rsp_type, mmc_rsp_type); in mmcspi_translate_response()
1696 TRACE(dev, ACTION, "translating SPI-R1/2 to SD-R1\n"); in mmcspi_translate_response()
1698 if ((MMCSPI_RSP_R1 == cmd->rsp_type) || in mmcspi_translate_response()
1699 (MMCSPI_RSP_R1B == cmd->rsp_type) || in mmcspi_translate_response()
1700 (MMCSPI_RSP_R2 == cmd->rsp_type)) { in mmcspi_translate_response()
1701 mmc_cmd->resp[0] = 0; in mmcspi_translate_response()
1704 mmc_cmd->resp[0] |= R1_OUT_OF_RANGE; in mmcspi_translate_response()
1707 mmc_cmd->resp[0] |= R1_ADDRESS_ERROR; in mmcspi_translate_response()
1710 mmc_cmd->resp[0] |= R1_ERASE_SEQ_ERROR; in mmcspi_translate_response()
1713 mmc_cmd->resp[0] |= R1_COM_CRC_ERROR; in mmcspi_translate_response()
1716 mmc_cmd->resp[0] |= R1_ILLEGAL_COMMAND; in mmcspi_translate_response()
1719 mmc_cmd->resp[0] |= R1_ERASE_RESET; in mmcspi_translate_response()
1722 mmc_cmd->resp[0] |= in mmcspi_translate_response()
1725 mmc_cmd->resp[0] |= in mmcspi_translate_response()
1729 SD-bus status bit. */ in mmcspi_translate_response()
1730 if (!(cmd->flags & MMC_CMD_IS_APP) && in mmcspi_translate_response()
1731 (MMC_APP_CMD == cmd->opcode)) in mmcspi_translate_response()
1732 mmc_cmd->resp[0] |= R1_APP_CMD; in mmcspi_translate_response()
1734 if (MMCSPI_RSP_R2 == cmd->rsp_type) { in mmcspi_translate_response()
1736 mmc_cmd->resp[0] |= in mmcspi_translate_response()
1741 mmc_cmd->resp[0] |= R1_ERASE_PARAM; in mmcspi_translate_response()
1744 mmc_cmd->resp[0] |= R1_WP_VIOLATION; in mmcspi_translate_response()
1747 mmc_cmd->resp[0] |= R1_CARD_ECC_FAILED; in mmcspi_translate_response()
1750 mmc_cmd->resp[0] |= R1_CC_ERROR; in mmcspi_translate_response()
1753 mmc_cmd->resp[0] |= R1_ERROR; in mmcspi_translate_response()
1756 mmc_cmd->resp[0] |= in mmcspi_translate_response()
1761 mmc_cmd->resp[0] |= R1_CARD_IS_LOCKED; in mmcspi_translate_response()
1769 if (16 == cmd->ldata.len) { in mmcspi_translate_response()
1771 TRACE(dev, ACTION, "translating SPI-R1/ldata(16) " in mmcspi_translate_response()
1772 "to SD-R2\n"); in mmcspi_translate_response()
1776 mmc_cmd->resp[0] = in mmcspi_translate_response()
1782 mmc_cmd->resp[1] = in mmcspi_translate_response()
1788 mmc_cmd->resp[2] = in mmcspi_translate_response()
1794 mmc_cmd->resp[3] = in mmcspi_translate_response()
1804 if (MMCSPI_RSP_R3 == cmd->rsp_type) { in mmcspi_translate_response()
1806 TRACE(dev, ACTION, "translating SPI-R3 to SD-R3\n"); in mmcspi_translate_response()
1808 /* rspbuf contains a 40-bit spi-R3 from the in mmcspi_translate_response()
1814 mmc_cmd->resp[0] = in mmcspi_translate_response()
1821 SPI-R1 idle bit is set. */ in mmcspi_translate_response()
1823 mmc_cmd->resp[0] &= ~MMC_OCR_CARD_BUSY; in mmcspi_translate_response()
1825 mmc_cmd->resp[0] |= MMC_OCR_CARD_BUSY; in mmcspi_translate_response()
1828 TRACE(dev, DETAILS, "ocr=0x%08x\n", mmc_cmd->resp[0]); in mmcspi_translate_response()
1833 if (MMCSPI_RSP_R2 == cmd->rsp_type) { in mmcspi_translate_response()
1835 TRACE(dev, ACTION, "translating SPI-R2 to SD-R6\n"); in mmcspi_translate_response()
1838 mmc_cmd->resp[0] = 0; in mmcspi_translate_response()
1841 mmc_cmd->resp[0] |= 0x8000; in mmcspi_translate_response()
1844 mmc_cmd->resp[0] |= 0x4000; in mmcspi_translate_response()
1847 mmc_cmd->resp[0] |= 0x2000; in mmcspi_translate_response()
1850 mmc_cmd->resp[0] |= in mmcspi_translate_response()
1853 mmc_cmd->resp[0] |= in mmcspi_translate_response()
1859 if (MMCSPI_RSP_R7 == cmd->rsp_type) { in mmcspi_translate_response()
1861 TRACE(dev, ACTION, "translating SPI-R7 to SD-R7\n"); in mmcspi_translate_response()
1863 /* rsp buf contains a 40-bit spi-R7, of which bits in mmcspi_translate_response()
1868 mmc_cmd->resp[0] = in mmcspi_translate_response()
1974 struct mmcspi_slot *slot; in mmcspi_update_crc_setting() local
1981 slot = &sc->slot; in mmcspi_update_crc_setting()
1995 slot->crc_enabled = 1; in mmcspi_update_crc_setting()
1997 slot->crc_enabled = 0; in mmcspi_update_crc_setting()
2010 struct mmcspi_slot *slot = &sc->slot; in mmcspi_request() local
2012 struct mmc_command *mmc_cmd = req->cmd; in mmcspi_request()
2028 if (power_on != slot->host.ios.power_mode) in mmcspi_request()
2035 use_crc_sample = sc->use_crc; in mmcspi_request()
2036 if (slot->crc_init_done && in mmcspi_request()
2037 (use_crc_sample != slot->crc_enabled)) { in mmcspi_request()
2041 slot->crc_init_done = 1; in mmcspi_request()
2052 last_opcode = slot->last_opcode; in mmcspi_request()
2053 last_flags = slot->last_flags; in mmcspi_request()
2062 if ((data->len % MMCSPI_DATA_BLOCK_LEN) && in mmcspi_request()
2063 !((data->flags & MMC_DATA_READ) && in mmcspi_request()
2064 (data->len < MMCSPI_DATA_BLOCK_LEN))) { in mmcspi_request()
2072 if (((data->flags & MMC_DATA_READ) && in mmcspi_request()
2073 (data->flags & MMC_DATA_WRITE)) || in mmcspi_request()
2074 (data->flags & MMC_DATA_STREAM)) { in mmcspi_request()
2076 data->flags); in mmcspi_request()
2088 err = mmcspi_get_ocr(brdev, slot->last_ocr); in mmcspi_request()
2104 if (data->flags & MMC_DATA_READ) in mmcspi_request()
2137 memcpy(&rspbuf[1], slot->last_ocr, MMCSPI_OCR_LEN); in mmcspi_request()
2149 if (!slot->crc_init_done) { in mmcspi_request()
2151 sc->use_crc); in mmcspi_request()
2154 slot->crc_init_done = 1; in mmcspi_request()
2186 slot->last_opcode = mmc_cmd->opcode; in mmcspi_request()
2187 slot->last_flags = mmc_cmd->flags; in mmcspi_request()
2189 mmc_cmd->error = err; in mmcspi_request()
2191 if (req->done) in mmcspi_request()
2192 req->done(req); in mmcspi_request()
2213 struct mmcspi_slot *slot; in mmcspi_acquire_host() local
2219 slot = device_get_ivars(reqdev); in mmcspi_acquire_host()
2221 MMCSPI_LOCK_SLOT(slot); in mmcspi_acquire_host()
2222 while (slot->bus_busy) in mmcspi_acquire_host()
2223 mtx_sleep(slot, &slot->mtx, 0, "mmcspiah", 0); in mmcspi_acquire_host()
2224 slot->bus_busy++; in mmcspi_acquire_host()
2225 MMCSPI_UNLOCK_SLOT(slot); in mmcspi_acquire_host()
2235 struct mmcspi_slot *slot; in mmcspi_release_host() local
2239 slot = device_get_ivars(reqdev); in mmcspi_release_host()
2241 MMCSPI_LOCK_SLOT(slot); in mmcspi_release_host()
2242 slot->bus_busy--; in mmcspi_release_host()
2243 MMCSPI_UNLOCK_SLOT(slot); in mmcspi_release_host()
2245 wakeup(slot); in mmcspi_release_host()
2288 residual = len - 16 * num_lines; in mmcspi_dump_data()
2317 residual = len - num_blocks * MMCSPI_DATA_BLOCK_LEN; in mmcspi_dump_spi_bus()