diff --git a/cpu/sam0_common/Makefile b/cpu/sam0_common/Makefile index 3824d9e978..f88f199ffb 100644 --- a/cpu/sam0_common/Makefile +++ b/cpu/sam0_common/Makefile @@ -1,7 +1,10 @@ DIRS = periph -ifneq (, $(filter sam0_eth, $(USEMODULE))) - DIRS += sam0_eth +ifneq (,$(filter sam0_eth, $(USEMODULE))) + DIRS += sam0_eth +endif +ifneq (,$(filter sam0_sdhc, $(USEMODULE))) + DIRS += sam0_sdhc endif include $(RIOTBASE)/Makefile.base diff --git a/cpu/sam0_common/include/mtd_sam0_sdhc.h b/cpu/sam0_common/include/mtd_sam0_sdhc.h new file mode 100644 index 0000000000..b28766409e --- /dev/null +++ b/cpu/sam0_common/include/mtd_sam0_sdhc.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 Benjamin Valentin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_storage + * @ingroup cpu_sam0_common_sdhc + * @brief Driver for SD-cards using mtd interface + * + * @{ + * + * @file + * @brief Interface definition for SAM SDHC driver + * + * @author Benjamin Valentin + */ + +#ifndef MTD_SAM0_SDHC_H +#define MTD_SAM0_SDHC_H + +#include + +#include "mtd.h" +#include "sdhc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Device descriptor for mtd_sdcard device + * + * This is an extension of the @c mtd_dev_t struct + */ +typedef struct { + mtd_dev_t base; /**< inherit from mtd_dev_t object */ + sdhc_state_t state; /**< sdcard_spi dev descriptor */ +} mtd_sam0_sdhc_t; + +/** + * @brief sdcard device operations table for mtd + */ +extern const mtd_desc_t mtd_sam0_sdhc_driver; + +#ifdef __cplusplus +} +#endif + +#endif /* MTD_SAM0_SDHC_H */ +/** @} */ diff --git a/cpu/sam0_common/include/sdhc.h b/cpu/sam0_common/include/sdhc.h new file mode 100644 index 0000000000..a89125cfe0 --- /dev/null +++ b/cpu/sam0_common/include/sdhc.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2018 Alkgrove + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup cpu_sam0_common_sdhc sam0 SD Host Controller + * @ingroup cpu_sam0_common + * @brief SD card interface functions for sam0 class devices + * + * @{ + * + * @file + * @brief SD card interface functions for sam0 class devices + * + * @author alkgrove + * @author Benjamin Valentin + */ + +#ifndef SDHC_H +#define SDHC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "periph/gpio.h" +#include "mutex.h" + +/** + * @brief SD Card driver context + */ +typedef struct { + Sdhc *dev; /**< SDHC instance */ + gpio_t cd; /**< Card detect pin */ + gpio_t wp; /**< Write Protect pin */ + mutex_t lock; /**< Ensure thread-safe access */ + mutex_t sync; /**< ISR mutex */ + uint32_t sectors; /**< Capacity in bytes */ + uint32_t clock; /**< Accepted Cloc Rate in Hz */ + uint16_t rca; /**< Relative Card Address */ + uint16_t error; /**< Last error state */ + uint8_t type; /**< Type of Card */ + uint8_t version; /**< Version of Card */ + uint8_t bus_width; /**< Acceptable Bus Width (1 or 4) */ + bool high_speed; /**< Turbo mode */ + bool need_init; /**< Card installed but not initialized if true */ +} sdhc_state_t; + +/** @name Card Types */ +/** @{ */ +#define CARD_TYPE_UNKNOWN (0) /**< Unknown type card */ +#define CARD_TYPE_SD (1 << 0) /**< SD card */ +#define CARD_TYPE_MMC (1 << 1) /**< MMC card */ +#define CARD_TYPE_SDIO (1 << 2) /**< SDIO card */ +#define CARD_TYPE_HC (1 << 3) /**< High capacity card */ +/** SD combo card (io + memory) */ +#define CARD_TYPE_SD_COMBO (CARD_TYPE_SD | CARD_TYPE_SDIO) +/** @} */ + +/** @name Card Versions */ +/** @{ */ +#define CARD_VER_UNKNOWN (0) /**< Unknown card version */ +#define CARD_VER_SD_1_0 (0x10) /**< SD version 1.0 and 1.01 */ +#define CARD_VER_SD_1_10 (0x1A) /**< SD version 1.10 */ +#define CARD_VER_SD_2_0 (0X20) /**< SD version 2.00 */ +#define CARD_VER_SD_3_0 (0X30) /**< SD version 3.0X */ +#define CARD_VER_MMC_1_2 (0x12) /**< MMC version 1.2 */ +#define CARD_VER_MMC_1_4 (0x14) /**< MMC version 1.4 */ +#define CARD_VER_MMC_2_2 (0x22) /**< MMC version 2.2 */ +#define CARD_VER_MMC_3 (0x30) /**< MMC version 3 */ +#define CARD_VER_MMC_4 (0x40) /**< MMC version 4 */ +/** @} */ + +/** @name Flags used to define MCI parser for SD/MMC command */ +/** @{ */ +#define MCI_RESP_PRESENT (1ul << 8) /**< Have response */ +#define MCI_RESP_136 (1ul << 11) /**< 136 bit response */ +#define MCI_RESP_CRC (1ul << 12) /**< Expect valid crc */ +#define MCI_RESP_BUSY (1ul << 13) /**< Card may send busy */ +#define MCI_CMD_OPENDRAIN (1ul << 14) /**< Open drain for a braodcast command */ +#define MCI_CMD_WRITE (1ul << 15) /**< To signal a data write operation */ +#define MCI_CMD_SDIO_BYTE (1ul << 16) /**< To signal a SDIO transfer in multi byte mode */ +#define MCI_CMD_SDIO_BLOCK (1ul << 17) /**< To signal a SDIO transfer in block mode */ +#define MCI_CMD_STREAM (1ul << 18) /**< To signal a data transfer in stream mode */ +#define MCI_CMD_SINGLE_BLOCK (1ul << 19) /**< To signal a data transfer in single block mode */ +#define MCI_CMD_MULTI_BLOCK (1ul << 20) /**< To signal a data transfer in multi block mode */ +/** @} */ + +/** This SD stack uses the maximum block size authorized (512 bytes) */ +#define SD_MMC_BLOCK_SIZE 512 /**< SD card block size */ +#define SDHC_SLOW_CLOCK_HZ 400000 /**< Clock frequency on init */ + +/** + * @brief Initialize the SD host controller + * + * @param[in] state driver context + * + * @return int 0 on success, error otherwise + */ +int sdhc_init(sdhc_state_t *state); + +/** + * @brief Send a command to the SD card + * + * @param[in] state driver context + * @param[in] cmd the command code + * @param[in] arg command argument + * + * @return true command was successful + * @return false command returned error + */ +bool sdhc_send_cmd(sdhc_state_t *state, uint32_t cmd, uint32_t arg); + +/** + * @brief Read blocks from the SD card into memory + * + * Reads n 512 byte blocks from the SD card + * + * @param[in] state driver context + * @param[in] block block number to read from + * @param[out] dst destination address + * @param[in] num number of blocks to read + * + * @return 0 if success, negative error if failed + */ +int sdhc_read_blocks(sdhc_state_t *state, uint32_t block, void *dst, uint16_t num); + +/** + * @brief Write memory to SD card blocks + * + * Writes n 512 bytes blocks on the SD card + * + * @param[in] state driver context + * @param[in] block block number to write to + * @param[in] src pointer to memory to write + * @param[in] num number of blocks to write + * + * @return 0 if success, negative error if failed + */ +int sdhc_write_blocks(sdhc_state_t *state, uint32_t block, const void *src, + uint16_t num); + +/** + * @brief Erase memory from SD card blocks + * + * Erases n 512 byte blocks on the SD card + * + * @param[in] state driver context + * @param[in] block first block number to erase + * @param[in] num number of blocks to erase + * + * @return 0 if success, negative error if failed + */ +int sdhc_erase_blocks(sdhc_state_t *state, uint32_t block, uint16_t num); + +#ifdef __cplusplus +} +#endif + +#endif /* SDHC_H */ +/** @} */ diff --git a/cpu/sam0_common/sam0_sdhc/Makefile b/cpu/sam0_common/sam0_sdhc/Makefile new file mode 100644 index 0000000000..2cc6531a04 --- /dev/null +++ b/cpu/sam0_common/sam0_sdhc/Makefile @@ -0,0 +1,3 @@ +MODULE=sam0_sdhc + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/sam0_common/sam0_sdhc/mtd_sdhc.c b/cpu/sam0_common/sam0_sdhc/mtd_sdhc.c new file mode 100644 index 0000000000..0a58e495ac --- /dev/null +++ b/cpu/sam0_common/sam0_sdhc/mtd_sdhc.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2022 Benjamin Valentin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + */ + +/** + * @ingroup drivers_mtd + * @{ + * + * @file + * @brief Driver for using sam0 SDHC controller via mtd interface + * + * @author Benjamin Valentin + * + * @} + */ + +#include +#include +#include + +#include "mtd_sam0_sdhc.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#define min(a, b) ((a) > (b) ? (b) : (a)) + +static int _init(mtd_dev_t *dev) +{ + mtd_sam0_sdhc_t *ctx = container_of(dev, mtd_sam0_sdhc_t, base); + + if (sdhc_init(&ctx->state)) { + DEBUG("SDHC init failed\n"); + return -EIO; + } + + dev->pages_per_sector = 1; + dev->page_size = SD_MMC_BLOCK_SIZE; + dev->sector_count = ctx->state.sectors; + dev->write_size = SD_MMC_BLOCK_SIZE; + +#if IS_USED(MODULE_MTD_WRITE_PAGE) + /* TODO: move to MTD layer */ + dev->work_area = malloc(SD_MMC_BLOCK_SIZE); + if (dev->work_area == NULL) { + return -ENOMEM; + } + dev->write_size = 1; +#endif + + DEBUG("sector size: %lu\n", dev->page_size); + DEBUG("sector count: %lu\n", dev->sector_count); + DEBUG("pages / sector: %lu\n", dev->pages_per_sector); + + return 0; +} + +static int _read_page(mtd_dev_t *dev, void *buff, uint32_t page, + uint32_t offset, uint32_t size) +{ + mtd_sam0_sdhc_t *ctx = container_of(dev, mtd_sam0_sdhc_t, base); + uint16_t pages = size / SD_MMC_BLOCK_SIZE; + + DEBUG("%s(%lu, %lu, %lu)\n", __func__, page, offset, size); + + /* emulate unaligned / sub-page read */ + if (pages == 0 || offset) { +#if IS_USED(MODULE_MTD_WRITE_PAGE) + if (dev->work_area == NULL) { + DEBUG("mtd_sdhc: no work area\n"); + return -ENOTSUP; + } + + size = min(SD_MMC_BLOCK_SIZE - offset, size); + + if (sdhc_read_blocks(&ctx->state, page, dev->work_area, 1)) { + return -EIO; + } + + memcpy(buff, dev->work_area + offset, size); + return size; +#else + return -ENOTSUP; +#endif + } + + if (sdhc_read_blocks(&ctx->state, page, buff, pages)) { + return -EIO; + } + + return pages * SD_MMC_BLOCK_SIZE; +} + +static int _write_page(mtd_dev_t *dev, const void *buff, uint32_t page, + uint32_t offset, uint32_t size) +{ + mtd_sam0_sdhc_t *ctx = container_of(dev, mtd_sam0_sdhc_t, base); + uint16_t pages = size / SD_MMC_BLOCK_SIZE; + + DEBUG("%s(%lu, %lu, %lu)\n", __func__, page, offset, size); + + /* emulate unaligned / sub-page write */ + if (pages == 0 || offset) { +#if IS_USED(MODULE_MTD_WRITE_PAGE) + if (dev->work_area == NULL) { + DEBUG("mtd_sdhc: no work area\n"); + return -ENOTSUP; + } + + size = min(SD_MMC_BLOCK_SIZE - offset, size); + + if (sdhc_read_blocks(&ctx->state, page, dev->work_area, 1)) { + return -EIO; + } + + memcpy(dev->work_area + offset, buff, size); + + buff = dev->work_area; + pages = 1; +#else + return -ENOTSUP; +#endif + } + + if (sdhc_write_blocks(&ctx->state, page, buff, pages)) { + return -EIO; + } + + return min(size, pages * SD_MMC_BLOCK_SIZE); +} + +static int _erase_sector(mtd_dev_t *dev, uint32_t sector, uint32_t count) +{ + mtd_sam0_sdhc_t *ctx = container_of(dev, mtd_sam0_sdhc_t, base); + + if (sdhc_erase_blocks(&ctx->state, sector, count)) { + return -EIO; + } + + return 0; +} + +const mtd_desc_t mtd_sam0_sdhc_driver = { + .init = _init, + .read_page = _read_page, + .write_page = _write_page, + .erase_sector = _erase_sector, + .flags = MTD_DRIVER_FLAG_DIRECT_WRITE, +}; diff --git a/cpu/sam0_common/sam0_sdhc/sdhc.c b/cpu/sam0_common/sam0_sdhc/sdhc.c new file mode 100644 index 0000000000..95f04e67a9 --- /dev/null +++ b/cpu/sam0_common/sam0_sdhc/sdhc.c @@ -0,0 +1,1068 @@ +/* + * Copyright (C) 2018 Alkgrove + * + * C file for SD card host controller driver + * This is a complete rewrite of the SD Card code from ASF4 + * Copyright © Alkgrove 04/29/2018 + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific prior written + * permission. + * + * @par THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @ingroup cpu_sam0_common_sdhc + * @{ + * + * @file + * @brief Driver for the SD Host Controller + * + * @author alkgrove + * @author Benjamin Valentin + * + * @} + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "periph_cpu.h" +#include "periph/pm.h" +#include "vendor/sd_mmc_protocol.h" +#include "sdhc.h" +#include "time_units.h" +#include "ztimer.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#ifndef SDHC_CLOCK +#define SDHC_CLOCK SAM0_GCLK_MAIN +#endif + +#ifndef SDHC_CLOCK_SLOW +#define SDHC_CLOCK_SLOW SAM0_GCLK_TIMER +#endif + +/** + * @brief The board can overwrite this if only a single SDHC instance is used + * to save 80 Bytes of ROM. + */ +#ifndef SDHC_DEV +#ifdef SDHC1 +#define SDHC_DEV state->dev +#else +#define SDHC_DEV SDHC0 +#endif +#endif + +/** + * @brief Monitor card insertion and removal + */ +#define NISTR_CARD_DETECT (SDHC_NISTR_CREM | SDHC_NISTR_CINS) + +static sdhc_state_t *isr_ctx_0; +static sdhc_state_t *isr_ctx_1; + +static void _set_speed(sdhc_state_t *state, uint32_t fsdhc); +static void _set_hc(sdhc_state_t *state); +static bool _test_voltage(sdhc_state_t *state, bool f8); +static bool _test_capacity(sdhc_state_t *state); +static bool _test_version(sdhc_state_t *state); +static bool _wait_not_busy(sdhc_state_t *state); +static bool _test_bus_width(sdhc_state_t *state); +static bool _test_high_speed(sdhc_state_t *state); +static bool _init_transfer(sdhc_state_t *state, uint32_t cmd, uint32_t arg, uint16_t block_size, + uint16_t num_blocks); +static bool sdio_test_type(sdhc_state_t *state); + +/** SD/MMC transfer rate unit codes (10K) list */ +static const uint32_t transfer_units[] = { 10, 100, 1000, 10000, 0, 0, 0, 0 }; +/** SD transfer multiplier factor codes (1/10) list */ +static const uint8_t transfer_multiplier[16] = +{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; + +static bool _card_detect(sdhc_state_t *state) +{ + return state->dev->PSR.bit.CARDINS; +} + +static bool _check_mask(uint32_t val, uint32_t mask) +{ + return (val & mask) == mask; +} + +static void _delay(unsigned us) +{ + if (IS_USED(MODULE_ZTIMER_USEC)) { + ztimer_sleep(ZTIMER_USEC, us); + } else if (IS_USED(MODULE_ZTIMER_MSEC)) { + ztimer_sleep(ZTIMER_MSEC, 1); + } else { + volatile unsigned count = (us * CLOCK_CORECLOCK) / US_PER_SEC; + while (--count) {} + } +} + +static void _reset_all(sdhc_state_t *state) +{ + SDHC_DEV->SRR.reg = SDHC_SRR_SWRSTALL; + while (SDHC_DEV->SRR.bit.SWRSTALL) {} + state->need_init = true; + state->error = 0; +} + +static uint32_t _wait_for_event(sdhc_state_t *state) +{ + uint32_t res; + + /* SDHC runs off CPU clock - block IDLE so that the clock does not stop */ + pm_block(3); + mutex_lock(&state->sync); + pm_unblock(3); + + res = state->error; + state->error = 0; + return res; +} + +static void _init_clocks(sdhc_state_t *state) +{ + assert((SDHC_DEV == SDHC0) +#ifdef SDHC1 + || (SDHC_DEV == SDHC1) +#endif + ); + + sam0_gclk_enable(SDHC_CLOCK); + sam0_gclk_enable(SDHC_CLOCK_SLOW); + + gpio_init_mux(state->cd, SAM0_SDHC_MUX); + if (gpio_is_valid(state->wp)) { + gpio_init_mux(state->wp, SAM0_SDHC_MUX); + } + + if (SDHC_DEV == SDHC0) { + /* data pins are fixed */ + gpio_init_mux(SAM0_SDHC0_PIN_SDDAT0, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC0_PIN_SDDAT1, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC0_PIN_SDDAT2, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC0_PIN_SDDAT3, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC0_PIN_SDCMD, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC0_PIN_SDCK, SAM0_SDHC_MUX); + + GCLK->PCHCTRL[SDHC0_GCLK_ID].reg = GCLK_PCHCTRL_CHEN + | GCLK_PCHCTRL_GEN(SDHC_CLOCK); + GCLK->PCHCTRL[SDHC0_GCLK_ID_SLOW].reg = GCLK_PCHCTRL_CHEN + | GCLK_PCHCTRL_GEN(SDHC_CLOCK_SLOW); + MCLK->AHBMASK.bit.SDHC0_ = 1; + isr_ctx_0 = state; + NVIC_EnableIRQ(SDHC0_IRQn); + } + +#ifdef SDHC1 + if (SDHC_DEV == SDHC1) { + /* data pins are fixed */ + gpio_init_mux(SAM0_SDHC1_PIN_SDDAT0, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC1_PIN_SDDAT1, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC1_PIN_SDDAT2, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC1_PIN_SDDAT3, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC1_PIN_SDCMD, SAM0_SDHC_MUX); + gpio_init_mux(SAM0_SDHC1_PIN_SDCK, SAM0_SDHC_MUX); + + GCLK->PCHCTRL[SDHC1_GCLK_ID].reg = GCLK_PCHCTRL_CHEN + | GCLK_PCHCTRL_GEN(SDHC_CLOCK); + GCLK->PCHCTRL[SDHC1_GCLK_ID_SLOW].reg = GCLK_PCHCTRL_CHEN + | GCLK_PCHCTRL_GEN(SDHC_CLOCK_SLOW); + MCLK->AHBMASK.bit.SDHC1_ = 1; + isr_ctx_1 = state; + NVIC_EnableIRQ(SDHC1_IRQn); + } +#endif +} + +int sdhc_init(sdhc_state_t *state) +{ + bool f8; + uint32_t response; + + /* set the initial clock slow, single bit and normal speed */ + state->type = CARD_TYPE_SD; + state->version = CARD_VER_UNKNOWN; + state->rca = 0; + state->bus_width = 1; + state->high_speed = false; + state->clock = SDHC_SLOW_CLOCK_HZ; + mutex_init(&state->lock); + const mutex_t _init_locked = MUTEX_INIT_LOCKED; + state->sync = _init_locked; + + _init_clocks(state); + _reset_all(state); + + SDHC_DEV->TCR.reg = 14; /* max timeout is 14 or about 1sec */ + SDHC_DEV->PCR.reg = SDHC_PCR_SDBPWR | SDHC_PCR_SDBVSEL_3V3; + SDHC_DEV->NISTER.reg = SDHC_NISTER_MASK; /* clear all normal interrupt bits */ + SDHC_DEV->EISTER.reg = SDHC_EISTER_MASK; /* clear all error interrupt bits */ + + _set_hc(state); + /* 74 startup clocks (190us) */ + _delay(190); + + /* reset the SD card to idle state CMD0 */ + f8 = false; + for (int i = 0; i < 2; i++) { /* we do this step twice before failing */ + if (!sdhc_send_cmd(state, SDMMC_MCI_CMD0_GO_IDLE_STATE, 0)) { + if (i == 1) { + return -EIO; + } + } + /* Test for SD version 2 */ + if (!sdhc_send_cmd(state, SD_CMD8_SEND_IF_COND, SD_CMD8_PATTERN | SD_CMD8_HIGH_VOLTAGE)) { + if (i == 1) { + /* bad card */ + return -EIO; + } + } + else { + response = SDHC_DEV->RR[0].reg; + /* good response but no compliance R7 Value, legacy card */ + if (response == 0xFFFFFFFF) { + f8 = false; + break; + } + if (_check_mask(response, SD_CMD8_PATTERN | SD_CMD8_HIGH_VOLTAGE)) { + f8 = true; + break; + } + } + } + if (!sdio_test_type(state)) { + return -EIO; + } + if (state->type & CARD_TYPE_SDIO) { + return -ENOTSUP; + } + /* Try to get the SD card's operating condition */ + if (!_test_voltage(state, f8)) { + state->type = CARD_TYPE_UNKNOWN; + return -EIO; + } + /* SD MEMORY, Put the Card in Identify Mode + * Note: The CID is not used in this stack */ + if (!sdhc_send_cmd(state, SDMMC_CMD2_ALL_SEND_CID, 0)) { + return -EIO; + } + /* Ask the card to publish a new relative address (RCA).*/ + if (!sdhc_send_cmd(state, SD_CMD3_SEND_RELATIVE_ADDR, 0)) { + return -EIO; + } + state->rca = (uint16_t)(SDHC_DEV->RR[0].reg >> 16); + /* SD MEMORY, Get the Card-Specific Data */ + if (!_test_capacity(state)) { + return -EIO; + } + /* Put it into Transfer Mode */ + if (!sdhc_send_cmd(state, SDMMC_CMD7_SELECT_CARD_CMD, (uint32_t)state->rca << 16)) { + return -EIO; + } + /* SD MEMORY, Read the SCR to get card version */ + if (!_test_version(state)) { + return -EIO; + } + if (!_test_bus_width(state)) { + return -EIO; + } + + /* update the host controller to the detected changes in bus_width and clock */ + _set_hc(state); + + /* if it is high speed capable, (well it is) */ + if (SDHC_DEV->CA0R.bit.HSSUP) { + if (!_test_high_speed(state)) { + return -EIO; + } + } + + /* update host controller */ + _set_hc(state); + + if (!sdhc_send_cmd(state, SDMMC_CMD16_SET_BLOCKLEN, SD_MMC_BLOCK_SIZE)) { + return -EIO; + } + + state->need_init = false; + return 0; +} + +bool sdhc_send_cmd(sdhc_state_t *state, uint32_t cmd, uint32_t arg) +{ + uint32_t timeout = 0xFFFFFFFF; + uint32_t command; + uint32_t eis; + + /* wait if card is busy */ + while (SDHC_DEV->PSR.reg & (SDHC_PSR_CMDINHC | SDHC_PSR_CMDINHD)) {} + + SDHC_DEV->TMR.reg = 0; /* only single transfer */ + SDHC_DEV->BCR.reg = 0; /* block count is zero */ + + command = SDHC_CR_CMDIDX(cmd) | SDHC_CR_CMDTYP_NORMAL; + if (cmd & MCI_RESP_PRESENT) { + if (cmd & MCI_RESP_136) { + command |= SDHC_CR_RESPTYP_136_BIT; + } + else if (cmd & MCI_RESP_BUSY) { + command |= SDHC_CR_RESPTYP_48_BIT_BUSY; + } + else { + command |= SDHC_CR_RESPTYP_48_BIT; + } + } + + if (cmd & MCI_CMD_OPENDRAIN) { + SDHC_DEV->MC1R.reg |= SDHC_MC1R_OPD; + } + else { + SDHC_DEV->MC1R.reg &= ~SDHC_MC1R_OPD; + } + + eis = (cmd & MCI_RESP_CRC) + ? SDHC_EISTR_CMDTEO | SDHC_EISTR_CMDEND | SDHC_EISTR_CMDIDX | SDHC_EISTR_DATTEO | + SDHC_EISTR_DATEND | SDHC_EISTR_ADMA + : SDHC_EISTR_CMDTEO | SDHC_EISTR_CMDEND | SDHC_EISTR_CMDIDX | SDHC_EISTR_DATTEO | + SDHC_EISTR_DATEND | SDHC_EISTR_ADMA | SDHC_EISTR_CMDCRC | SDHC_EISTR_DATCRC; + + SDHC_DEV->NISIER.reg = SDHC_NISTR_CMDC | NISTR_CARD_DETECT; + SDHC_DEV->EISIER.reg = eis; + + SDHC_DEV->ARG1R.reg = arg; /* setup the argument register */ + SDHC_DEV->CR.reg = command; /* send command */ + + if (_wait_for_event(state)) { + SDHC_DEV->SRR.reg = SDHC_SRR_SWRSTCMD; /* reset command */ + while (SDHC_DEV->SRR.bit.SWRSTCMD) {} + return false; + } + + if (cmd & MCI_RESP_BUSY) { + do { + if (--timeout == 0) { + SDHC_DEV->SRR.reg = SDHC_SRR_SWRSTCMD; /* reset command */ + while (SDHC_DEV->SRR.bit.SWRSTCMD) {} + return false; + } + } while (!(SDHC_DEV->PSR.reg & SDHC_PSR_DATLL(1))); /* DAT[0] is busy bit */ + } + + return true; +} + +static void _set_speed(sdhc_state_t *state, uint32_t fsdhc) +{ + (void)state; + + uint32_t div; + + if (SDHC_DEV->CCR.bit.SDCLKEN) { + /* wait for command/data to go inactive */ + while (SDHC_DEV->PSR.reg & (SDHC_PSR_CMDINHC | SDHC_PSR_CMDINHD)) {} + /* disable the clock */ + SDHC_DEV->CCR.reg &= ~SDHC_CCR_SDCLKEN; + } + + /* since both examples use divided clock rather than programmable - just use divided here */ + SDHC_DEV->CCR.reg &= ~SDHC_CCR_CLKGSEL; /* divided clock */ + + /* Fsdclk = Fsdhc_core/(2 * div) */ + div = (sam0_gclk_freq(SDHC_CLOCK) / fsdhc) / 2; + + /* high speed div must not be 0 */ + if (SDHC_DEV->HC1R.bit.HSEN && (div == 0)) { + div = 1; + } + + /* write the 10 bit clock divider */ + SDHC_DEV->CCR.reg &= ~(SDHC_CCR_USDCLKFSEL_Msk | SDHC_CCR_SDCLKFSEL_Msk); + SDHC_DEV->CCR.reg |= SDHC_CCR_SDCLKFSEL(div) | SDHC_CCR_USDCLKFSEL(div >> 8); + SDHC_DEV->CCR.reg |= SDHC_CCR_INTCLKEN; /* enable internal clock */ + while (!SDHC_DEV->CCR.bit.INTCLKS) {} /* wait for clock to be stable */ + SDHC_DEV->CCR.reg |= SDHC_CCR_SDCLKEN; /* enable clock to card */ +} + +/** + * _set_hc selects either one or four bit mode, low/high speed and clock + * + * bitwidth is SDHC_HC1R_DW_1BIT_Val or SDHC_HC1R_DW_4BIT_Val + * speed is SDHC_HC1R_HSEN_NORMAL_Val or SDHC_HC1R_HSEN_HIGH_Val + */ +static void _set_hc(sdhc_state_t *state) +{ + if (state->high_speed) { + SDHC_DEV->HC1R.reg |= SDHC_HC1R_HSEN; + } + else { + SDHC_DEV->HC1R.reg &= ~SDHC_HC1R_HSEN; + } + if (!SDHC_DEV->HC2R.bit.PVALEN) { /* PVALEN is probably always low */ + _set_speed(state, state->clock); + } + if (state->bus_width == 4) { + /* set four bit mode */ + SDHC_DEV->HC1R.reg |= SDHC_HC1R_DW; + } + else { + /* set one bit mode */ + SDHC_DEV->HC1R.reg &= ~SDHC_HC1R_DW; + } +} + +/** + * @brief Ask to all cards to send their operations conditions (MCI only). + * - ACMD41 sends operation condition command. + * - ACMD41 reads OCR + * + * @param state pointer to sdhc + * + * @return true if success, otherwise false + */ +static bool _test_voltage(sdhc_state_t *state, bool f8) +{ + uint32_t arg; + uint32_t retry = 2100; + uint32_t response; + + /* + * Timeout 1s = 400KHz / ((6+6+6+6)*8) cycles = 2100 retry + * 6 = cmd byte size + * 6 = response byte size + * 6 = cmd byte size + * 6 = response byte size + */ + retry = 2100; + do { + /* CMD55 - Indicate to the card that the next command is an + * application specific command rather than a standard command.*/ + if (!sdhc_send_cmd(state, SDMMC_CMD55_APP_CMD, 0)) { + return false; + } + + /* (ACMD41) Sends host OCR register */ + arg = OCR_VDD_27_28 | OCR_VDD_28_29 | OCR_VDD_29_30 | OCR_VDD_30_31 | + OCR_VDD_31_32 | OCR_VDD_32_33; + if (f8) { /* if not legacy card */ + arg |= SD_ACMD41_HCS; + } + + /* Check response */ + if (!sdhc_send_cmd(state, SD_MCI_ACMD41_SD_SEND_OP_COND, arg)) { + return false; + } + response = SDHC_DEV->RR[0].reg; + if (response & OCR_POWER_UP_BUSY) { + /* Card is ready */ + if ((response & OCR_CCS) != 0) { + state->type |= CARD_TYPE_HC; + } + break; + } + } while (retry--); + + return retry; +} + +/** + * \brief CMD9: Addressed card sends its card-specific + * data (CSD) on the CMD line mci. + * + * \return true if success, otherwise false + */ +static bool _test_capacity(sdhc_state_t *state) +{ + alignas(uint32_t) + uint8_t csd[CSD_REG_BSIZE]; + uint32_t transfer_speed; + + if (!sdhc_send_cmd(state, SDMMC_MCI_CMD9_SEND_CSD, (uint32_t)state->rca << 16)) { + return false; + } + for (int i = 0; i < 4; i++) { + uint32_t *csd32 = (void *)csd; + csd32[i] = __builtin_bswap32(SDHC_DEV->RR[3 - i].reg); + } + transfer_speed = CSD_TRAN_SPEED(&csd[1]); + state->clock = transfer_units[transfer_speed & 0x7] * + transfer_multiplier[(transfer_speed >> 3) & 0xF] * 1000; + /* + * Card Capacity. + * ---------------------------------------------------- + * For normal SD/MMC card: + * sector size is ((device size + 1) * (1 << (device size multiplier + 2)) * (1 << max_read_data_block_length))/512 + * we can rearrange this like this + * sector size is ((device size + 1) * (1 << (device size multiplier + max_read_data_block_length - 7)) + * device_size = SD_CSD_1_0_C_SIZE(&csd[1]) + * device_size_multiplier = SD_CSD_1_0_C_SIZE_MULT(&csd[1]) + * max_read_data_block_length = SD_CSD_1_0_READ_BL_LEN(&csd[1]) + * Number of sectors is bytes/512 + * ---------------------------------------------------- + * For high capacity SD card: + * memory capacity = (C_SIZE+1) * 512K byte + * So number of sectors is ((C_SIZE+1) * 512 * 1024) / 512 + * or 1024 * (C_SIZE+1) + */ + if (CSD_STRUCTURE_VERSION(&csd[1]) >= SD_CSD_VER_2_0) { + state->sectors = (SD_CSD_2_0_C_SIZE(&csd[1]) + 1) * 1024; + } + else { + state->sectors = (SD_CSD_1_0_C_SIZE(&csd[1]) + 1) + * (1 << (SD_CSD_1_0_C_SIZE_MULT(&csd[1]) + SD_CSD_1_0_READ_BL_LEN(&csd[1]) - 7)); + } + + return true; +} + +/** + * @brief ACMD51 - Read the SD Configuration Register. + * + * @note + * SD Card Configuration Register (SCR) provides information on the SD Memory + * Card's special features that were configured into the given card. The size + * of SCR register is 64 bits. + * + * + * @return true if success, otherwise false + */ +static bool _test_version(sdhc_state_t *state) +{ + uint8_t scr[SD_SCR_REG_BSIZE]; + uint32_t *p = (void *)scr; + + /* CMD55 - Indicate to the card that the next command is an + * application specific command rather than a standard command.*/ + if (!sdhc_send_cmd(state, SDMMC_CMD55_APP_CMD, (uint32_t)state->rca << 16)) { + return false; + } + + if (!_init_transfer(state, SD_ACMD51_SEND_SCR, 0, SD_SCR_REG_BSIZE, 1)) { + return false; + } + + for (int words = 0; words < (SD_SCR_REG_BSIZE / 4); words++) { + *p++ = SDHC_DEV->BDPR.reg; + } + + /* Get SD Memory Card - Spec. Version */ + switch (SD_SCR_SD_SPEC(scr)) { + case SD_SCR_SD_SPEC_1_0_01: + state->version = CARD_VER_SD_1_0; + break; + + case SD_SCR_SD_SPEC_1_10: + state->version = CARD_VER_SD_1_10; + break; + + case SD_SCR_SD_SPEC_2_00: + if (SD_SCR_SD_SPEC3(scr) == SD_SCR_SD_SPEC_3_00) { + state->version = CARD_VER_SD_3_0; + } + else { + state->version = CARD_VER_SD_2_0; + } + break; + + default: + state->version = CARD_VER_SD_1_0; + break; + } + + return true; +} + +static bool _init_transfer(sdhc_state_t *state, uint32_t cmd, uint32_t arg, uint16_t block_size, + uint16_t num_blocks) +{ + uint32_t tmr; + uint32_t command; + uint32_t eis; + + /* wait if card is busy */ + while (SDHC_DEV->PSR.reg & (SDHC_PSR_CMDINHC | SDHC_PSR_CMDINHD)) {} + + if (cmd & MCI_CMD_WRITE) { + tmr = SDHC_TMR_DTDSEL_WRITE; + SDHC_DEV->NISIER.reg = SDHC_NISTR_BWRRDY | NISTR_CARD_DETECT; + } + else { + tmr = SDHC_TMR_DTDSEL_READ; + SDHC_DEV->NISIER.reg = SDHC_NISTR_BRDRDY | NISTR_CARD_DETECT; + } + + if (cmd & MCI_CMD_SDIO_BYTE) { + tmr |= SDHC_TMR_MSBSEL_SINGLE; + } + else if (cmd & MCI_CMD_SDIO_BLOCK) { + tmr |= SDHC_TMR_BCEN | SDHC_TMR_MSBSEL_MULTIPLE; + } + else if (cmd & MCI_CMD_SINGLE_BLOCK) { + tmr |= SDHC_TMR_MSBSEL_SINGLE; + } + else if (cmd & MCI_CMD_MULTI_BLOCK) { + tmr |= SDHC_TMR_BCEN | SDHC_TMR_MSBSEL_MULTIPLE; + if (tmr & SDHC_TMR_DTDSEL_WRITE) { + tmr |= SDHC_TMR_ACMDEN_CMD23; + } else { + tmr |= SDHC_TMR_ACMDEN_CMD12; + } + } + else { + return false; + } + + SDHC_DEV->TMR.reg = tmr; + SDHC_DEV->BSR.reg = SDHC_BSR_BLOCKSIZE(block_size) | SDHC_BSR_BOUNDARY_4K; + SDHC_DEV->BCR.reg = SDHC_BCR_BCNT(num_blocks); + + command = SDHC_CR_DPSEL_DATA; + command |= SDHC_CR_CMDIDX(cmd) | SDHC_CR_CMDTYP_NORMAL; + if (cmd & MCI_RESP_PRESENT) { + if (cmd & MCI_RESP_136) { + command |= SDHC_CR_RESPTYP_136_BIT; + } + else if (cmd & MCI_RESP_BUSY) { + command |= SDHC_CR_RESPTYP_48_BIT_BUSY; + } + else { + command |= SDHC_CR_RESPTYP_48_BIT; + } + } + if (cmd & MCI_CMD_OPENDRAIN) { + SDHC_DEV->MC1R.reg |= SDHC_MC1R_OPD; + } + else { + SDHC_DEV->MC1R.reg &= ~SDHC_MC1R_OPD; + } + + eis = SDHC_EISTR_CMDTEO | SDHC_EISTR_CMDEND | SDHC_EISTR_CMDIDX | SDHC_EISTR_DATTEO + | SDHC_EISTR_DATEND | SDHC_EISTR_ADMA | SDHC_EISTR_ACMD; + if ((cmd & MCI_RESP_CRC) == 0) { + eis |= (SDHC_EISTR_CMDCRC | SDHC_EISTR_DATCRC); + } + + DEBUG("sdhc: send cmd %lx\n", command); + + SDHC_DEV->EISIER.reg = eis; + SDHC_DEV->SSAR.reg = num_blocks; /* Setup block size for Auto CMD23 */ + SDHC_DEV->ARG1R.reg = arg; /* setup the argument register */ + SDHC_DEV->CR.reg = command; /* send command */ + + if (_wait_for_event(state)) { + DEBUG("sdhc error: %x, reset all\n", state->error); + _reset_all(state); + return false; + } + + return true; +} + +/** + * @brief Start a read blocks transfer on the line + * + * dst must be on 4 byte boundary + */ +int sdhc_read_blocks(sdhc_state_t *state, uint32_t address, void *dst, uint16_t num_blocks) +{ + uint32_t cmd; + uint32_t arg; + uint32_t *p = dst; + int res = 0; + + /* card detect should be done differently + * card detect with interrupt and if removed and reinstalled + * set need_init, sdhc_init clears need_init + */ + if (!_card_detect(state)) { + return -ENODEV; + } + + mutex_lock(&state->lock); + + if (state->need_init) { + res = sdhc_init(state); + if (res != 0) { + goto out; + } + } + + if (state->type & CARD_TYPE_HC) { + arg = address; + } + else { + arg = address * SD_MMC_BLOCK_SIZE; + } + + cmd = (1 == num_blocks) + ? SDMMC_CMD17_READ_SINGLE_BLOCK + : SDMMC_CMD18_READ_MULTIPLE_BLOCK; + + if (!_wait_not_busy(state)) { + res = -EBUSY; + goto out; + } + + if (!_init_transfer(state, cmd, arg, SD_MMC_BLOCK_SIZE, num_blocks)) { + res = -EIO; + goto out; + } + + if (SDHC_DEV->RR[0].reg & CARD_STATUS_ERR_RD_WR) { + res = -EIO; + goto out; + } + + int num_words = (num_blocks * SD_MMC_BLOCK_SIZE) / 4; + for (int words = 0; words < num_words; words++) { + while (!SDHC_DEV->PSR.bit.BUFRDEN) {} + *p++ = SDHC_DEV->BDPR.reg; + } + +out: + mutex_unlock(&state->lock); + return res; +} + +/** + * @brief Start a write blocks transfer on the line + * @note The driver will use the DMA available to speed up the transfer. + * (There is no evidence of that.) + * @pre @p src must be on 4 byte boundary + */ +int sdhc_write_blocks(sdhc_state_t *state, uint32_t address, const void *src, + uint16_t num_blocks) +{ + assert(((uintptr_t)src & 3) == 0); + uint32_t cmd; + uint32_t arg; + const uint32_t *p = src; + int res = 0; + + if (!_card_detect(state)) { + return -ENODEV; + } + + mutex_lock(&state->lock); + + if (state->need_init) { + res = sdhc_init(state); + if (res != 0) { + goto out; + } + } + + /* + * SDSC Card (CCS=0) uses byte unit address, + * SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit). + */ + if (state->type & CARD_TYPE_HC) { + arg = address; + } + else { + arg = address * SD_MMC_BLOCK_SIZE; + } + + cmd = (1 == num_blocks) ? SDMMC_CMD24_WRITE_BLOCK : SDMMC_CMD25_WRITE_MULTIPLE_BLOCK; + + if (!_wait_not_busy(state)) { + res = -EBUSY; + goto out; + } + + if (!_init_transfer(state, cmd, arg, SD_MMC_BLOCK_SIZE, num_blocks)) { + res = -EIO; + goto out; + } + + if (SDHC_DEV->RR[0].reg & CARD_STATUS_ERR_RD_WR) { + res = -EIO; + goto out; + } + + /* Write data */ + int num_words = (num_blocks * SD_MMC_BLOCK_SIZE) / 4; + for (int words = 0; words < num_words; words++) { + while (!SDHC_DEV->PSR.bit.BUFWREN) {} + SDHC_DEV->BDPR.reg = *p++; + } + +out: + mutex_unlock(&state->lock); + return res; +} + +int sdhc_erase_blocks(sdhc_state_t *state, uint32_t start, uint16_t num_blocks) +{ + uint32_t end = start + num_blocks - 1; + int res = 0; + + if (!_card_detect(state)) { + return -ENODEV; + } + + mutex_lock(&state->lock); + + if (state->need_init) { + res = sdhc_init(state); + if (res != 0) { + goto out; + } + } + + /* + * SDSC Card (CCS=0) uses byte unit address, + * SDHC and SDXC Cards (CCS=1) use block unit address (512 Bytes unit). + */ + if (!(state->type & CARD_TYPE_HC)) { + start *= SD_MMC_BLOCK_SIZE; + end *= SD_MMC_BLOCK_SIZE; + } + + if (!_wait_not_busy(state)) { + res = -EBUSY; + goto out; + } + + sdhc_send_cmd(state, SD_CMD32_ERASE_WR_BLK_START, start); + sdhc_send_cmd(state, SD_CMD33_ERASE_WR_BLK_END, end); + if (!sdhc_send_cmd(state, SDMMC_CMD38_ERASE, 0)) { + res = -EIO; + } + +out: + mutex_unlock(&state->lock); + return res; +} + +/** + * @brief CMD13 - Addressed card sends its status register. + * This function waits the clear of the busy flag + * + * @return true if success, otherwise false + */ +static bool _wait_not_busy(sdhc_state_t *state) +{ + uint32_t timeout; + + /* Wait for data ready status. + * Nec timing: 0 to unlimited + * However a timeout is used. + * 200 000 * 8 cycles + */ + timeout = 200000; + do { + if (!sdhc_send_cmd(state, SDMMC_MCI_CMD13_SEND_STATUS, (uint32_t)state->rca << 16)) { + return false; + } + /* Check busy flag */ + if (SDHC_DEV->RR[0].reg & CARD_STATUS_READY_FOR_DATA) { + break; + } + if (timeout-- == 0) { + return false; + } + } while (1); + + return true; +} + +/** + * @brief Try to get the SDIO card's operating condition + * - CMD5 to read OCR NF field + * - CMD5 to wait OCR power up busy + * - CMD5 to read OCR MP field + * sd_mmc_card->type is updated + * + * @return true if success, otherwise false + */ +static bool sdio_test_type(sdhc_state_t *state) +{ + uint32_t response; + uint32_t cmd5_retry = 5000; + + /* CMD5 - SDIO send operation condition (OCR) command. */ + if (!sdhc_send_cmd(state, SDIO_CMD5_SEND_OP_COND, 0)) { + return true; /* No error but card type not updated */ + } + response = SDHC_DEV->RR[0].reg; + if ((response & OCR_SDIO_NF) == 0) { + return true; /* No error but card type not updated */ + } + + /* + * Wait card ready + * Timeout 1s = 400KHz / ((6+4)*8) cylces = 5000 retry + * 6 = cmd byte size + * 4(SPI) 6(MCI) = response byte size + */ + while (1) { + response &= OCR_VDD_27_28 | OCR_VDD_28_29 | OCR_VDD_29_30 + | OCR_VDD_30_31 | OCR_VDD_31_32 | OCR_VDD_32_33; + /* CMD5 - SDIO send operation condition (OCR) command.*/ + if (!sdhc_send_cmd(state, SDIO_CMD5_SEND_OP_COND, response)) { + return false; + } + response = SDHC_DEV->RR[0].reg; + if ((response & OCR_POWER_UP_BUSY) == OCR_POWER_UP_BUSY) { + break; + } + if (cmd5_retry-- == 0) { + return false; + } + } + /* Update card type at the end of busy */ + if ((response & OCR_SDIO_MP) > 0) { + state->type = CARD_TYPE_SD_COMBO; + } + else { + state->type = CARD_TYPE_SDIO; + } + return true; +} + +static bool _test_high_speed(sdhc_state_t *state) +{ + alignas(uint32_t) + uint8_t switch_status[SD_SW_STATUS_BSIZE] = { 0 }; + uint32_t *p = (void *)switch_status; + + if ((state->type & CARD_TYPE_SD) && (state->version > CARD_VER_SD_1_0)) { + + if (!_init_transfer(state, SD_CMD6_SWITCH_FUNC, + SD_CMD6_MODE_SWITCH | SD_CMD6_GRP6_NO_INFLUENCE | + SD_CMD6_GRP5_NO_INFLUENCE | SD_CMD6_GRP4_NO_INFLUENCE | + SD_CMD6_GRP3_NO_INFLUENCE | SD_CMD6_GRP2_DEFAULT | + SD_CMD6_GRP1_HIGH_SPEED, SD_SW_STATUS_BSIZE, 1)) { + + return false; + } + + for (int words = 0; words < (SD_SW_STATUS_BSIZE / 4); words++) { + *p++ = SDHC_DEV->BDPR.reg; + } + + if (SDHC_DEV->RR[0].reg & CARD_STATUS_SWITCH_ERROR) { + return false; + } + + if (SD_SW_STATUS_FUN_GRP1_RC(switch_status) == SD_SW_STATUS_FUN_GRP_RC_ERROR) { + /* No supported, it is not a protocol error */ + return true; + } + + if (SD_SW_STATUS_FUN_GRP1_BUSY(switch_status)) { + return false; + } + + /* CMD6 function switching period is within 8 clocks + * after the end bit of status data.*/ + _delay(100); + } + state->high_speed = true; + state->clock *= 2; /* turbo clock */ + return true; +} + +static bool _test_bus_width(sdhc_state_t *state) +{ + /** + * A SD memory card always supports bus 4bit + * A SD COMBO card always supports bus 4bit + * A SDIO Full-Speed alone always supports 4bit + * A SDIO Low-Speed alone can supports 4bit (Optional) + */ + if (state->type & CARD_TYPE_SD) { + /* CMD55 - Indicate to the card that the next command is an + * application specific command rather than a standard command.*/ + if (!sdhc_send_cmd(state, SDMMC_CMD55_APP_CMD, (uint32_t)state->rca << 16)) { + return false; + } + if (!sdhc_send_cmd(state, SD_ACMD6_SET_BUS_WIDTH, SD_ACMD6_4B)) { + return false; + } + } + state->bus_width = 4; + return true; +} + +static void _isr(sdhc_state_t *state) +{ + uint16_t events = (SDHC_DEV->NISIER.reg & ~NISTR_CARD_DETECT) + | SDHC_NISTR_ERRINT; + + if (SDHC_DEV->EISTR.reg) { + state->error = SDHC_DEV->EISTR.reg; + } + + DEBUG("NISTR: %x\n", SDHC_DEV->NISTR.reg); + DEBUG("EISTR: %x\n", SDHC_DEV->EISTR.reg); + DEBUG("ACESR: %x\n", SDHC_DEV->ACESR.reg); + + /* we got the awaited event */ + if (SDHC_DEV->NISTR.reg & events) { + DEBUG_PUTS("unlock"); + mutex_unlock(&state->sync); + } + + /* if card got inserted we need to re-init */ + if (SDHC_DEV->NISTR.reg & NISTR_CARD_DETECT) { + DEBUG_PUTS("card presence changed"); + state->need_init = true; + } + + SDHC_DEV->EISTR.reg = SDHC_EISTR_MASK; + SDHC_DEV->NISTR.reg = SDHC_NISTR_MASK; + + cortexm_isr_end(); +} + +#ifdef SDHC_DEV_ISR +void SDHC_DEV_ISR(void) +{ + if (SDHC_DEV == SDHC0) { + _isr(isr_ctx_0); + } + if (SDHC_DEV == SDHC1) { + _isr(isr_ctx_1); + } +} +#else +void isr_sdhc0(void) +{ + _isr(isr_ctx_0); +} + +void isr_sdhc1(void) +{ + _isr(isr_ctx_1); +} +#endif diff --git a/cpu/sam0_common/sam0_sdhc/vendor/sd_mmc_protocol.h b/cpu/sam0_common/sam0_sdhc/vendor/sd_mmc_protocol.h new file mode 100644 index 0000000000..8ca47990ba --- /dev/null +++ b/cpu/sam0_common/sam0_sdhc/vendor/sd_mmc_protocol.h @@ -0,0 +1,1015 @@ +/** + * \file + * + * \brief SD/MMC protocol definitions. + * + * Copyright (c) 2014-2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef SD_MMC_PROTOCOL_H_INCLUDED +#define SD_MMC_PROTOCOL_H_INCLUDED + +#include +#include +#include +#include + +/** + * \addtogroup sd_mmc_protocol SD/MMC Protocol Definition + * \ingroup sd_mmc_stack_group + * @{ + */ + +// SD/MMC/SDIO default clock frequency for initialization (400KHz) +#define SDMMC_CLOCK_INIT 400000 + +/** + * \name Macros for command definition + * + * Commands types: + * - broadcast commands (bc), no response + * - broadcast commands with response (bcr) (Note: No open drain on SD card) + * - addressed (point-to-point) commands (ac), no data transfer on DAT lines + * - addressed (point-to-point) data transfer commands (adtc), data transfer + * on DAT lines + * + * Specific MMC norms: + * CMD1, CMD2 & CMD3 are processed in the open-drain mode. + * The CMD line is driven with push-pull drivers. + * + * Specific SD norms: + * There is no open drain mode in SD memory card. + * + *************************************** + * Responses types: + * + * R1, R3, R4 & R5 use a 48 bits response protected by a 7bit CRC checksum + * - R1 receiv data not specified + * - R3 receiv OCR + * - R4, R5 RCA management (MMC only) + * - R6, R7 RCA management (SD only) + * + * R1b assert the BUSY signal and respond with R1. + * If the busy signal is asserted, it is done two clock cycles (Nsr time) + * after the end bit of the command. The DAT0 line is driven low. + * DAT1-DAT7 lines are driven by the card though their values are not relevant. + * + * R2 use a 136 bits response protected by a 7bit CRC checksum + * The content is CID or CSD + * + * Specific MMC norms: + * - R4 (Fast I/O) return RCA + * - R5 (interrupt request) return RCA null + * + * Specific SD norms: + * - R6 (Published RCA) return RCA + * - R7 (Card interface condition) return RCA null + * + * @{ + */ + +//! Value to define a SD/MMC/SDIO command +typedef uint32_t sdmmc_cmd_def_t; + +//! \name Flags used to define a SD/MMC/SDIO command +//! @{ +#define SDMMC_CMD_GET_INDEX(cmd) (cmd & 0x3F) +//! Have response (MCI only) +#define SDMMC_RESP_PRESENT (1lu << 8) +//! 8 bit response (SPI only) +#define SDMMC_RESP_8 (1lu << 9) +//! 32 bit response (SPI only) +#define SDMMC_RESP_32 (1lu << 10) +//! 136 bit response (MCI only) +#define SDMMC_RESP_136 (1lu << 11) +//! Expect valid crc (MCI only) +#define SDMMC_RESP_CRC (1lu << 12) +//! Card may send busy +#define SDMMC_RESP_BUSY (1lu << 13) +// Open drain for a braodcast command (bc) +// or to enter in inactive state (MCI only) +#define SDMMC_CMD_OPENDRAIN (1lu << 14) +//! To signal a data write operation +#define SDMMC_CMD_WRITE (1lu << 15) +//! To signal a SDIO tranfer in multi byte mode +#define SDMMC_CMD_SDIO_BYTE (1lu << 16) +//! To signal a SDIO tranfer in block mode +#define SDMMC_CMD_SDIO_BLOCK (1lu << 17) +//! To signal a data transfer in stream mode +#define SDMMC_CMD_STREAM (1lu << 18) +//! To signal a data transfer in single block mode +#define SDMMC_CMD_SINGLE_BLOCK (1lu << 19) +//! To signal a data transfer in multi block mode +#define SDMMC_CMD_MULTI_BLOCK (1lu << 20) +//! @} + +//! \name Set of flags to define a reponse type +//! @{ +#define SDMMC_CMD_NO_RESP (0) +#define SDMMC_CMD_R1 (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC) +#define SDMMC_CMD_R1B (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC | SDMMC_RESP_BUSY) +#define SDMMC_CMD_R2 (SDMMC_RESP_PRESENT | SDMMC_RESP_8 | SDMMC_RESP_136 | SDMMC_RESP_CRC) +#define SDMMC_CMD_R3 (SDMMC_RESP_PRESENT | SDMMC_RESP_32) +#define SDMMC_CMD_R4 (SDMMC_RESP_PRESENT | SDMMC_RESP_32) +#define SDMMC_CMD_R5 (SDMMC_RESP_PRESENT | SDMMC_RESP_8 | SDMMC_RESP_CRC) +#define SDMMC_CMD_R6 (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC) +#define SDMMC_CMD_R7 (SDMMC_RESP_PRESENT | SDMMC_RESP_32 | SDMMC_RESP_CRC) +//! @} + +//! \name SD/MMC/SDIO command definitions +//! SDMMC_CMDx are include in SD and MMC norms +//! MMC_CMDx are include in MMC norms only +//! SD_CMDx are include in SD norms only +//! SDIO_CMDx are include in SDIO norms only +//! @{ + +/* + * --- Basic commands and read-stream command (class 0 and class 1) --- + */ + +/** Cmd0(bc): Reset all cards to idle state */ +#define SDMMC_SPI_CMD0_GO_IDLE_STATE (0 | SDMMC_CMD_R1) +#define SDMMC_MCI_CMD0_GO_IDLE_STATE (0 | SDMMC_CMD_NO_RESP | SDMMC_CMD_OPENDRAIN) +/** MMC Cmd1(bcr, R3): Ask the card to send its Operating Conditions */ +#define MMC_SPI_CMD1_SEND_OP_COND (1 | SDMMC_CMD_R1) +#define MMC_MCI_CMD1_SEND_OP_COND (1 | SDMMC_CMD_R3 | SDMMC_CMD_OPENDRAIN) +/** Cmd2(bcr, R2): Ask the card to send its CID number (stuff but arg 0 used) */ +#define SDMMC_CMD2_ALL_SEND_CID (2 | SDMMC_CMD_R2 | SDMMC_CMD_OPENDRAIN) +/** SD Cmd3(bcr, R6): Ask the card to publish a new relative address (RCA) */ +#define SD_CMD3_SEND_RELATIVE_ADDR (3 | SDMMC_CMD_R6 | SDMMC_CMD_OPENDRAIN) +/** MMC Cmd3(ac, R1): Assigns relative address to the card */ +#define MMC_CMD3_SET_RELATIVE_ADDR (3 | SDMMC_CMD_R1) +/** Cmd4(bc): Program the DSR of all cards (MCI only) */ +#define SDMMC_CMD4_SET_DSR (4 | SDMMC_CMD_NO_RESP) +/** MMC Cmd5(ac, R1b): Toggle the card between Sleep state and Standby state. */ +#define MMC_CMD5_SLEEP_AWAKE (5 | SDMMC_CMD_R1B) +/** Cmd7(ac, R1/R1b): Select/Deselect card + * For SD: R1b only from the selected card. + * For MMC: R1 while selecting from Stand-By State to Transfer State; + * R1b while selecting from Disconnected State to Programming State. + */ +#define SDMMC_CMD7_SELECT_CARD_CMD (7 | SDMMC_CMD_R1B) +#define SDMMC_CMD7_DESELECT_CARD_CMD (7 | SDMMC_CMD_R1) +/** MMC Cmd8(adtc, R1): Send EXT_CSD register as a block of data */ +#define MMC_CMD8_SEND_EXT_CSD (8 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK) +/** SD Cmd8(bcr, R7) : Send SD Memory Card interface condition */ +#define SD_CMD8_SEND_IF_COND (8 | SDMMC_CMD_R7 | SDMMC_CMD_OPENDRAIN) +/** Cmd9 SPI (R1): Addressed card sends its card-specific data (CSD) */ +#define SDMMC_SPI_CMD9_SEND_CSD (9 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK) +/** Cmd9 MCI (ac, R2): Addressed card sends its card-specific data (CSD) */ +#define SDMMC_MCI_CMD9_SEND_CSD (9 | SDMMC_CMD_R2) +/** Cmd10(ac, R2): Addressed card sends its card identification (CID) */ +#define SDMMC_CMD10_SEND_CID (10 | SDMMC_CMD_R2) +/** + * MMC Cmd11(adtc, R1): Read data stream from the card, starting at the given + * address, until a STOP_TRANSMISSION follows. + */ +#define MMC_CMD11_READ_DAT_UNTIL_STOP (11 | SDMMC_CMD_R1) +/* SD Cmd11 MCI (ac, R1): Voltage switching */ +#define SD_CMD11_READ_DAT_UNTIL_STOP (11 | SDMMC_CMD_R1) +/** Cmd12(ac, R1b): Force the card to stop transmission */ +#define SDMMC_CMD12_STOP_TRANSMISSION (12 | SDMMC_CMD_R1B) +/** Cmd13(R2): Addressed card sends its status register. */ +#define SDMMC_SPI_CMD13_SEND_STATUS (13 | SDMMC_CMD_R2) +/** Cmd13(ac, R1): Addressed card sends its status register. */ +#define SDMMC_MCI_CMD13_SEND_STATUS (13 | SDMMC_CMD_R1) +/** MMC Cmd14(adtc, R1): Read the reversed bus testing data pattern from a card. */ +#define MMC_CMD14_BUSTEST_R (14 | SDMMC_CMD_R1) +/** Cmd15(ac): Send an addressed card into the Inactive State. */ +// Note: It is a ac cmd, but it must be send like bc cmd to open drain +#define SDMMC_CMD15_GO_INACTIVE_STATE (15 | SDMMC_CMD_NO_RESP | SDMMC_CMD_OPENDRAIN) +/** MMC Cmd19(adtc, R1): Send the bus test data pattern */ +#define MMC_CMD19_BUSTEST_W (19 | SDMMC_CMD_R1) +/** Cmd58(R3): Reads the OCR register of a card */ +#define SDMMC_SPI_CMD58_READ_OCR (58 | SDMMC_CMD_R3) +/** Cmd59(R1): Turns the CRC option on or off */ +#define SDMMC_SPI_CMD59_CRC_ON_OFF (59 | SDMMC_CMD_R1) + +/* + * --- Block-oriented read commands (class 2) --- + */ +/** Cmd16(ac, R1): Set the block length (in bytes) */ +#define SDMMC_CMD16_SET_BLOCKLEN (16 | SDMMC_CMD_R1) +/** Cmd17(adtc, R1): Read single block */ +#define SDMMC_CMD17_READ_SINGLE_BLOCK (17 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK) +/** Cmd18(adtc, R1): Read multiple block */ +#define SDMMC_CMD18_READ_MULTIPLE_BLOCK (18 | SDMMC_CMD_R1 | SDMMC_CMD_MULTI_BLOCK) + +/* + * --- Sequential write commands (class 3) --- + */ + +/** + * MMC Cmd20(adtc, R1): Write a data stream from the host, starting at the + * given address, until a STOP_TRANSMISSION follows. + */ +#define MMC_CMD20_WRITE_DAT_UNTIL_STOP (20 | SDMMC_CMD_R1) + +/* + * --- Block-oriented write commands (class 4) --- + */ +/** MMC Cmd23(ac, R1): Set block count */ +#define MMC_CMD23_SET_BLOCK_COUNT (23 | SDMMC_CMD_R1) +/** Cmd24(adtc, R1): Write block */ +#define SDMMC_CMD24_WRITE_BLOCK (24 | SDMMC_CMD_R1 | SDMMC_CMD_WRITE | SDMMC_CMD_SINGLE_BLOCK) +/** Cmd25(adtc, R1): Write multiple block */ +#define SDMMC_CMD25_WRITE_MULTIPLE_BLOCK (25 | SDMMC_CMD_R1 | SDMMC_CMD_WRITE | SDMMC_CMD_MULTI_BLOCK) +/** MMC Cmd26(adtc, R1): Programming of the card identification register. */ +#define MMC_CMD26_PROGRAM_CID (26 | SDMMC_CMD_R1) +/** Cmd27(adtc, R1): Programming of the programmable bits of the CSD. */ +#define SDMMC_CMD27_PROGRAM_CSD (27 | SDMMC_CMD_R1) + +/* + * --- Erase commands (class 5) --- + */ +/** SD Cmd32(ac, R1): */ +#define SD_CMD32_ERASE_WR_BLK_START (32 | SDMMC_CMD_R1) +/** SD Cmd33(ac, R1): */ +#define SD_CMD33_ERASE_WR_BLK_END (33 | SDMMC_CMD_R1) +/** MMC Cmd35(ac, R1): */ +#define MMC_CMD35_ERASE_GROUP_START (35 | SDMMC_CMD_R1) +/** MMC Cmd36(ac, R1): */ +#define MMC_CMD36_ERASE_GROUP_END (36 | SDMMC_CMD_R1) +/** Cmd38(ac, R1B): */ +#define SDMMC_CMD38_ERASE (38 | SDMMC_CMD_R1B) + +/* + * --- Block Oriented Write Protection Commands (class 6) --- + */ +/** Cmd28(ac, R1b): Set write protection */ +#define SDMMC_CMD28_SET_WRITE_PROT (28 | SDMMC_CMD_R1B) +/** Cmd29(ac, R1b): Clr write protection */ +#define SDMMC_CMD29_CLR_WRITE_PROT (29 | SDMMC_CMD_R1B) +/** Cmd30(adtc, R1b): Send write protection */ +#define SDMMC_CMD30_SEND_WRITE_PROT (30 | SDMMC_CMD_R1) + +/* + * --- Lock Card (class 7) --- + */ +/** Cmd42(adtc, R1): Used to set/reset the password or lock/unlock the card. */ +#define SDMMC_CMD42_LOCK_UNLOCK (42 | SDMMC_CMD_R1) + +/* + * --- Application-specific commands (class 8) --- + */ +/** + * Cmd55(ac, R1): Indicate to the card that the next command is an application + * specific command rather than a standard command. + */ +#define SDMMC_CMD55_APP_CMD (55 | SDMMC_CMD_R1) +/** + * Cmd 56(adtc, R1): Used either to transfer a data block to the card or to get + * a data block from the card for general purpose/application specific commands. + */ +#define SDMMC_CMD56_GEN_CMD (56 | SDMMC_CMD_R1) + +/** + * MMC Cmd6(ac, R1b) : Switche the mode of operation of the selected card + * or modifies the EXT_CSD registers. + */ +#define MMC_CMD6_SWITCH (6 | SDMMC_CMD_R1B) +/** + * SD Cmd6(adtc, R1) : Check switchable function (mode 0) + * and switch card function (mode 1). + */ +#define SD_CMD6_SWITCH_FUNC (6 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK) +/** ACMD6(ac, R1): Define the data bus width */ +#define SD_ACMD6_SET_BUS_WIDTH (6 | SDMMC_CMD_R1) +/** ACMD13(adtc, R1): Send the SD Status. */ +#define SD_ACMD13_SD_STATUS (13 | SDMMC_CMD_R1) +/** + * ACMD22(adtc, R1): Send the number of the written (with-out errors) write + * blocks. + */ +#define SD_ACMD22_SEND_NUM_WR_BLOCKS (22 | SDMMC_CMD_R1) +/** + * ACMD23(ac, R1): Set the number of write blocks to be pre-erased before + * writing + */ +#define SD_ACMD23_SET_WR_BLK_ERASE_COUNT (23 | SDMMC_CMD_R1) +/** + * ACMD41(bcr, R3): Send host capacity support information (HCS) and asks the + * accessed card to send its operating condition register (OCR) content + * in the response + */ +#define SD_MCI_ACMD41_SD_SEND_OP_COND (41 | SDMMC_CMD_R3 | SDMMC_CMD_OPENDRAIN) +/** + * ACMD41(R1): Send host capacity support information (HCS) and activates the + * card's initilization process + */ +#define SD_SPI_ACMD41_SD_SEND_OP_COND (41 | SDMMC_CMD_R1) +/** + * ACMD42(ac, R1): Connect[1]/Disconnect[0] the 50 KOhm pull-up resistor on + * CD/DAT3 (pin 1) of the card. + */ +#define SD_ACMD42_SET_CLR_CARD_DETECT (42 | SDMMC_CMD_R1) +/** ACMD51(adtc, R1): Read the SD Configuration Register (SCR). */ +#define SD_ACMD51_SEND_SCR (51 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK) + +/* + * --- I/O mode commands (class 9) --- + */ +/** MMC Cmd39(ac, R4): Used to write and read 8 bit (register) data fields. */ +#define MMC_CMD39_FAST_IO (39 | SDMMC_CMD_R4) +/** MMC Cmd40(bcr, R5): Set the system into interrupt mode */ +#define MMC_CMD40_GO_IRQ_STATE (40 | SDMMC_CMD_R5 | SDMMC_CMD_OPENDRAIN) +/** SDIO Cmd5(R4): Send operation condition */ +#define SDIO_CMD5_SEND_OP_COND (5 | SDMMC_CMD_R4 | SDMMC_CMD_OPENDRAIN) +/** SDIO CMD52(R5): Direct IO read/write */ +#define SDIO_CMD52_IO_RW_DIRECT (52 | SDMMC_CMD_R5) +/** SDIO CMD53(R5): Extended IO read/write */ +#define SDIO_CMD53_IO_R_BYTE_EXTENDED (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BYTE) +#define SDIO_CMD53_IO_W_BYTE_EXTENDED (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BYTE | SDMMC_CMD_WRITE) +#define SDIO_CMD53_IO_R_BLOCK_EXTENDED (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BLOCK) +#define SDIO_CMD53_IO_W_BLOCK_EXTENDED (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BLOCK | SDMMC_CMD_WRITE) +//! @} +//! @} + +//! \name Macros for command argument definition +//! @{ + +//! \name MMC CMD6 argument structure +//! @{ +//! [31:26] Set to 0 +//! [25:24] Access +#define MMC_CMD6_ACCESS_COMMAND_SET (0lu << 24) +#define MMC_CMD6_ACCESS_SET_BITS (1lu << 24) +#define MMC_CMD6_ACCESS_CLEAR_BITS (2lu << 24) +#define MMC_CMD6_ACCESS_WRITE_BYTE (3lu << 24) +//! [23:16] Index for Mode Segment +#define MMC_CMD6_INDEX_CMD_SET (EXT_CSD_CMD_SET_INDEX << 16) +#define MMC_CMD6_INDEX_CMD_SET_REV (EXT_CSD_CMD_SET_REV_INDEX << 16) +#define MMC_CMD6_INDEX_POWER_CLASS (EXT_CSD_POWER_CLASS_INDEX << 16) +#define MMC_CMD6_INDEX_HS_TIMING (EXT_CSD_HS_TIMING_INDEX << 16) +#define MMC_CMD6_INDEX_BUS_WIDTH (EXT_CSD_BUS_WIDTH_INDEX << 16) +#define MMC_CMD6_INDEX_ERASED_MEM_CONT (EXT_CSD_ERASED_MEM_CONT_INDEX << 16) +#define MMC_CMD6_INDEX_BOOT_CONFIG (EXT_CSD_BOOT_CONFIG_INDEX << 16) +#define MMC_CMD6_INDEX_BOOT_BUS_WIDTH (EXT_CSD_BOOT_BUS_WIDTH_INDEX << 16) +#define MMC_CMD6_INDEX_ERASE_GROUP_DEF (EXT_CSD_ERASE_GROUP_DEF_INDEX << 16) +//! [15:8] Value +#define MMC_CMD6_VALUE_BUS_WIDTH_1BIT (0x0lu << 8) +#define MMC_CMD6_VALUE_BUS_WIDTH_4BIT (0x1lu << 8) +#define MMC_CMD6_VALUE_BUS_WIDTH_8BIT (0x2lu << 8) +#define MMC_CMD6_VALUE_HS_TIMING_ENABLE (0x1lu << 8) +#define MMC_CMD6_VALUE_HS_TIMING_DISABLE (0x0lu << 8) +//! [7:3] Set to 0 +//! [2:0] Cmd Set +//! @} + +//! \name SD CMD6 argument structure +//! @{ +//! CMD6 arg[ 3: 0] function group 1, access mode +#define SD_CMD6_GRP1_HIGH_SPEED (0x1lu << 0) +#define SD_CMD6_GRP1_DEFAULT (0x0lu << 0) +//! CMD6 arg[ 7: 4] function group 2, command system +#define SD_CMD6_GRP2_NO_INFLUENCE (0xFlu << 4) +#define SD_CMD6_GRP2_DEFAULT (0x0lu << 4) +//! CMD6 arg[11: 8] function group 3, 0xF or 0x0 +#define SD_CMD6_GRP3_NO_INFLUENCE (0xFlu << 8) +#define SD_CMD6_GRP3_DEFAULT (0x0lu << 8) +//! CMD6 arg[15:12] function group 4, 0xF or 0x0 +#define SD_CMD6_GRP4_NO_INFLUENCE (0xFlu << 12) +#define SD_CMD6_GRP4_DEFAULT (0x0lu << 12) +//! CMD6 arg[19:16] function group 5, 0xF or 0x0 +#define SD_CMD6_GRP5_NO_INFLUENCE (0xFlu << 16) +#define SD_CMD6_GRP5_DEFAULT (0x0lu << 16) +//! CMD6 arg[23:20] function group 6, 0xF or 0x0 +#define SD_CMD6_GRP6_NO_INFLUENCE (0xFlu << 20) +#define SD_CMD6_GRP6_DEFAULT (0x0lu << 20) +//! CMD6 arg[30:24] reserved 0 +//! CMD6 arg[31 ] Mode, 0: Check, 1: Switch +#define SD_CMD6_MODE_CHECK (0lu << 31) +#define SD_CMD6_MODE_SWITCH (1lu << 31) +//! @} + +//! \name SD CMD8 argument structure +//! @{ +#define SD_CMD8_PATTERN 0xAA +#define SD_CMD8_MASK_PATTERN 0xFF +#define SD_CMD8_HIGH_VOLTAGE 0x100 +#define SD_CMD8_MASK_VOLTAGE 0xF00 +//! @} + +//! \name SD ACMD41 arguments +//! @{ +#define SD_ACMD41_HCS (1lu << 30) //!< (SD) Host Capacity Support + //! @} +//! @name SD ACMD6 arguments +//! @{ +#define SD_ACMD6_1B (0lu) //!< (SD) 1 Bit bus width +#define SD_ACMD6_4B (0b10UL) //!< (SD) 4 Bit bus width + //! @} +//! @} + +//! \name SDIO definitions +//! @{ + +//! \name SDIO state (in R5) +//! @{ +#define SDIO_R5_COM_CRC_ERROR (1lu << 15) /**< CRC check error */ +#define SDIO_R5_ILLEGAL_COMMAND (1lu << 14) /**< Illegal command */ +#define SDIO_R5_STATE (3lu << 12) /**< SDIO R5 state mask */ +#define SDIO_R5_STATE_DIS (0lu << 12) /**< Disabled */ +#define SDIO_R5_STATE_CMD (1lu << 12) /**< DAT lines free */ +#define SDIO_R5_STATE_TRN (2lu << 12) /**< Transfer */ +#define SDIO_R5_STATE_RFU (3lu << 12) /**< Reserved */ +#define SDIO_R5_ERROR (1lu << 11) /**< General error */ +#define SDIO_R5_FUNC_NUM (1lu << 9) /**< Invalid function number */ +#define SDIO_R5_OUT_OF_RANGE (1lu << 8) /**< Argument out of range */ +#define SDIO_R5_STATUS_ERR (SDIO_R5_ERROR | SDIO_R5_FUNC_NUM | SDIO_R5_OUT_OF_RANGE) //!< Errro status bits mask + //! @} + +//! \name SDIO state (in R6) +//! @{ +/** The CRC check of the previous command failed. */ +#define SDIO_R6_COM_CRC_ERROR (1lu << 15) +/** Command not legal for the card state. */ +#define SDIO_R6_ILLEGAL_COMMAND (1lu << 14) +/** A general or an unknown error occurred during the operation. */ +#define SDIO_R6_ERROR (1lu << 13) +/** Status bits mask for SDIO R6 */ +#define SDIO_STATUS_R6 (SDIO_R6_COM_CRC_ERROR | SDIO_R6_ILLEGAL_COMMAND | SDIO_R6_ERROR) +//! @} + +//! \name SDIO CMD52 argument bit offset +//! @{ +//! CMD52 arg[ 7: 0] Write data or stuff bits +#define SDIO_CMD52_WR_DATA 0 +//! CMD52 arg[ 8] Reserved +#define SDIO_CMD52_STUFF0 8 +//! CMD52 arg[25: 9] Register address +#define SDIO_CMD52_REG_ADRR 9 +//! CMD52 arg[ 26] Reserved +#define SDIO_CMD52_STUFF1 26 +//! CMD52 arg[ 27] Read after Write flag +#define SDIO_CMD52_RAW_FLAG 27 +//! CMD52 arg[30:28] Number of the function +#define SDIO_CMD52_FUNCTION_NUM 28 +//! CMD52 arg[ 31] Direction, 1:write, 0:read. +#define SDIO_CMD52_RW_FLAG 31 +#define SDIO_CMD52_READ_FLAG 0 +#define SDIO_CMD52_WRITE_FLAG 1 +//! @} + +//! \name SDIO CMD53 argument structure +//! @{ +/** + * [ 8: 0] Byte mode: number of bytes to transfer, + * 0 cause 512 bytes transfer. + * Block mode: number of blocks to transfer, + * 0 set count to infinite. + */ +#define SDIO_CMD53_COUNT 0 +//! CMD53 arg[25: 9] Start Address I/O register +#define SDIO_CMD53_REG_ADDR 9 +//! CMD53 arg[ 26] 1:Incrementing address, 0: fixed +#define SDIO_CMD53_OP_CODE 26 +//! CMD53 arg[ 27] (Optional) 1:block mode +#define SDIO_CMD53_BLOCK_MODE 27 +//! CMD53 arg[30:28] Number of the function +#define SDIO_CMD53_FUNCTION_NUM 28 +//! CMD53 arg[ 31] Direction, 1:WR, 0:RD +#define SDIO_CMD53_RW_FLAG 31 +#define SDIO_CMD53_READ_FLAG 0 +#define SDIO_CMD53_WRITE_FLAG 1 +//! @} + +//! \name SDIO Functions +//! @{ +#define SDIO_CIA 0 /**< SDIO Function 0 (CIA) */ +#define SDIO_FN0 0 /**< SDIO Function 0 */ +#define SDIO_FN1 1 /**< SDIO Function 1 */ +#define SDIO_FN2 2 /**< SDIO Function 2 */ +#define SDIO_FN3 3 /**< SDIO Function 3 */ +#define SDIO_FN4 4 /**< SDIO Function 4 */ +#define SDIO_FN5 5 /**< SDIO Function 5 */ +#define SDIO_FN6 6 /**< SDIO Function 6 */ +#define SDIO_FN7 7 /**< SDIO Function 7 */ + //! @} + +//! \name SDIO Card Common Control Registers (CCCR) +//! @{ +#define SDIO_CCCR_SDIO_REV 0x00 /**< CCCR/SDIO revision (RO) */ +#define SDIO_CCCR_REV (0xFlu << 0) /**< CCCR/FBR Version */ +#define SDIO_CCCR_REV_1_00 (0x0lu << 0) /**< CCCR/FBR Version 1.00 */ +#define SDIO_CCCR_REV_1_10 (0x1lu << 0) /**< CCCR/FBR Version 1.10 */ +#define SDIO_CCCR_REV_2_00 (0x2lu << 0) /**< CCCR/FBR Version 2.00 */ +#define SDIO_CCCR_REV_3_00 (0x3lu << 0) /**< CCCR/FBR Version 3.00 */ +#define SDIO_SDIO_REV (0xFlu << 4) /**< SDIO Spec */ +#define SDIO_SDIO_REV_1_00 (0x0lu << 4) /**< SDIO Spec 1.00 */ +#define SDIO_SDIO_REV_1_10 (0x1lu << 4) /**< SDIO Spec 1.10 */ +#define SDIO_SDIO_REV_1_20 (0x2lu << 4) /**< SDIO Spec 1.20(unreleased) */ +#define SDIO_SDIO_REV_2_00 (0x3lu << 4) /**< SDIO Spec Version 2.00 */ +#define SDIO_SDIO_REV_3_00 (0x4lu << 4) /**< SDIO Spec Version 3.00 */ +#define SDIO_CCCR_SD_REV 0x01 /**< SD Spec Revision (RO) */ +#define SDIO_SD_REV (0xFlu << 0) /**< SD Physical Spec */ +#define SDIO_SD_REV_1_01 (0x0lu << 0) /**< SD 1.01 (Mar 2000) */ +#define SDIO_SD_REV_1_10 (0x1lu << 0) /**< SD 1.10 (Oct 2004) */ +#define SDIO_SD_REV_2_00 (0x2lu << 0) /**< SD 2.00 (May 2006) */ +#define SDIO_SD_REV_3_00 (0x3lu << 0) /**< SD 3.00 */ +#define SDIO_CCCR_IOE 0x02 /**< I/O Enable (R/W) */ +#define SDIO_IOE (0xFElu << 1) /**< Functions Enable/Disable */ +#define SDIO_IOE_FN1 (0x1lu << 1) /**< Function 1 Enable/Disable */ +#define SDIO_IOE_FN2 (0x1lu << 2) /**< Function 2 Enable/Disable */ +#define SDIO_IOE_FN3 (0x1lu << 3) /**< Function 3 Enable/Disable */ +#define SDIO_IOE_FN4 (0x1lu << 4) /**< Function 4 Enable/Disable */ +#define SDIO_IOE_FN5 (0x1lu << 5) /**< Function 5 Enable/Disable */ +#define SDIO_IOE_FN6 (0x1lu << 6) /**< Function 6 Enable/Disable */ +#define SDIO_IOE_FN7 (0x1lu << 7) /**< Function 7 Enable/Disable */ +#define SDIO_CCCR_IOR 0x03 /**< I/O Ready (RO) */ +#define SDIO_IOR (0xFElu << 1) /**< Functions ready */ +#define SDIO_IOR_FN1 (0x1lu << 1) /**< Function 1 ready */ +#define SDIO_IOR_FN2 (0x1lu << 2) /**< Function 2 ready */ +#define SDIO_IOR_FN3 (0x1lu << 3) /**< Function 3 ready */ +#define SDIO_IOR_FN4 (0x1lu << 4) /**< Function 4 ready */ +#define SDIO_IOR_FN5 (0x1lu << 5) /**< Function 5 ready */ +#define SDIO_IOR_FN6 (0x1lu << 6) /**< Function 6 ready */ +#define SDIO_IOR_FN7 (0x1lu << 7) /**< Function 7 ready */ +#define SDIO_CCCR_IEN 0x04 /**< Int Enable */ +#define SDIO_IENM (0x1lu << 0) /**< Int Enable Master (R/W) */ +#define SDIO_IEN (0xFElu << 1) /**< Functions Int Enable */ +#define SDIO_IEN_FN1 (0x1lu << 1) /**< Function 1 Int Enable */ +#define SDIO_IEN_FN2 (0x1lu << 2) /**< Function 2 Int Enable */ +#define SDIO_IEN_FN3 (0x1lu << 3) /**< Function 3 Int Enable */ +#define SDIO_IEN_FN4 (0x1lu << 4) /**< Function 4 Int Enable */ +#define SDIO_IEN_FN5 (0x1lu << 5) /**< Function 5 Int Enable */ +#define SDIO_IEN_FN6 (0x1lu << 6) /**< Function 6 Int Enable */ +#define SDIO_IEN_FN7 (0x1lu << 7) /**< Function 7 Int Enable */ +#define SDIO_CCCR_INT 0x05 /**< Int Pending */ +#define SDIO_INT (0xFElu << 1) /**< Functions Int pending */ +#define SDIO_INT_FN1 (0x1lu << 1) /**< Function 1 Int pending */ +#define SDIO_INT_FN2 (0x1lu << 2) /**< Function 2 Int pending */ +#define SDIO_INT_FN3 (0x1lu << 3) /**< Function 3 Int pending */ +#define SDIO_INT_FN4 (0x1lu << 4) /**< Function 4 Int pending */ +#define SDIO_INT_FN5 (0x1lu << 5) /**< Function 5 Int pending */ +#define SDIO_INT_FN6 (0x1lu << 6) /**< Function 6 Int pending */ +#define SDIO_INT_FN7 (0x1lu << 7) /**< Function 7 Int pending */ +#define SDIO_CCCR_IOA 0x06 /**< I/O Abort */ +#define SDIO_AS (0x7lu << 0) /**< Abort Select In Order (WO) */ +#define SDIO_AS_FN1 (0x1lu << 0) /**< Abort function 1 IO */ +#define SDIO_AS_FN2 (0x2lu << 0) /**< Abort function 2 IO */ +#define SDIO_AS_FN3 (0x3lu << 0) /**< Abort function 3 IO */ +#define SDIO_AS_FN4 (0x4lu << 0) /**< Abort function 4 IO */ +#define SDIO_AS_FN5 (0x5lu << 0) /**< Abort function 5 IO */ +#define SDIO_AS_FN6 (0x6lu << 0) /**< Abort function 6 IO */ +#define SDIO_AS_FN7 (0x7lu << 0) /**< Abort function 7 IO */ +#define SDIO_RES (0x1lu << 3) /**< IO CARD RESET (WO) */ +#define SDIO_CCCR_BUS_CTRL 0x07 /**< Bus Interface Control */ +#define SDIO_BUSWIDTH (0x3lu << 0) /**< Data bus width (R/W) */ +#define SDIO_BUSWIDTH_1B (0x0lu << 0) /**< 1-bit data bus */ +#define SDIO_BUSWIDTH_4B (0x2lu << 0) /**< 4-bit data bus */ +/** Enable Continuous SPI interrupt (R/W) */ +#define SDIO_BUS_ECSI (0x1lu << 5) +/** Support Continuous SPI interrupt (RO) */ +#define SDIO_BUS_SCSI (0x1lu << 6) +/** Connect(0)/Disconnect(1) pull-up on CD/DAT[3] (R/W) */ +#define SDIO_BUS_CD_DISABLE (0x1lu << 7) +#define SDIO_CCCR_CAP 0x08 /**< Card Capability */ +/** Support Direct Commands during data transfer (RO) */ +#define SDIO_CAP_SDC (0x1lu << 0) +/** Support Multi-Block (RO) */ +#define SDIO_CAP_SMB (0x1lu << 1) +/** Support Read Wait (RO) */ +#define SDIO_CAP_SRW (0x1lu << 2) +/** Support Suspend/Resume (RO) */ +#define SDIO_CAP_SBS (0x1lu << 3) +/** Support interrupt between blocks of data in 4-bit SD mode (RO) */ +#define SDIO_CAP_S4MI (0x1lu << 4) +/** Enable interrupt between blocks of data in 4-bit SD mode (R/W) */ +#define SDIO_CAP_E4MI (0x1lu << 5) +/** Low-Speed Card (RO) */ +#define SDIO_CAP_LSC (0x1lu << 6) +/** 4-bit support for Low-Speed Card (RO) */ +#define SDIO_CAP_4BLS (0x1lu << 7) +/** Pointer to CIS (3B, LSB first) */ +#define SDIO_CCCR_CIS_PTR 0x09 +/** Bus Suspend */ +#define SDIO_CCCR_BUS_SUSPEND 0x0C +/** Bus Status (transfer on DAT[x] lines) (RO) */ +#define SDIO_BS (0x1lu << 0) +/** Bus Release Request/Status (R/W) */ +#define SDIO_BR (0x1lu << 1) +#define SDIO_CCCR_FUN_SEL 0x0D /**< Function select */ +#define SDIO_DF (0x1lu << 7) /**< Resume Data Flag (RO) */ +#define SDIO_FS (0xFlu << 0) /**< Select Function (R/W) */ +#define SDIO_FS_CIA (0x0lu << 0) /**< Select CIA (function 0) */ +#define SDIO_FS_FN1 (0x1lu << 0) /**< Select Function 1 */ +#define SDIO_FS_FN2 (0x2lu << 0) /**< Select Function 2 */ +#define SDIO_FS_FN3 (0x3lu << 0) /**< Select Function 3 */ +#define SDIO_FS_FN4 (0x4lu << 0) /**< Select Function 4 */ +#define SDIO_FS_FN5 (0x5lu << 0) /**< Select Function 5 */ +#define SDIO_FS_FN6 (0x6lu << 0) /**< Select Function 6 */ +#define SDIO_FS_FN7 (0x7lu << 0) /**< Select Function 7 */ +#define SDIO_FS_MEM (0x8lu << 0) /**< Select memory in combo card */ +#define SDIO_CCCR_EXEC 0x0E /**< Exec Flags (RO) */ +#define SDIO_EXM (0x1lu << 0) /**< Executing status of memory */ +#define SDIO_EX (0xFElu << 1) /**< Executing functions status */ +#define SDIO_EX_FN1 (0x1lu << 1) /**< Executing status of func 1 */ +#define SDIO_EX_FN2 (0x1lu << 2) /**< Executing status of func 2 */ +#define SDIO_EX_FN3 (0x1lu << 3) /**< Executing status of func 3 */ +#define SDIO_EX_FN4 (0x1lu << 4) /**< Executing status of func 4 */ +#define SDIO_EX_FN5 (0x1lu << 5) /**< Executing status of func 5 */ +#define SDIO_EX_FN6 (0x1lu << 6) /**< Executing status of func 6 */ +#define SDIO_EX_FN7 (0x1lu << 7) /**< Executing status of func 7 */ +#define SDIO_CCCR_READY 0x0F /**< Ready Flags (RO) */ +#define SDIO_RFM (0x1lu << 0) /**< Ready Flag for memory */ +#define SDIO_RF (0xFElu) /**< Ready Flag for functions */ +#define SDIO_RF_FN1 (0x1lu << 1) /**< Ready Flag for function 1 */ +#define SDIO_RF_FN2 (0x1lu << 2) /**< Ready Flag for function 2 */ +#define SDIO_RF_FN3 (0x1lu << 3) /**< Ready Flag for function 3 */ +#define SDIO_RF_FN4 (0x1lu << 4) /**< Ready Flag for function 4 */ +#define SDIO_RF_FN5 (0x1lu << 5) /**< Ready Flag for function 5 */ +#define SDIO_RF_FN6 (0x1lu << 6) /**< Ready Flag for function 6 */ +#define SDIO_RF_FN7 (0x1lu << 7) /**< Ready Flag for function 7 */ +#define SDIO_CCCR_FN0_BLKSIZ 0x10 /**< FN0 Block Size (2B, LSB first) (R/W) */ +#define SDIO_CCCR_POWER 0x12 /**< Power Control */ +#define SDIO_SMPC (0x1lu << 0) /**< Support Master Power Control*/ +#define SDIO_EMPC (0x1lu << 1) /**< Enable Master Power Control */ +#define SDIO_CCCR_HS 0x13 /**< High-Speed */ +#define SDIO_SHS (0x1lu << 0) /**< Support High-Speed (RO) */ +#define SDIO_EHS (0x1lu << 1) /**< Enable High-Speed (R/W) */ + //! @} + +//! \name SDIO Function Basic Registers (FBR) +//! @{ +#define SDIO_FBR_ADDR(fn, x) (0x100 * (fn) + (x)) +#define SDIO_FBR_CSA_IF 0x0 /**< CSA and function interface code (RO) */ +#define SDIO_IFC (0xFUL << 0) /**< Standard SDIO Fun Interface Code */ +#define SDIO_IFC_NO_IF (0x0UL << 0) /**< No SDIO standard interface */ +#define SDIO_IFC_UART (0x1UL << 0) /**< UART */ +#define SDIO_IFC_TA_BT (0x2UL << 0) /**< Type-A Bluetooth */ +#define SDIO_IFC_TB_BT (0x3UL << 0) /**< Type-B Bluetooth */ +#define SDIO_IFC_GPS (0x4UL << 0) /**< GPS */ +#define SDIO_IFC_CAMERA (0x5UL << 0) /**< Camera */ +#define SDIO_IFC_PHS (0x6UL << 0) /**< PHS */ +#define SDIO_IFC_WLAN (0x7UL << 0) /**< WLAN */ +#define SDIO_IFC_ATA (0x8UL << 0) /**< Embedded SDIO-ATA */ +#define SDIO_IFC_EXT (0xFUL << 0) /**< Check EXT interface code */ +#define SDIO_SCSA (0x1UL << 6) /**< Function supports Code Storage Area (CSA) */ +#define SDIO_FBR_CSA (0x1UL << 7) /**< Function CSA enable */ +#define SDIO_FBR_EXT_IF 0x1 /**< Extended function interface code (RO) */ +#define SDIO_FBR_PWR 0x2 /**< function power control */ +#define SDIO_SPS (0x1UL << 0) /**< function support power selection (RO) */ +#define SDIO_EPS (0x1UL << 1) /**< Low Current Mode/High Current Mode (R/W) */ +#define SDIO_FBR_CIS_PTR 0x9 /**< Address pointer to function CIS (3B, LSB first) (RO) */ +#define SDIO_FBR_CSA_PTR 0xC /**< Address pointer to CSA (3B, LSB first) (R/W) */ +#define SDIO_FBR_CSA_DATA 0xF /**< Read/Write fifo to CSA (R/W) */ +#define SDIO_FBR_BLK_SIZ 0x10 /**< Block size (2B, LSB first) (R/W) */ + //! @} + +//! \name SDIO Card Metaformat +//! @{ +/** Null tuple (PCMCIA 3.1.9) */ +#define SDIO_CISTPL_NULL 0x00 +/** Device tuple (PCMCIA 3.2.2) */ +#define SDIO_CISTPL_DEVICE 0x01 +/** Checksum control (PCMCIA 3.1.1) */ +#define SDIO_CISTPL_CHECKSUM 0x10 +/** Level 1 version (PCMCIA 3.2.10) */ +#define SDIO_CISTPL_VERS_1 0x15 +/** Alternate Language String (PCMCIA 3.2.1) */ +#define SDIO_CISTPL_ALTSTR 0x16 +/** Manufacturer Identification String (PCMCIA 3.2.9) */ +#define SDIO_CISTPL_MANFID 0x20 +/** Function Identification (PCMCIA 3.2.7) */ +#define SDIO_CISTPL_FUNCID 0x21 +/** Function Extensions (PCMCIA 3.2.6) */ +#define SDIO_CISTPL_FUNCE 0x22 +/** Additional information for SDIO (PCMCIA 6.1.2) */ +#define SDIO_CISTPL_SDIO_STD 0x91 +/** Reserved for future SDIO (PCMCIA 6.1.3) */ +#define SDIO_CISTPL_SDIO_EXT 0x92 +/** The End-of-chain Tuple (PCMCIA 3.1.2) */ +#define SDIO_CISTPL_END 0xFF +//! @} + +//! @} + +//! \name CSD, OCR, SCR, Switch status, extend CSD definitions +//! @{ + +/** + * \brief Macro function to extract a bits field from a large SD MMC register + * Used by : CSD, SCR, Switch status + */ +static inline uint32_t SDMMC_UNSTUFF_BITS(uint8_t *reg, uint16_t reg_size, uint16_t pos, uint8_t size) +{ + uint32_t value; + value = reg[((reg_size - pos + 7) / 8) - 1] >> (pos % 8); + if (((pos % 8) + size) > 8) { + value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 2] << (8 - (pos % 8)); + } + if (((pos % 8) + size) > 16) { + value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 3] << (16 - (pos % 8)); + } + if (((pos % 8) + size) > 24) { + value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 4] << (24 - (pos % 8)); + } + value &= ((uint32_t)1 << size) - 1; + return value; +} + +//! \name CSD Fields +//! @{ +#define CSD_REG_BIT_SIZE 128 //!< 128 bits +#define CSD_REG_BSIZE (CSD_REG_BIT_SIZE / 8) //!< 16 bytes +#define CSD_STRUCTURE(csd, pos, size) SDMMC_UNSTUFF_BITS(csd, CSD_REG_BIT_SIZE, pos, size) +#define CSD_STRUCTURE_VERSION(csd) CSD_STRUCTURE(csd, 126, 2) +#define SD_CSD_VER_1_0 0 +#define SD_CSD_VER_2_0 1 +#define MMC_CSD_VER_1_0 0 +#define MMC_CSD_VER_1_1 1 +#define MMC_CSD_VER_1_2 2 +#define CSD_TRAN_SPEED(csd) CSD_STRUCTURE(csd, 96, 8) +#define SD_CSD_1_0_C_SIZE(csd) CSD_STRUCTURE(csd, 62, 12) +#define SD_CSD_1_0_C_SIZE_MULT(csd) CSD_STRUCTURE(csd, 47, 3) +#define SD_CSD_1_0_READ_BL_LEN(csd) CSD_STRUCTURE(csd, 80, 4) +#define SD_CSD_2_0_C_SIZE(csd) CSD_STRUCTURE(csd, 48, 22) +#define MMC_CSD_C_SIZE(csd) CSD_STRUCTURE(csd, 62, 12) +#define MMC_CSD_C_SIZE_MULT(csd) CSD_STRUCTURE(csd, 47, 3) +#define MMC_CSD_READ_BL_LEN(csd) CSD_STRUCTURE(csd, 80, 4) +#define MMC_CSD_SPEC_VERS(csd) CSD_STRUCTURE(csd, 122, 4) +//! @} + +//! \name OCR Register Fields +//! @{ +#define OCR_REG_BSIZE (32 / 8) /**< 32 bits, 4 bytes */ +#define OCR_VDD_170_195 (1lu << 7) +#define OCR_VDD_20_21 (1lu << 8) +#define OCR_VDD_21_22 (1lu << 9) +#define OCR_VDD_22_23 (1lu << 10) +#define OCR_VDD_23_24 (1lu << 11) +#define OCR_VDD_24_25 (1lu << 12) +#define OCR_VDD_25_26 (1lu << 13) +#define OCR_VDD_26_27 (1lu << 14) +#define OCR_VDD_27_28 (1lu << 15) +#define OCR_VDD_28_29 (1lu << 16) +#define OCR_VDD_29_30 (1lu << 17) +#define OCR_VDD_30_31 (1lu << 18) +#define OCR_VDD_31_32 (1lu << 19) +#define OCR_VDD_32_33 (1lu << 20) +#define OCR_VDD_33_34 (1lu << 21) +#define OCR_VDD_34_35 (1lu << 22) +#define OCR_VDD_35_36 (1lu << 23) +#define OCR_SDIO_S18R (1lu << 24) /**< Switching to 1.8V Accepted */ +#define OCR_SDIO_MP (1lu << 27) /**< Memory Present */ +#define OCR_SDIO_NF (7lu << 28) /**< Number of I/O Functions */ +#define OCR_ACCESS_MODE_MASK (3lu << 29) /**< (MMC) Access mode mask */ +#define OCR_ACCESS_MODE_BYTE (0lu << 29) /**< (MMC) Byte access mode */ +#define OCR_ACCESS_MODE_SECTOR (2lu << 29) /**< (MMC) Sector access mode */ +#define OCR_CCS (1lu << 30) /**< (SD) Card Capacity Status */ +#define OCR_POWER_UP_BUSY (1lu << 31) /**< Card power up status bit */ + //! @} + +//! \name SD SCR Register Fields +//! @{ +#define SD_SCR_REG_BIT_SIZE 64 //!< 64 bits +#define SD_SCR_REG_BSIZE (SD_SCR_REG_BIT_SIZE / 8) //!< 8 bytes +#define SD_SCR_STRUCTURE(scr, pos, size) SDMMC_UNSTUFF_BITS(scr, SD_SCR_REG_BIT_SIZE, pos, size) +#define SD_SCR_SCR_STRUCTURE(scr) SD_SCR_STRUCTURE(scr, 60, 4) +#define SD_SCR_SCR_STRUCTURE_1_0 0 +#define SD_SCR_SD_SPEC(scr) SD_SCR_STRUCTURE(scr, 56, 4) +#define SD_SCR_SD_SPEC_1_0_01 0 +#define SD_SCR_SD_SPEC_1_10 1 +#define SD_SCR_SD_SPEC_2_00 2 +#define SD_SCR_DATA_STATUS_AFTER_ERASE(scr) SD_SCR_STRUCTURE(scr, 55, 1) +#define SD_SCR_SD_SECURITY(scr) SD_SCR_STRUCTURE(scr, 52, 3) +#define SD_SCR_SD_SECURITY_NO 0 +#define SD_SCR_SD_SECURITY_NOTUSED 1 +#define SD_SCR_SD_SECURITY_1_01 2 +#define SD_SCR_SD_SECURITY_2_00 3 +#define SD_SCR_SD_SECURITY_3_00 4 +#define SD_SCR_SD_BUS_WIDTHS(scr) SD_SCR_STRUCTURE(scr, 48, 4) +#define SD_SCR_SD_BUS_WIDTH_1BITS (1lu << 0) +#define SD_SCR_SD_BUS_WIDTH_4BITS (1lu << 2) +#define SD_SCR_SD_SPEC3(scr) SD_SCR_STRUCTURE(scr, 47, 1) +#define SD_SCR_SD_SPEC_3_00 1 +#define SD_SCR_SD_EX_SECURITY(scr) SD_SCR_STRUCTURE(scr, 43, 4) +#define SD_SCR_SD_CMD_SUPPORT(scr) SD_SCR_STRUCTURE(scr, 32, 2) +//! @} + +//! \name SD Switch Status Fields +//! @{ +#define SD_SW_STATUS_BIT_SIZE 512 //!< 512 bits +#define SD_SW_STATUS_BSIZE (SD_SW_STATUS_BIT_SIZE / 8) //!< 64 bytes +#define SD_SW_STATUS_STRUCTURE(sd_sw_status, pos, size) \ + SDMMC_UNSTUFF_BITS(sd_sw_status, SD_SW_STATUS_BIT_SIZE, pos, size) +#define SD_SW_STATUS_MAX_CURRENT_CONSUMPTION(status) SD_SW_STATUS_STRUCTURE(status, 496, 16) +#define SD_SW_STATUS_FUN_GRP6_INFO(status) SD_SW_STATUS_STRUCTURE(status, 480, 16) +#define SD_SW_STATUS_FUN_GRP5_INFO(status) SD_SW_STATUS_STRUCTURE(status, 464, 16) +#define SD_SW_STATUS_FUN_GRP4_INFO(status) SD_SW_STATUS_STRUCTURE(status, 448, 16) +#define SD_SW_STATUS_FUN_GRP3_INFO(status) SD_SW_STATUS_STRUCTURE(status, 432, 16) +#define SD_SW_STATUS_FUN_GRP2_INFO(status) SD_SW_STATUS_STRUCTURE(status, 416, 16) +#define SD_SW_STATUS_FUN_GRP1_INFO(status) SD_SW_STATUS_STRUCTURE(status, 400, 16) +#define SD_SW_STATUS_FUN_GRP6_RC(status) SD_SW_STATUS_STRUCTURE(status, 396, 4) +#define SD_SW_STATUS_FUN_GRP5_RC(status) SD_SW_STATUS_STRUCTURE(status, 392, 4) +#define SD_SW_STATUS_FUN_GRP4_RC(status) SD_SW_STATUS_STRUCTURE(status, 388, 4) +#define SD_SW_STATUS_FUN_GRP3_RC(status) SD_SW_STATUS_STRUCTURE(status, 384, 4) +#define SD_SW_STATUS_FUN_GRP2_RC(status) SD_SW_STATUS_STRUCTURE(status, 380, 4) +#define SD_SW_STATUS_FUN_GRP1_RC(status) SD_SW_STATUS_STRUCTURE(status, 376, 4) +#define SD_SW_STATUS_FUN_GRP_RC_ERROR 0xFU +#define SD_SW_STATUS_DATA_STRUCT_VER(status) SD_SW_STATUS_STRUCTURE(status, 368, 8) +#define SD_SW_STATUS_FUN_GRP6_BUSY(status) SD_SW_STATUS_STRUCTURE(status, 352, 16) +#define SD_SW_STATUS_FUN_GRP5_BUSY(status) SD_SW_STATUS_STRUCTURE(status, 336, 16) +#define SD_SW_STATUS_FUN_GRP4_BUSY(status) SD_SW_STATUS_STRUCTURE(status, 320, 16) +#define SD_SW_STATUS_FUN_GRP3_BUSY(status) SD_SW_STATUS_STRUCTURE(status, 304, 16) +#define SD_SW_STATUS_FUN_GRP2_BUSY(status) SD_SW_STATUS_STRUCTURE(status, 288, 16) +#define SD_SW_STATUS_FUN_GRP1_BUSY(status) SD_SW_STATUS_STRUCTURE(status, 272, 16) +//! @} + +//! \name Card Status Fields +//! @{ +#define CARD_STATUS_APP_CMD (1lu << 5) +#define CARD_STATUS_SWITCH_ERROR (1lu << 7) +#define CARD_STATUS_READY_FOR_DATA (1lu << 8) +#define CARD_STATUS_STATE_IDLE (0lu << 9) +#define CARD_STATUS_STATE_READY (1lu << 9) +#define CARD_STATUS_STATE_IDENT (2lu << 9) +#define CARD_STATUS_STATE_STBY (3lu << 9) +#define CARD_STATUS_STATE_TRAN (4lu << 9) +#define CARD_STATUS_STATE_DATA (5lu << 9) +#define CARD_STATUS_STATE_RCV (6lu << 9) +#define CARD_STATUS_STATE_PRG (7lu << 9) +#define CARD_STATUS_STATE_DIS (8lu << 9) +#define CARD_STATUS_STATE (0xFlu << 9) +#define CARD_STATUS_ERASE_RESET (1lu << 13) +#define CARD_STATUS_ECC_DISABLED (1lu << 14) +#define CARD_STATUS_WP_ERASE_SKIP (1lu << 15) +#define CARD_STATUS_CIDCSD_OVERWRITE (1lu << 16) +#define CARD_STATUS_OVERRUN (1lu << 17) +#define CARD_STATUS_UNERRUN (1lu << 18) +#define CARD_STATUS_ERROR (1lu << 19) +#define CARD_STATUS_CC_ERROR (1lu << 20) +#define CARD_STATUS_CARD_ECC_FAILED (1lu << 21) +#define CARD_STATUS_ILLEGAL_COMMAND (1lu << 22) +#define CARD_STATUS_COM_CRC_ERROR (1lu << 23) +#define CARD_STATUS_UNLOCK_FAILED (1lu << 24) +#define CARD_STATUS_CARD_IS_LOCKED (1lu << 25) +#define CARD_STATUS_WP_VIOLATION (1lu << 26) +#define CARD_STATUS_ERASE_PARAM (1lu << 27) +#define CARD_STATUS_ERASE_SEQ_ERROR (1lu << 28) +#define CARD_STATUS_BLOCK_LEN_ERROR (1lu << 29) +#define CARD_STATUS_ADDRESS_MISALIGN (1lu << 30) +#define CARD_STATUS_ADDR_OUT_OF_RANGE (1lu << 31) + +#define CARD_STATUS_ERR_RD_WR \ + (CARD_STATUS_ADDR_OUT_OF_RANGE | CARD_STATUS_ADDRESS_MISALIGN | CARD_STATUS_BLOCK_LEN_ERROR \ + | CARD_STATUS_WP_VIOLATION \ + | CARD_STATUS_ILLEGAL_COMMAND \ + | CARD_STATUS_CC_ERROR \ + | CARD_STATUS_ERROR) +//! @} + +//! \name SD Status Field +//! @{ +#define SD_STATUS_BSIZE (512 / 8) /**< 512 bits, 64bytes */ + //! @} + +//! \name MMC Extended CSD Register Field +//! @{ +#define EXT_CSD_BSIZE 512 /**< 512 bytes. */ +/* Below belongs to Properties Segment */ +#define EXT_CSD_S_CMD_SET_INDEX 504lu +#define EXT_CSD_BOOT_INFO_INDEX 228lu +#define EXT_CSD_BOOT_SIZE_MULTI_INDEX 226lu +#define EXT_CSD_ACC_SIZE_INDEX 225lu +#define EXT_CSD_HC_ERASE_GRP_SIZE_INDEX 224lu +#define EXT_CSD_ERASE_TIMEOUT_MULT_INDEX 223lu +#define EXT_CSD_REL_WR_SEC_C_INDEX 222lu +#define EXT_CSD_HC_WP_GRP_SIZE_INDEX 221lu +#define EXT_CSD_S_C_VCC_INDEX 220lu +#define EXT_CSD_S_C_VCCQ_INDEX 219lu +#define EXT_CSD_S_A_TIMEOUT_INDEX 217lu +#define EXT_CSD_SEC_COUNT_INDEX 212lu +#define EXT_CSD_MIN_PERF_W_8_52_INDEX 210lu +#define EXT_CSD_MIN_PERF_R_8_52_INDEX 209lu +#define EXT_CSD_MIN_PERF_W_8_26_4_52_INDEX 208lu +#define EXT_CSD_MIN_PERF_R_8_26_4_52_INDEX 207lu +#define EXT_CSD_MIN_PERF_W_4_26_INDEX 206lu +#define EXT_CSD_MIN_PERF_R_4_26_INDEX 205lu +#define EXT_CSD_PWR_CL_26_360_INDEX 203lu +#define EXT_CSD_PWR_CL_52_360_INDEX 202lu +#define EXT_CSD_PWR_CL_26_195_INDEX 201lu +#define EXT_CSD_PWR_CL_52_195_INDEX 200lu +#define EXT_CSD_CARD_TYPE_INDEX 196lu +/* MMC card type */ +#define MMC_CTYPE_26MHZ 0x1 +#define MMC_CTYPE_52MHZ 0x2 +#define EXT_CSD_CSD_STRUCTURE_INDEX 194lu +#define EXT_CSD_EXT_CSD_REV_INDEX 192lu + +/* Below belongs to Mode Segment */ +#define EXT_CSD_CMD_SET_INDEX 191lu +#define EXT_CSD_CMD_SET_REV_INDEX 189lu +#define EXT_CSD_POWER_CLASS_INDEX 187lu +#define EXT_CSD_HS_TIMING_INDEX 185lu +#define EXT_CSD_BUS_WIDTH_INDEX 183lu +#define EXT_CSD_ERASED_MEM_CONT_INDEX 181lu +#define EXT_CSD_BOOT_CONFIG_INDEX 179lu +#define EXT_CSD_BOOT_BUS_WIDTH_INDEX 177lu +#define EXT_CSD_ERASE_GROUP_DEF_INDEX 175lu +//! @} +//! @} + +//! \name Definition for SPI mode only +//! @{ + +//! SPI commands start with a start bit "0" and a transmit bit "1" +#define SPI_CMD_ENCODE(x) (0x40 | (x & 0x3F)) + +//! \name Register R1 definition for SPI mode +//! The R1 register is always send after a command. +//! @{ +#define R1_SPI_IDLE (1lu << 0) +#define R1_SPI_ERASE_RESET (1lu << 1) +#define R1_SPI_ILLEGAL_COMMAND (1lu << 2) +#define R1_SPI_COM_CRC (1lu << 3) +#define R1_SPI_ERASE_SEQ (1lu << 4) +#define R1_SPI_ADDRESS (1lu << 5) +#define R1_SPI_PARAMETER (1lu << 6) +// R1 bit 7 is always zero, reuse this bit for error +#define R1_SPI_ERROR (1lu << 7) +//! @} + +//! \name Register R2 definition for SPI mode +//! The R2 register can be send after R1 register. +//! @{ +#define R2_SPI_CARD_LOCKED (1lu << 0) +#define R2_SPI_WP_ERASE_SKIP (1lu << 1) +#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP +#define R2_SPI_ERROR (1lu << 2) +#define R2_SPI_CC_ERROR (1lu << 3) +#define R2_SPI_CARD_ECC_ERROR (1lu << 4) +#define R2_SPI_WP_VIOLATION (1lu << 5) +#define R2_SPI_ERASE_PARAM (1lu << 6) +#define R2_SPI_OUT_OF_RANGE (1lu << 7) +#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE +//! @} + +//! \name Control Tokens in SPI Mode +//! @{ +//! \name Tokens used for a read operation +//! @{ +#define SPI_TOKEN_SINGLE_MULTI_READ 0xFE +#define SPI_TOKEN_DATA_ERROR_VALID(token) (((token)&0xF0) == 0) +#define SPI_TOKEN_DATA_ERROR_ERRORS (0x0F) +#define SPI_TOKEN_DATA_ERROR_ERROR (1lu << 0) +#define SPI_TOKEN_DATA_ERROR_CC_ERROR (1lu << 1) +#define SPI_TOKEN_DATA_ERROR_ECC_ERROR (1lu << 2) +#define SPI_TOKEN_DATA_ERROR_OUT_RANGE (1lu << 3) +//! @} +//! \name Tokens used for a write operation +//! @{ +#define SPI_TOKEN_SINGLE_WRITE 0xFE +#define SPI_TOKEN_MULTI_WRITE 0xFC +#define SPI_TOKEN_STOP_TRAN 0xFD +#define SPI_TOKEN_DATA_RESP_VALID(token) ((((token) & (1 << 4)) == 0) && (((token) & (1 << 0)) == 1)) +#define SPI_TOKEN_DATA_RESP_CODE(token) ((token)&0x1E) +#define SPI_TOKEN_DATA_RESP_ACCEPTED (2lu << 1) +#define SPI_TOKEN_DATA_RESP_CRC_ERR (5lu << 1) +#define SPI_TOKEN_DATA_RESP_WRITE_ERR (6lu << 1) +//! @} +//! @} +//! @} + +//! @} end of sd_mmc_protocol + +#endif /* SD_MMC_PROTOCOL_H_INCLUDED */ diff --git a/cpu/samd5x/include/periph_cpu.h b/cpu/samd5x/include/periph_cpu.h index 9cd91e1b33..e6b20233e7 100644 --- a/cpu/samd5x/include/periph_cpu.h +++ b/cpu/samd5x/include/periph_cpu.h @@ -172,6 +172,27 @@ struct sam0_aux_cfg_mapping { #define SAM0_QSPI_MUX GPIO_MUX_H /**< QSPI mux */ /** @} */ +/** + * @name SDHC pins are fixed + * @{ + */ +#define SAM0_SDHC_MUX GPIO_MUX_I /**< SDHC function */ + +#define SAM0_SDHC0_PIN_SDCMD GPIO_PIN(PA, 8) /**< Command */ +#define SAM0_SDHC0_PIN_SDDAT0 GPIO_PIN(PA, 9) /**< DATA0 */ +#define SAM0_SDHC0_PIN_SDDAT1 GPIO_PIN(PA, 10) /**< DATA1 */ +#define SAM0_SDHC0_PIN_SDDAT2 GPIO_PIN(PA, 11) /**< DATA2 */ +#define SAM0_SDHC0_PIN_SDDAT3 GPIO_PIN(PB, 10) /**< DATA3 */ +#define SAM0_SDHC0_PIN_SDCK GPIO_PIN(PB, 11) /**< Clock */ + +#define SAM0_SDHC1_PIN_SDCMD GPIO_PIN(PA, 20) /**< Command */ +#define SAM0_SDHC1_PIN_SDDAT0 GPIO_PIN(PB, 18) /**< DATA0 */ +#define SAM0_SDHC1_PIN_SDDAT1 GPIO_PIN(PB, 19) /**< DATA1 */ +#define SAM0_SDHC1_PIN_SDDAT2 GPIO_PIN(PB, 20) /**< DATA2 */ +#define SAM0_SDHC1_PIN_SDDAT3 GPIO_PIN(PB, 21) /**< DATA3 */ +#define SAM0_SDHC1_PIN_SDCK GPIO_PIN(PA, 21) /**< Clock */ +/** @} */ + #ifdef __cplusplus } #endif diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 1c57f2cc85..2c6c512208 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -37,6 +37,12 @@ config HAVE_MTD_SPI_NOR help Indicates that a spi-nor MTD is present +config HAVE_SAM0_SDHC + bool + imply MODULE_SAM0_SDHC if MODULE_MTD + help + Indicates that a SAM0 SD Host Controller MTD is present + config HAVE_MTD_SPI_MCI bool imply MODULE_MTD_MCI if MODULE_MTD @@ -86,6 +92,10 @@ config MODULE_MTD_SDCARD bool "MTD interface for SPI SD-Card" depends on MODULE_SDCARD_SPI +config MODULE_SAM0_SDHC + bool "MTD interface for SAM0 SD Host Controller" + depends on CPU_COMMON_SAM0 + endmenu # MTD Interfacs config MODULE_MTD_WRITE_PAGE diff --git a/sys/include/vfs_default.h b/sys/include/vfs_default.h index db6e0def1d..a33a2e920e 100644 --- a/sys/include/vfs_default.h +++ b/sys/include/vfs_default.h @@ -59,7 +59,7 @@ extern "C" { * This can be written to by applications */ #ifndef VFS_DEFAULT_DATA -#if IS_USED(MODULE_MTD_MCI) || IS_USED(MODULE_MTD_SDCARD) +#if IS_USED(MODULE_MTD_MCI) || IS_USED(MODULE_MTD_SDCARD) || IS_USED(MODULE_SAM0_SDHC) #define VFS_DEFAULT_DATA VFS_DEFAULT_SD(0) #else #define VFS_DEFAULT_DATA VFS_DEFAULT_NVM(0)