tests: sd: Adds MMC test and Kconfigs

Adds MMC test and Kconfigs for MMC
Note: MMC not yet implemented as of this commit

Signed-off-by: Declan Snyder <declan.snyder@nxp.com>
This commit is contained in:
Declan Snyder 2022-09-07 19:40:20 -05:00 committed by Carles Cufí
commit fea01b4254
6 changed files with 290 additions and 1 deletions

View file

@ -5,6 +5,11 @@
menu "SD" menu "SD"
config MMC_STACK
bool "MMC protocol support"
help
Enable MMC protocol support. Required for eMMC cards to function.
config SDMMC_STACK config SDMMC_STACK
bool "SDMMC protocol support" bool "SDMMC protocol support"
help help
@ -18,7 +23,7 @@ config SDIO_STACK
config SD_STACK config SD_STACK
bool bool
default y if SDMMC_STACK || SDIO_STACK default y if MMC_STACK || SDMMC_STACK || SDIO_STACK
select SDHC select SDHC
help help
Enable SD card support. Enable SD card support.
@ -65,6 +70,8 @@ config SD_BUFFER_SIZE
# If SDHC required buffer alignment, we need a full block size in # If SDHC required buffer alignment, we need a full block size in
# internal buffer # internal buffer
default 512 if SDHC_BUFFER_ALIGNMENT != 1 default 512 if SDHC_BUFFER_ALIGNMENT != 1
# If MMC is being used, need 512 bytes to read EXT_CSD
default 512 if MMC_STACK
# Otherwise, we only need 64 bytes to read SD switch function # Otherwise, we only need 64 bytes to read SD switch function
default 64 default 64
help help
@ -85,6 +92,12 @@ config SD_UHS_PROTOCOL
Enable support for ultra high speed SD cards. This can be disabled to Enable support for ultra high speed SD cards. This can be disabled to
reduce code size, at the cost of data transfer speeds. reduce code size, at the cost of data transfer speeds.
config MMC_RCA
hex "MMC Relative card address"
default 2
help
Relative card address to publish to MMC card.
endif # SD_STACK endif # SD_STACK
endmenu endmenu

View file

@ -0,0 +1,8 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(mmc_subsys_test)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View file

@ -0,0 +1,29 @@
MMC Subsystem Test
##################
This test is designed to verify the MMC protocol stack implementation,
and run stress tests to verify large data transfers succeed using the
subsystem. Due to the differences between underlying SD host controller drivers,
this test also serves as a complete test for the SDHC driver implementation in
use. It requires an SD card be connected to the board to pass, and will
perform destructive I/O on the card, wiping any data present. The test has
the following phases:
* Init test: verify the SD host controller can detect card presence, and
test the initialization flow of the MMC subsystem to verify that the stack
can correctly initialize an SD card.
* IOCTL test: verify the SD subsystem correctly implements IOCTL calls required
for block devices in Zephyr.
* Read test: verify that single block reads work, followed by multiple
block reads. Ensure the subsystem will reject reads beyond the end of
the card's stated size.
* Write test: verify that single block writes work, followed by multiple
block writes. Ensure the subsystem will reject writes beyond the end of
the card's stated size.
* R/W test: write data to the MMC card, and verify that it is able
to be read back without error. Perform this R/W combination at several
sector locations across the MMC card.

View file

@ -0,0 +1,5 @@
CONFIG_TEST=y
CONFIG_ZTEST=y
CONFIG_MMC_STACK=y
CONFIG_LOG=y
CONFIG_ZTEST_NEW_API=y

View file

