/* * Copyright 2022 NXP * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #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 SDMMC_UNALIGN_OFFSET 1 /* * Verify that SD stack can initialize an SD 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_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 */ ZTEST(sd_stack, test_ioctl) { int ret; ret = sdmmc_ioctl(&card, DISK_IOCTL_GET_SECTOR_COUNT, §or_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, §or_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 = 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 */ ZTEST(sd_stack, test_write) { 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 */ 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 = 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. */ 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 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"); } } ZTEST_SUITE(sd_stack, NULL, NULL, NULL, NULL, NULL);