From 9125aef74d166d5cb2756cf7ee2b9995d5b428ea Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Tue, 1 Aug 2023 09:03:24 +0200 Subject: [PATCH] drivers/mmc: Add support for bus driver Bus driver support is needed for nrf53 but it can be used with any MCU that has SPI driver support (in contrast to just SPI HAL) Signed-off-by: Jerzy Kasenberg --- hw/drivers/mmc/include/mmc/mmc.h | 14 ++ hw/drivers/mmc/pkg.yml | 6 + hw/drivers/mmc/src/mmc.c | 390 ++++++++++++++++++++++++++----- hw/drivers/mmc/syscfg.yml | 40 ++++ 4 files changed, 387 insertions(+), 63 deletions(-) create mode 100644 hw/drivers/mmc/syscfg.yml diff --git a/hw/drivers/mmc/include/mmc/mmc.h b/hw/drivers/mmc/include/mmc/mmc.h index 6975058b39..07f78b594f 100644 --- a/hw/drivers/mmc/include/mmc/mmc.h +++ b/hw/drivers/mmc/include/mmc/mmc.h @@ -22,6 +22,9 @@ #include "os/mynewt.h" #include +#if MYNEWT_VAL(BUS_DRIVER_PRESENT) +#include +#endif #ifdef __cplusplus extern "C" { @@ -96,6 +99,17 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len); int mmc_ioctl(uint8_t mmc_id, uint32_t cmd, void *arg); +#if MYNEWT_VAL(BUS_DRIVER_PRESENT) +struct mmc_config { + struct bus_spi_node_cfg spi_cfg; +}; +struct mmc { + struct bus_spi_node node; +}; + +int mmc_create_dev(struct mmc *mmc, const char *name, struct mmc_config *mmc_cfg); +#endif + #ifdef __cplusplus } #endif diff --git a/hw/drivers/mmc/pkg.yml b/hw/drivers/mmc/pkg.yml index e29902f5d3..d7f9ced400 100644 --- a/hw/drivers/mmc/pkg.yml +++ b/hw/drivers/mmc/pkg.yml @@ -25,3 +25,9 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/hw/hal" + +pkg.deps.BUS_DRIVER_PRESENT: + - "@apache-mynewt-core/hw/bus/drivers/spi_common" + +pkg.init.MMC_AUTO_MOUNT: + mmc_pkg_init: MYNEWT_VAL(MMC_PKG_SYSINIT_STAGE) diff --git a/hw/drivers/mmc/src/mmc.c b/hw/drivers/mmc/src/mmc.c index bd5f8bd79d..bb14520a43 100644 --- a/hw/drivers/mmc/src/mmc.c +++ b/hw/drivers/mmc/src/mmc.c @@ -17,6 +17,8 @@ * under the License. */ +#include +#include #include #include #include @@ -63,14 +65,23 @@ #define BLOCK_LEN (512) -static uint8_t g_block_buf[BLOCK_LEN]; +static uint8_t g_block_buf[BLOCK_LEN + 2]; -/* FIXME: currently limited to single MMC spi device */ -static struct mmc_cfg { +#if !MYNEWT_VAL(BUS_DRIVER_PRESENT) + +static struct mmc { int spi_num; int ss_pin; struct mmc_spi_cfg mmc_spi_cfg; -} g_mmc_cfg; +} g_mmc; + +/* FIXME: currently limited to single MMC spi device */ +static struct mmc *mmcs[1] = { &g_mmc }; + +#else +static struct mmc *mmcs[1]; +static uint8_t mmcs_count; +#endif static int error_by_response(uint8_t status) @@ -100,22 +111,81 @@ error_by_response(uint8_t status) return (rc); } -static struct mmc_cfg * +static struct mmc * mmc_cfg_dev(uint8_t id) { if (id != 0) { return NULL; } - return &g_mmc_cfg; + return mmcs[0]; +} + +#if MYNEWT_VAL(BUS_DRIVER_PRESENT) + +static void +mmc_spi_set_cs(struct mmc *mmc, int cs) +{ + /* Let bus driver actiave CS, deactivation is done here */ + if (cs) { + hal_gpio_write(mmc->node.pin_cs, cs); + } +} + +static int +mmc_spi_tx(struct mmc *mmc, const uint8_t *buf, uint16_t count) +{ + return bus_node_write(&mmc->node.bnode.odev, buf, count, 1000, BUS_F_NOSTOP); +} + +static int +mmc_spi_rx(struct mmc *mmc, uint8_t *buf, uint16_t count) +{ + memset(buf, 0xFF, count); + return bus_node_duplex_write_read(&mmc->node.bnode.odev, buf, buf, count, 1000, BUS_F_NOSTOP); +} + +#else + +static void +mmc_spi_set_cs(struct mmc *mmc, int cs) +{ + hal_gpio_write(mmc->ss_pin, cs); +} + +static int +mmc_spi_tx(struct mmc *mmc, const uint8_t *buf, uint16_t count) +{ + for (int i = 0; i < count; i++) { + hal_spi_tx_val(mmc->spi_num, buf[i]); + } + return 0; +} + +static int +mmc_spi_rx(struct mmc *mmc, uint8_t *buf, uint16_t count) +{ + for (int i = 0; i < count; i++) { + buf[i] = hal_spi_tx_val(mmc->spi_num, 0xFF); + } + return 0; +} + +#endif + +static int +mmc_spi_tx_byte(struct mmc *mmc, uint8_t b) +{ + return mmc_spi_tx(mmc, &b, 1); } static uint8_t -send_mmc_cmd(struct mmc_cfg *mmc, uint8_t cmd, uint32_t payload) +send_mmc_cmd(struct mmc *mmc, uint8_t cmd, uint32_t payload) { int n; uint8_t status; uint8_t crc; + uint8_t buf[6]; if (cmd & 0x80) { /* TODO: refactor recursion? */ @@ -124,12 +194,11 @@ send_mmc_cmd(struct mmc_cfg *mmc, uint8_t cmd, uint32_t payload) } /* 4.7.2: Command Format */ - hal_spi_tx_val(mmc->spi_num, 0x40 | (cmd & ~0x80)); - - hal_spi_tx_val(mmc->spi_num, payload >> 24 & 0xff); - hal_spi_tx_val(mmc->spi_num, payload >> 16 & 0xff); - hal_spi_tx_val(mmc->spi_num, payload >> 8 & 0xff); - hal_spi_tx_val(mmc->spi_num, payload & 0xff); + buf[0] = 0x40 | (cmd & ~0x80); + buf[1] = (uint8_t)(payload >> 24); + buf[2] = (uint8_t)(payload >> 16); + buf[3] = (uint8_t)(payload >> 8); + buf[4] = (uint8_t)(payload); /** * 7.2.2 Bus Transfer Protection @@ -145,17 +214,176 @@ send_mmc_cmd(struct mmc_cfg *mmc, uint8_t cmd, uint32_t payload) case CMD8: crc = 0x87; break; + default: + break; } - hal_spi_tx_val(mmc->spi_num, crc); + buf[5] = crc; + mmc_spi_tx(mmc, buf, 6); for (n = 255; n > 0; n--) { - status = hal_spi_tx_val(mmc->spi_num, 0xff); - if ((status & 0x80) == 0) break; + mmc_spi_rx(mmc, buf, 1); + status = buf[0]; + if ((status & 0x80) == 0) { + break; + } } return status; } +#if MYNEWT_VAL(BUS_DRIVER_PRESENT) + +static void +mmc_open_cb(struct bus_node *node) +{ + int rc; + int i; + uint8_t status; + uint8_t cmd_resp[4]; + uint32_t ocr; + os_time_t timeout; + struct mmc *mmc = (struct mmc *)node; + + /** + * NOTE: The state machine below follows: + * Section 6.4.1: Power Up Sequence for SD Bus Interface. + * Section 7.2.1: Mode Selection and Initialization. + */ + + /* give 10ms for VDD rampup */ + os_time_delay(OS_TICKS_PER_SEC / 100); + + /* send the required >= 74 clock cycles (10 bytes, 80 clock cycles). */ + for (i = 0; i < 10; i++) { + mmc_spi_tx_byte(mmc, 0xff); + } + + /* put card in idle state */ + status = send_mmc_cmd(mmc, CMD0, 0); + + mmc_spi_set_cs(mmc, 1); + /* No card inserted or bad card? */ + if (status != R_IDLE) { + rc = error_by_response(status); + goto out; + } + + /** + * FIXME: while doing a hot-swap of the card or powering off the board + * it is required to send a CMD1 here otherwise CMD8's response will + * be always invalid. + * + * Why is this happening? CMD1 should never be required for SDxC cards... + */ + + /** + * 4.3.13: Ask for 2.7-3.3V range, send 0xAA pattern + * + * NOTE: cards that are not compliant with "Physical Spec Version 2.00" + * will answer this with R_ILLEGAL_COMMAND. + */ + status = send_mmc_cmd(mmc, CMD8, 0x1AA); + if (status != 0xff && !(status & R_ILLEGAL_COMMAND)) { + + /** + * Ver2.00 or later SD Memory Card + */ + + /* Read the contents of R7 */ + mmc_spi_rx(mmc, cmd_resp, 4); + + /* Did the card return the same pattern? */ + if (cmd_resp[3] != 0xAA) { + rc = MMC_RESPONSE_ERROR; + goto out; + } + + /** + * 4.3.13 Send Interface Condition Command (CMD8) + * Check VHS for 2.7-3.6V support + */ + if (cmd_resp[2] != 0x01) { + rc = MMC_VOLTAGE_ERROR; + goto out; + } + + /** + * Wait for card to leave IDLE state or time out + */ + + timeout = os_time_get() + OS_TICKS_PER_SEC; + for (;;) { + status = send_mmc_cmd(mmc, ACMD41, HCS); + if ((status & R_IDLE) == 0 || os_time_get() > timeout) { + break; + } + os_time_delay(OS_TICKS_PER_SEC / 10); + } + + if (status) { + rc = error_by_response(status); + goto out; + } + + /** + * Check if this is an high density card + */ + + status = send_mmc_cmd(mmc, CMD58, 0); + mmc_spi_rx(mmc, cmd_resp, 4); + if (status == 0 && (cmd_resp[0] & (1 << 6))) { /* FIXME: CCS */ + /** + * TODO: if CCS is set this is an SDHC or SDXC card! + * SDSC uses byte addressing, SDHC/SDXC block addressing + * + * can also check the whole voltage range supported here + */ + } + + } else if (status != 0xff && status & R_ILLEGAL_COMMAND) { + + /** + * Ver1.x SD Memory Card or Not SD Memory Card + */ + + ocr = send_mmc_cmd(mmc, CMD58, 0); + + /* TODO: check if voltage range is ok! */ + + if (ocr & R_ILLEGAL_COMMAND) { + + } + + /* TODO: set blocklen */ + + } else { + rc = error_by_response(status); + } + +out: + mmc_spi_set_cs(mmc, 1); + (void)rc; +} + +int +mmc_create_dev(struct mmc *mmc, const char *name, struct mmc_config *mmc_cfg) +{ + int rc; + struct bus_node_callbacks cbs = { + .open = mmc_open_cb, + }; + + bus_node_set_callbacks((struct os_dev *)mmc, &cbs); + + rc = bus_spi_node_create(name, &mmc->node, &mmc_cfg->spi_cfg, NULL); + if (rc == 0 && mmcs_count < ARRAY_SIZE(mmcs)) { + mmcs[mmcs_count++] = mmc; + } + + return rc; +} + +#else /** * Initialize the MMC driver * @@ -175,7 +403,7 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin) uint32_t ocr; os_time_t timeout; /* TODO: create new struct for every new spi mmc, add to SLIST */ - struct mmc_cfg *mmc = &g_mmc_cfg; + struct mmc *mmc = mmcs[0]; mmc->ss_pin = ss_pin; mmc->mmc_spi_cfg = *spi_cfg; @@ -209,17 +437,17 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin) /* give 10ms for VDD rampup */ os_time_delay(OS_TICKS_PER_SEC / 100); - hal_gpio_write(mmc->ss_pin, 0); + mmc_spi_set_cs(mmc, 0); /* send the required >= 74 clock cycles (10 bytes, 80 clock cycles). */ for (i = 0; i < 10; i++) { - hal_spi_tx_val(mmc->spi_num, 0xff); + mmc_spi_tx_byte(mmc, 0xff); } /* put card in idle state */ status = send_mmc_cmd(mmc, CMD0, 0); - hal_gpio_write(mmc->ss_pin, 1); + mmc_spi_set_cs(mmc, 1); /* No card inserted or bad card? */ if (status != R_IDLE) { rc = error_by_response(status); @@ -230,7 +458,7 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin) spi_settings.baudrate = mmc->mmc_spi_cfg.freq_khz; rc = hal_spi_config(mmc->spi_num, &spi_settings); hal_spi_enable(mmc->spi_num); - hal_gpio_write(mmc->ss_pin, 0); + mmc_spi_set_cs(mmc, 0); /** * FIXME: while doing a hot-swap of the card or powering off the board @@ -254,9 +482,7 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin) */ /* Read the contents of R7 */ - for (i = 0; i < 4; i++) { - cmd_resp[i] = (uint8_t) hal_spi_tx_val(mmc->spi_num, 0xff); - } + mmc_spi_rx(mmc, cmd_resp, 4); /* Did the card return the same pattern? */ if (cmd_resp[3] != 0xAA) { @@ -296,9 +522,7 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin) */ status = send_mmc_cmd(mmc, CMD58, 0); - for (i = 0; i < 4; i++) { - cmd_resp[i] = (uint8_t) hal_spi_tx_val(mmc->spi_num, 0xff); - } + mmc_spi_rx(mmc, cmd_resp, 4); if (status == 0 && (cmd_resp[0] & (1 << 6))) { /* FIXME: CCS */ /** * TODO: if CCS is set this is an SDHC or SDXC card! @@ -329,25 +553,29 @@ mmc_init(int spi_num, struct mmc_spi_cfg *spi_cfg, int ss_pin) } out: - hal_gpio_write(mmc->ss_pin, 1); + mmc_spi_set_cs(mmc, 1); return rc; } +#endif + /** * Commands that return response in R1b format and write * commands enter busy state and keep return 0 while the * operations are in progress. */ static uint8_t -wait_busy(struct mmc_cfg *mmc) +wait_busy(struct mmc *mmc) { os_time_t timeout; uint8_t res; timeout = os_time_get() + OS_TICKS_PER_SEC / 2; do { - res = hal_spi_tx_val(mmc->spi_num, 0xff); - if (res) break; + mmc_spi_rx(mmc, &res, 1); + if (res) { + break; + } os_time_delay(OS_TICKS_PER_SEC / 1000); } while (os_time_get() < timeout); @@ -363,7 +591,6 @@ mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len) uint8_t cmd; uint8_t res; int rc; - uint32_t n; size_t block_len; size_t block_count; os_time_t timeout; @@ -371,7 +598,7 @@ mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len) size_t offset; size_t index; size_t amount; - struct mmc_cfg *mmc; + struct mmc *mmc; mmc = mmc_cfg_dev(mmc_id); if (mmc == NULL) { @@ -385,7 +612,7 @@ mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len) block_addr = addr / BLOCK_LEN; offset = addr - (block_addr * BLOCK_LEN); - hal_gpio_write(mmc->ss_pin, 0); + mmc_spi_set_cs(mmc, 0); cmd = (block_count == 1) ? CMD17 : CMD18; res = send_mmc_cmd(mmc, cmd, block_addr); @@ -402,7 +629,7 @@ mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len) */ timeout = os_time_get() + OS_TICKS_PER_SEC / 5; do { - res = hal_spi_tx_val(mmc->spi_num, 0xff); + mmc_spi_rx(mmc, &res, 1); if (res != 0xFF) { break; } @@ -417,13 +644,9 @@ mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len) goto out; } - for (n = 0; n < BLOCK_LEN; n++) { - g_block_buf[n] = hal_spi_tx_val(mmc->spi_num, 0xff); - } + mmc_spi_rx(mmc, g_block_buf, BLOCK_LEN + 2 /* CRC */); /* TODO: CRC-16 not used here but would be cool to have */ - hal_spi_tx_val(mmc->spi_num, 0xff); - hal_spi_tx_val(mmc->spi_num, 0xff); amount = MIN(BLOCK_LEN - offset, len); @@ -440,7 +663,7 @@ mmc_read(uint8_t mmc_id, uint32_t addr, void *buf, uint32_t len) } out: - hal_gpio_write(mmc->ss_pin, 1); + mmc_spi_set_cs(mmc, 1); return (rc); } @@ -452,7 +675,6 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len) { uint8_t cmd; uint8_t res; - uint32_t n; size_t block_len; size_t block_count; os_time_t timeout; @@ -461,7 +683,7 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len) size_t index; size_t amount; int rc; - struct mmc_cfg *mmc; + struct mmc *mmc; mmc = mmc_cfg_dev(mmc_id); if (mmc == NULL) { @@ -473,7 +695,7 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len) block_addr = addr / BLOCK_LEN; offset = addr - (block_addr * BLOCK_LEN); - hal_gpio_write(mmc->ss_pin, 0); + mmc_spi_set_cs(mmc, 0); /** * This code ensures that if the requested address doesn't align with the @@ -492,8 +714,10 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len) timeout = os_time_get() + OS_TICKS_PER_SEC / 5; do { - res = hal_spi_tx_val(mmc->spi_num, 0xff); - if (res != 0xff) break; + mmc_spi_rx(mmc, &res, 1); + if (res != 0xff) { + break; + } os_time_delay(OS_TICKS_PER_SEC / 20); } while (os_time_get() < timeout); @@ -502,12 +726,7 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len) goto out; } - for (n = 0; n < BLOCK_LEN; n++) { - g_block_buf[n] = hal_spi_tx_val(mmc->spi_num, 0xff); - } - - hal_spi_tx_val(mmc->spi_num, 0xff); - hal_spi_tx_val(mmc->spi_num, 0xff); + mmc_spi_rx(mmc, g_block_buf, BLOCK_LEN + 2); } /* now start write */ @@ -525,26 +744,23 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len) * 7.3.3.2 Start Block Tokens and Stop Tran Token */ if (cmd == CMD24) { - hal_spi_tx_val(mmc->spi_num, START_BLOCK); + mmc_spi_tx_byte(mmc, START_BLOCK); } else { - hal_spi_tx_val(mmc->spi_num, START_BLOCK_TOKEN); + mmc_spi_tx_byte(mmc, START_BLOCK_TOKEN); } amount = MIN(BLOCK_LEN - offset, len); memcpy(&g_block_buf[offset], ((uint8_t *)buf + index), amount); - for (n = 0; n < BLOCK_LEN; n++) { - hal_spi_tx_val(mmc->spi_num, g_block_buf[n]); - } - /* CRC */ - hal_spi_tx_val(mmc->spi_num, 0xff); - hal_spi_tx_val(mmc->spi_num, 0xff); + g_block_buf[BLOCK_LEN] = 0xFF; + g_block_buf[BLOCK_LEN + 1] = 0xFF; + mmc_spi_tx(mmc, g_block_buf, BLOCK_LEN + 2); /** * 7.3.3.1 Data Response Token */ - res = hal_spi_tx_val(mmc->spi_num, 0xff); + mmc_spi_rx(mmc, &res, 1); if ((res & 0x1f) != 0x05) { break; } @@ -559,7 +775,7 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len) } if (cmd == CMD25) { - hal_spi_tx_val(mmc->spi_num, STOP_TRAN_TOKEN); + mmc_spi_tx_byte(mmc, STOP_TRAN_TOKEN); wait_busy(mmc); } @@ -579,7 +795,7 @@ mmc_write(uint8_t mmc_id, uint32_t addr, const void *buf, uint32_t len) wait_busy(mmc); out: - hal_gpio_write(mmc->ss_pin, 1); + mmc_spi_set_cs(mmc, 1); return (rc); } @@ -600,3 +816,51 @@ struct disk_ops mmc_ops = { .write = &mmc_write, .ioctl = &mmc_ioctl, }; + +#if MYNEWT_VAL(BUS_DRIVER_PRESENT) +static struct mmc mmc; +static struct mmc_config mmc_config = { + .spi_cfg = { + .pin_cs = MYNEWT_VAL(MMC_SPI_CS_PIN), + .freq = MYNEWT_VAL(MMC_SPI_FREQ), + .data_order = BUS_SPI_DATA_ORDER_MSB, + .mode = BUS_SPI_MODE_0, + .node_cfg.bus_name = MYNEWT_VAL(MMC_SPI_BUS_NAME), + .node_cfg.lock_timeout_ms = 1000, + } +}; +#endif + +void +mmc_pkg_init(void) +{ +#if MYNEWT_VAL(BUS_DRIVER_PRESENT) + if (0 == mmc_create_dev(&mmc, MYNEWT_VAL(MMC_DEV_NAME), &mmc_config)) { + if (MYNEWT_VAL(MMC_AUTO_MOUNT)) { + os_dev_open(MYNEWT_VAL(MMC_DEV_NAME), 1000, NULL); + } + } +#else + struct mmc_spi_cfg spi_cfg = { + .clock_mode = HAL_SPI_MODE0, + .initial_freq_khz = 400, + .freq_khz = MYNEWT_VAL(MMC_SPI_FREQ), + }; + mmc_init(MYNEWT_VAL(MMC_SPI_NUM), &spi_cfg, MYNEWT_VAL(MMC_SPI_CS_PIN)); +#endif + if (MYNEWT_VAL(MMC_AUTO_MOUNT)) { + uint8_t *sector = malloc(512); + + if (sector == NULL) { + } else { + /* For now only FAT partition are mounted */ + if (mmc_read(0, 0, sector, 512) == 0) { + /* Check if first partition is FAT */ + if (sector[450] == 0x0C) { + disk_register(MYNEWT_VAL(MMC_DEV_NAME), "fatfs", &mmc_ops); + } + } + } + free(sector); + } +} diff --git a/hw/drivers/mmc/syscfg.yml b/hw/drivers/mmc/syscfg.yml new file mode 100644 index 0000000000..1c6bfad450 --- /dev/null +++ b/hw/drivers/mmc/syscfg.yml @@ -0,0 +1,40 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + MMC_SPI_NUM: + description: MMC SPI number. + value: 0 + MMC_SPI_BUS_NAME: + description: MMC SPI device name for bus driver build. + value: '"spi0"' + MMC_SPI_FREQ: + description: SPI device frequency for MMC. + value: 25000 + MMC_SPI_CS_PIN: + description: MMC SPI CS pin. + value: -1 + MMC_DEV_NAME: + description: MMC SPI device name for bus driver build. + value: '"mmc"' + MMC_PKG_SYSINIT_STAGE: + description: Sysinit stage for MMC package. + value: 5 + MMC_AUTO_MOUNT: + description: Try to mount disk at creation time. + value: 1