@ -0,0 +1,224 @@
/*
* Copyright 2022 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <zephyr/drivers/disk.h>
#include <zephyr/sd/mmc.h>
#include <zephyr/kernel.h>
#include <zephyr/ztest.h>
#define SECTOR_COUNT 32
#define SECTOR_SIZE 512 /* subsystem should set all cards to 512 byte blocks */
#define BUF_SIZE (SECTOR_SIZE * SECTOR_COUNT)
static const struct device *const sdhc_dev = DEVICE_DT_GET(DT_ALIAS(sdhc0));
static struct sd_card card;
static uint8_t buf[BUF_SIZE] __aligned(CONFIG_SDHC_BUFFER_ALIGNMENT);
static uint8_t check_buf[BUF_SIZE] __aligned(CONFIG_SDHC_BUFFER_ALIGNMENT);
static uint32_t sector_size;
static uint32_t sector_count;
#define MMC_UNALIGN_OFFSET 1
/*
* Verify that SD stack can initialize an MMC card
* This test must run first, to ensure the card is initialized.
*/
ZTEST(sd_stack, test_0_init)
{
int ret;
zassert_true(device_is_ready(sdhc_dev), "SDHC device is not ready");
ret = sd_init(sdhc_dev, &card);
zassert_equal(ret, 0, "Card initialization failed");
}
/* Verify that MMC stack returns valid IOCTL values */
ZTEST(sd_stack, test_ioctl)
{
int ret;
ret = mmc_ioctl(&card, DISK_IOCTL_GET_SECTOR_COUNT, &sector_count);
zassert_equal(ret, 0, "IOCTL sector count read failed");
TC_PRINT("SD card reports sector count of %d\n", sector_count);
ret = mmc_ioctl(&card, DISK_IOCTL_GET_SECTOR_SIZE, &sector_size);
zassert_equal(ret, 0, "IOCTL sector size read failed");
TC_PRINT("SD card reports sector size of %d\n", sector_size);
}
/* Verify that SD stack can read from an SD card */
ZTEST(sd_stack, test_read)
{
int ret;
int block_addr = 0;
/* Try simple reads from start of SD card */
ret = mmc_read_blocks(&card, buf, block_addr, 1);
zassert_equal(ret, 0, "Single block card read failed");
ret = mmc_read_blocks(&card, buf, block_addr, SECTOR_COUNT / 2);
zassert_equal(ret, 0, "Multiple block card read failed");
/* Try a series of reads from the same block */
block_addr = sector_count / 2;
for (int i = 0; i < 10; i++) {
ret = mmc_read_blocks(&card, buf, block_addr, SECTOR_COUNT);
zassert_equal(ret, 0, "Multiple reads from same addr failed");
}
/* Verify that out of bounds read fails */
block_addr = sector_count;
ret = mmc_read_blocks(&card, buf, block_addr, 1);
zassert_not_equal(ret, 0, "Out of bounds read should fail");
block_addr = sector_count - 2;
ret = mmc_read_blocks(&card, buf, block_addr, 2);
zassert_equal(ret, 0, "Read from end of card failed");
/* Verify that unaligned reads work */
block_addr = 3;
ret = mmc_read_blocks(&card, buf + MMC_UNALIGN_OFFSET, block_addr, SECTOR_COUNT - 1);
zassert_equal(ret, 0, "Unaligned read failed");
}
/* Verify that SD stack can write to an SD card */
ZTEST(sd_stack, test_write)
{
int ret;
int block_addr = 0;
/* Try simple writes from start of SD card */
ret = mmc_write_blocks(&card, buf, block_addr, 1);
zassert_equal(ret, 0, "Single block card write failed");
ret = mmc_write_blocks(&card, buf, block_addr, SECTOR_COUNT / 2);
zassert_equal(ret, 0, "Multiple block card write failed");
/* Try a series of reads from the same block */
block_addr = sector_count / 2;
for (int i = 0; i < 10; i++) {
ret = mmc_write_blocks(&card, buf, block_addr, SECTOR_COUNT);
zassert_equal(ret, 0, "Multiple writes to same addr failed");
}
/* Verify that out of bounds write fails */
block_addr = sector_count;
ret = mmc_write_blocks(&card, buf, block_addr, 1);
zassert_not_equal(ret, 0, "Out of bounds write should fail");
block_addr = sector_count - 2;
ret = mmc_write_blocks(&card, buf, block_addr, 2);
zassert_equal(ret, 0, "Write to end of card failed");
/* Verify that unaligned writes work */
block_addr = 3;
ret = mmc_write_blocks(&card, buf + MMC_UNALIGN_OFFSET, block_addr, SECTOR_COUNT - 1);
zassert_equal(ret, 0, "Unaligned write failed");
}
/* Test reads and writes interleaved, to verify data is making it on disk */
ZTEST(sd_stack, test_rw)
{
int ret;
int block_addr = 0;
/* Zero the write buffer */
memset(buf, 0, BUF_SIZE);
memset(check_buf, 0, BUF_SIZE);
ret = mmc_write_blocks(&card, buf, block_addr, SECTOR_COUNT / 2);
zassert_equal(ret, 0, "Write to card failed");
/* Verify that a read from this area is empty */
ret = mmc_read_blocks(&card, buf, block_addr, SECTOR_COUNT / 2);
zassert_equal(ret, 0, "Read from card failed");
zassert_mem_equal(buf, check_buf, BUF_SIZE, "Read of erased area was not zero");
/* Now write nonzero data block */
for (int i = 0; i < sizeof(buf); i++) {
check_buf[i] = buf[i] = (uint8_t)i;
}
ret = mmc_write_blocks(&card, buf, block_addr, SECTOR_COUNT);
zassert_equal(ret, 0, "Write to card failed");
/* Clear the read buffer, then write to it again */
memset(buf, 0, BUF_SIZE);
ret = mmc_read_blocks(&card, buf, block_addr, SECTOR_COUNT);
zassert_equal(ret, 0, "Read from card failed");
zassert_mem_equal(buf, check_buf, BUF_SIZE, "Read of written area was not correct");
block_addr = (sector_count / 3);
for (int i = 0; i < 10; i++) {
/* Verify that unaligned writes work */
ret = mmc_write_blocks(&card, buf + MMC_UNALIGN_OFFSET, block_addr,
SECTOR_COUNT - 1);
zassert_equal(ret, 0, "Write to card failed");
/* Zero check buffer and read into it */
memset(check_buf + MMC_UNALIGN_OFFSET, 0, (SECTOR_COUNT - 1) * sector_size);
ret = mmc_read_blocks(&card, check_buf + MMC_UNALIGN_OFFSET, block_addr,
(SECTOR_COUNT - 1));
zassert_equal(ret, 0, "Read from card failed");
zassert_mem_equal(buf + MMC_UNALIGN_OFFSET, check_buf + MMC_UNALIGN_OFFSET,
(SECTOR_COUNT - 1) * sector_size,
"Unaligned read of written area was not correct");
}
}
/* Simply dump the card configuration. */
ZTEST(sd_stack, test_card_config)
{
switch (card.card_voltage) {
case SD_VOL_1_2_V:
TC_PRINT("Card voltage: 1.2V\n");
break;
case SD_VOL_1_8_V:
TC_PRINT("Card voltage: 1.8V\n");
break;
case SD_VOL_3_0_V:
TC_PRINT("Card voltage: 3.0V\n");
break;
case SD_VOL_3_3_V:
TC_PRINT("Card voltage: 3.3V\n");
break;
default:
zassert_unreachable("Card voltage is not known value");
}
zassert_equal(card.status, CARD_INITIALIZED, "Card status is not OK");
switch (card.card_speed) {
case MMC_LEGACY_TIMING:
TC_PRINT("Card timing: Legacy MMC\n");
break;
case MMC_HS_TIMING:
TC_PRINT("Card timing: High Speed MMC\n");
break;
case MMC_HS200_TIMING:
TC_PRINT("Card timing: MMC HS200\n");
break;
case MMC_HS400_TIMING:
TC_PRINT("Card timing: MMC HS400\n");
break;
default:
zassert_unreachable("Card timing is not known value");
}
switch (card.type) {
case CARD_SDIO:
TC_PRINT("Card type: SDIO\n");
break;
case CARD_SDMMC:
TC_PRINT("Card type: SDMMC\n");
break;
case CARD_COMBO:
TC_PRINT("Card type: combo card\n");
break;
case CARD_MMC:
TC_PRINT("Card type: MMC\n");
break;
default:
zassert_unreachable("Card type is not known value");
}
}
ZTEST_SUITE(sd_stack, NULL, NULL, NULL, NULL, NULL);

View file

@ -0,0 +1,10 @@
common:
depends_on: sdhc
tags: drivers sdhc
tests:
subsys.sd.mmc:
harness: ztest
filter: dt_compat_enabled("zephyr,mmc-disk")
tags: sdhc
min_ram: 32
integration_platforms: