blob: 60898eea376dec85ab36c49c7b8a8ba3030ef467 [file] [log] [blame]
/*
* Copyright 2022 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/zephyr.h>
#include <zephyr/sd/sdmmc.h>
#include <zephyr/device.h>
#include <zephyr/drivers/disk.h>
#include <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
const struct device *sdhc_dev;
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 SDMMC_UNALIGN_OFFSET 1
/* Verify that SD stack can initialize an SD card */
static void test_init(void)
{
int ret;
sdhc_dev = device_get_binding(CONFIG_SDHC_LABEL);
zassert_not_null(sdhc_dev, "Could not get SD host controller dev");
ret = sd_is_card_present(sdhc_dev);
zassert_equal(ret, 1, "SD card not present in slot");
ret = sd_init(sdhc_dev, &card);
zassert_equal(ret, 0, "Card initialization failed");
}
/* Verify that SD stack returns valid IOCTL values */
static void test_ioctl(void)
{
int ret;
ret = sdmmc_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 = sdmmc_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 */
static void test_read(void)
{
int ret;
int block_addr = 0;
/* Try simple reads from start of SD card */
ret = sdmmc_read_blocks(&card, buf, block_addr, 1);
zassert_equal(ret, 0, "Single block card read failed");
ret = sdmmc_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 = sdmmc_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 = sdmmc_read_blocks(&card, buf, block_addr, 1);
zassert_not_equal(ret, 0, "Out of bounds read should fail");
block_addr = sector_count - 2;
ret = sdmmc_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 = sdmmc_read_blocks(&card, buf + SDMMC_UNALIGN_OFFSET,
block_addr, SECTOR_COUNT - 1);
zassert_equal(ret, 0, "Unaligned read failed");
}
/* Verify that SD stack can write to an SD card */
static void test_write(void)
{
int ret;
int block_addr = 0;
/* Try simple writes from start of SD card */
ret = sdmmc_write_blocks(&card, buf, block_addr, 1);
zassert_equal(ret, 0, "Single block card write failed");
ret = sdmmc_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 = sdmmc_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 = sdmmc_write_blocks(&card, buf, block_addr, 1);
zassert_not_equal(ret, 0, "Out of bounds write should fail");
block_addr = sector_count - 2;
ret = sdmmc_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 = sdmmc_write_blocks(&card, buf + SDMMC_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 */
static void test_rw(void)
{
int ret;
int block_addr = 0;
/* Zero the write buffer */
memset(buf, 0, BUF_SIZE);
memset(check_buf, 0, BUF_SIZE);
ret = sdmmc_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 = sdmmc_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 = sdmmc_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 = sdmmc_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 = sdmmc_write_blocks(&card, buf + SDMMC_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 + SDMMC_UNALIGN_OFFSET, 0,
(SECTOR_COUNT - 1) * sector_size);
ret = sdmmc_read_blocks(&card, check_buf + SDMMC_UNALIGN_OFFSET,
block_addr, (SECTOR_COUNT - 1));
zassert_equal(ret, 0, "Read from card failed");
zassert_mem_equal(buf + SDMMC_UNALIGN_OFFSET,
check_buf + SDMMC_UNALIGN_OFFSET,
(SECTOR_COUNT - 1) * sector_size,
"Unaligned read of written area was not correct");
}
}
/* Simply dump the card configuration. */
void test_card_config(void)
{
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 SD_TIMING_SDR12:
TC_PRINT("Card timing: SDR12\n");
break;
case SD_TIMING_SDR25:
TC_PRINT("Card timing: SDR25\n");
break;
case SD_TIMING_SDR50:
TC_PRINT("Card timing: SDR50\n");
break;
case SD_TIMING_SDR104:
TC_PRINT("Card timing: SDR104\n");
break;
case SD_TIMING_DDR50:
TC_PRINT("Card timing: DDR50\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;
default:
zassert_unreachable("Card type is not known value");
}
if (card.sd_version >= SD_SPEC_VER3_0) {
TC_PRINT("Card spec: 3.0\n");
} else if (card.sd_version >= SD_SPEC_VER2_0) {
TC_PRINT("Card spec: 2.0\n");
} else if (card.sd_version >= SD_SPEC_VER1_1) {
TC_PRINT("Card spec: 1.1\n");
} else if (card.sd_version >= SD_SPEC_VER1_0) {
TC_PRINT("Card spec: 1.0\n");
} else {
zassert_unreachable("Card spec is unknown value");
}
}
void test_main(void)
{
ztest_test_suite(sd_stack_test,
ztest_unit_test(test_init),
ztest_unit_test(test_ioctl),
ztest_unit_test(test_read),
ztest_unit_test(test_write),
ztest_unit_test(test_rw),
ztest_unit_test(test_card_config)
);
ztest_run_test_suite(sd_stack_test);
}