/* * Copyright (c) 2020 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #include #include #define TEST_FREQ_HZ 24000000U #define W25Q128_JEDEC_ID 0x001840efU #define TEST_BUF_SIZE 4096U #define MAX_TX_BUF 2 #define SPI_STATUS2_QE 0x02U #define SPI_READ_JEDEC_ID 0x9FU #define SPI_READ_STATUS1 0x05U #define SPI_READ_STATUS2 0x35U #define SPI_WRITE_STATUS2 0x31U #define SPI_WRITE_ENABLE_VS 0x50U #define SPI_WRITE_ENABLE 0x06U #define SPI_SECTOR_ERASE 0x20U #define SPI_SINGLE_WRITE_DATA 0x02U #define SPI_QUAD_WRITE_DATA 0x32U /* bits[7:0] = spi opcode, * bits[15:8] = bytes number of dummy clocks */ #define SPI_FAST_READ_DATA 0x080BU #define SPI_DUAL_FAST_READ_DATA 0x083BU #define SPI_QUAD_FAST_READ_DATA 0x086BU #define SPI_OCTAL_QUAD_READ_DATA 0xE3U #define BUF_SIZE 11 uint8_t buffer_tx[] = "0123456789\0"; #define BUF_SIZE_2 7 uint8_t buffer_tx_2[] = "abcdef\0"; #define SPI_TEST_ADDRESS 0x000010U #define SPI_TEST_ADDRESS_2 0x000020U static uint8_t safbuf[TEST_BUF_SIZE] __aligned(4); static uint8_t safbuf2[TEST_BUF_SIZE] __aligned(4); static const struct device *const spi_dev = DEVICE_DT_GET(DT_NODELABEL(spi0)); static struct spi_buf_set tx_bufs, rx_bufs; static struct spi_buf txb[MAX_TX_BUF], rxb; static struct spi_config spi_cfg_single, spi_cfg_dual, spi_cfg_quad; static void spi_single_init(void) { /* configure spi as single mode */ spi_cfg_single.frequency = TEST_FREQ_HZ; spi_cfg_single.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | SPI_LINES_SINGLE; zassert_true(device_is_ready(spi_dev), "SPI controller device is not ready"); } /** * @brief Test spi device * @details * - Find spi device * - Read flash jedec id */ ZTEST_USER(spi, test_spi_device) { uint32_t jedec_id; int ret; /* read jedec id */ memset(safbuf, 0, TEST_BUF_SIZE); safbuf[0] = SPI_READ_JEDEC_ID; txb[0].buf = &safbuf; txb[0].len = 1U; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; jedec_id = 0U; rxb.buf = &jedec_id; rxb.len = 3U; rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Read JEDEC ID spi_transceive failure: " "error %d", ret); zassert_true(jedec_id == W25Q128_JEDEC_ID, "JEDEC ID doesn't match"); } /** * @brief Test spi sector erase * @details * - write enable * - erase data in flash device * - read register1 and wait for erase operation completed */ ZTEST_USER(spi_sector_erase, test_spi_sector_erase) { int ret; /* write enable */ memset(safbuf, 0, TEST_BUF_SIZE); safbuf[0] = SPI_WRITE_ENABLE; txb[0].buf = &safbuf; txb[0].len = 1U; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send write enable spi_transceive failure: " "error %d", ret); /* erase data start from address 0x000010 */ safbuf[0] = SPI_SECTOR_ERASE; safbuf[1] = SPI_TEST_ADDRESS & 0xFFFFFFU; txb[0].buf = &safbuf; txb[0].len = 4; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send sector erase data spi_transceive failure: " "error %d", ret); /* read register1 to check whether erase operation completed */ safbuf[0] = SPI_READ_STATUS1; txb[0].buf = &safbuf; txb[0].len = 1; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; memset(safbuf2, 1U, 1U); rxb.buf = &safbuf2; rxb.len = 1U; rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; /* waiting for erase operation completed */ while (safbuf2[0]) { ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send read register1 spi_transceive " "failure: error %d", ret); } } /** * @brief Write data into flash using spi api * @details * - flash write enable * - write data into flash using spi api */ static void test_spi_single_write(void) { int ret; /* write enable */ memset(safbuf, 0, TEST_BUF_SIZE); safbuf[0] = SPI_WRITE_ENABLE; txb[0].buf = &safbuf; txb[0].len = 1U; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send write enable spi_transceive failure: " "error %d", ret); /* write data start from address 0x000010 */ safbuf[0] = SPI_SINGLE_WRITE_DATA; safbuf[1] = SPI_TEST_ADDRESS & 0xFFFFFFU; memcpy(&safbuf[4], buffer_tx, BUF_SIZE); txb[0].buf = &safbuf; txb[0].len = 4 + BUF_SIZE; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send write data spi_transceive failure: " "error %d", ret); } /** * @brief Read data from flash using spi single mode * @details * - read data using spi single mode * - check read buffer data whether correct */ ZTEST_USER(spi, test_spi_single_read) { int ret; uint8_t cnt = 0; uint16_t spi_opcode; spi_opcode = SPI_FAST_READ_DATA; /* read data using spi single mode */ /* set the spi operation code and address */ memset(safbuf, 0, TEST_BUF_SIZE); safbuf[0] = spi_opcode & 0xFFU; safbuf[1] = SPI_TEST_ADDRESS & 0xFFFFFFU; txb[cnt].buf = &safbuf; txb[cnt].len = 4U; /* set the dummy clocks */ if (spi_opcode & 0xFF00U) { cnt++; txb[cnt].buf = NULL; txb[cnt].len = (spi_opcode >> 8) & 0xFFU; } tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = cnt + 1; memset(safbuf2, 0, BUF_SIZE); rxb.buf = &safbuf2; rxb.len = BUF_SIZE; rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send fast read data spi_transceive failure: " "error %d", ret); /* check read buffer data whether correct */ zassert_true(memcmp(buffer_tx, safbuf2, BUF_SIZE) == 0, "Buffer read data is different to write data"); } static void spi_dual_init(void) { /* configure spi dual mode */ spi_cfg_dual.frequency = TEST_FREQ_HZ; spi_cfg_dual.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | SPI_LINES_DUAL; zassert_true(device_is_ready(spi_dev), "SPI controller device is not ready"); } /** * @brief Read data from flash using spi dual mode * @details * - read data using spi dual mode * - check read buffer data whether correct */ ZTEST_USER(spi, test_spi_dual_read) { int ret; uint8_t cnt = 0; uint16_t spi_opcode; spi_dual_init(); spi_opcode = SPI_DUAL_FAST_READ_DATA; /* read data using spi dual mode */ /* set the spi operation code and address */ memset(safbuf, 0, TEST_BUF_SIZE); safbuf[0] = spi_opcode & 0xFFU; safbuf[1] = SPI_TEST_ADDRESS & 0xFFFFFFU; txb[cnt].buf = &safbuf; txb[cnt].len = 4U; /* set the dummy clocks */ if (spi_opcode & 0xFF00U) { cnt++; txb[cnt].buf = NULL; txb[cnt].len = (spi_opcode >> 8) & 0xFFU; } tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = cnt + 1; /* send opcode and address using single mode */ spi_cfg_single.operation |= SPI_HOLD_ON_CS; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, NULL); zassert_true(ret == 0, "Send fast read data spi_transceive failure: " "error %d", ret); memset(safbuf2, 0, BUF_SIZE); rxb.buf = &safbuf2; rxb.len = BUF_SIZE; rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; /* get read data using dual mode */ ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_dual, NULL, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Receive fast read data spi_transceive failure: " "error %d", ret); /* check read buffer data whether correct */ zassert_true(memcmp(buffer_tx, safbuf2, BUF_SIZE) == 0, "Buffer read data is different to write data"); /* release spi device */ spi_cfg_single.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | SPI_LINES_SINGLE; ret = spi_release(spi_dev, (const struct spi_config *)&spi_cfg_single); zassert_true(ret == 0, "Spi release failure: error %d", ret); } /** * @brief Write data into flash using spi quad mode * @details * - check and make sure spi quad mode is enabled * - write data using spi quad mode */ static void test_spi_quad_write(void) { int ret; uint8_t spi_status2; /* read register2 to judge whether quad mode is enabled */ safbuf[0] = SPI_READ_STATUS2; txb[0].buf = &safbuf; txb[0].len = 1U; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; memset(safbuf2, 0, 1U); rxb.buf = &safbuf2; rxb.len = 1U; rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Read register2 status spi_transceive failure: " "error %d", ret); spi_status2 = safbuf2[0]; /* set register2 QE=1 to enable quad mode */ if ((spi_status2 & SPI_STATUS2_QE) == 0U) { safbuf[0] = SPI_WRITE_ENABLE_VS; txb[0].buf = &safbuf; txb[0].len = 1U; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send write enable volatile spi_transceive failure: " "error %d", ret); safbuf[0] = SPI_WRITE_STATUS2; safbuf[1] = spi_status2 | SPI_STATUS2_QE; txb[0].buf = &safbuf; txb[0].len = 2U; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Write spi status2 QE=1 spi_transceive failure: " "error %d", ret); /* read register2 to confirm quad mode is enabled */ safbuf[0] = SPI_READ_STATUS2; txb[0].buf = &safbuf; txb[0].len = 1U; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; memset(safbuf2, 0, 1U); rxb.buf = &safbuf2; rxb.len = 1U; rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Read register2 status spi_transceive failure: " "error %d", ret); spi_status2 = safbuf2[0]; zassert_true((spi_status2 & SPI_STATUS2_QE) == SPI_STATUS2_QE, "Enable QSPI mode failure"); } /* write enable */ safbuf[0] = SPI_WRITE_ENABLE; txb[0].buf = &safbuf; txb[0].len = 1U; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send write enable spi_transceive failure: " "error %d", ret); /* configure spi quad mode */ spi_cfg_quad.frequency = TEST_FREQ_HZ; spi_cfg_quad.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | SPI_LINES_QUAD; /* write data using spi quad mode */ /* send quad write opcode and address using single mode */ memset(safbuf, 0, TEST_BUF_SIZE); safbuf[0] = SPI_QUAD_WRITE_DATA; safbuf[1] = SPI_TEST_ADDRESS_2 & 0xFFFFFFU; txb[0].buf = &safbuf; txb[0].len = 4; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; spi_cfg_single.operation |= SPI_HOLD_ON_CS; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send quad write data spi_transceive failure: " "error %d", ret); /* send data using quad mode */ memset(safbuf, 0, TEST_BUF_SIZE); memcpy(&safbuf[0], buffer_tx_2, BUF_SIZE_2); txb[0].buf = &safbuf; txb[0].len = BUF_SIZE_2; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_quad, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send quad write data spi_transceive failure: " "error %d", ret); spi_cfg_single.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | SPI_LINES_SINGLE; ret = spi_release(spi_dev, (const struct spi_config *)&spi_cfg_single); zassert_true(ret == 0, "Spi release failure: error %d", ret); } /** * @brief Read data from flash using spi quad mode * @details * - read data using spi quad mode * - check read buffer data whether correct */ ZTEST_USER(spi_quad, test_spi_quad_read) { int ret; uint8_t cnt = 0; uint16_t spi_opcode; spi_opcode = SPI_QUAD_FAST_READ_DATA; /* read data using spi quad mode */ /* set the spi operation code and address */ memset(safbuf, 0, TEST_BUF_SIZE); safbuf[0] = spi_opcode & 0xFFU; safbuf[1] = SPI_TEST_ADDRESS_2 & 0xFFFFFFU; txb[cnt].buf = &safbuf; txb[cnt].len = 4U; /* set the dummy clocks */ if (spi_opcode & 0xFF00U) { cnt++; txb[cnt].buf = NULL; txb[cnt].len = (spi_opcode >> 8) & 0xFFU; } tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = cnt + 1; /* send opcode and address using single mode */ spi_cfg_single.operation |= SPI_HOLD_ON_CS; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, NULL); zassert_true(ret == 0, "Send fast read data spi_transceive failure: " "error %d", ret); memset(safbuf2, 0, TEST_BUF_SIZE); rxb.buf = &safbuf2; rxb.len = BUF_SIZE_2; rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; /* get read data using quad mode */ ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_quad, NULL, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Receive fast read data spi_transceive failure: " "error %d", ret); /* check read buffer data whether correct */ zassert_true(memcmp(buffer_tx_2, safbuf2, BUF_SIZE_2) == 0, "Buffer read data is different to write data"); /* release spi device */ spi_cfg_single.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | SPI_LINES_SINGLE; ret = spi_release(spi_dev, (const struct spi_config *)&spi_cfg_single); zassert_true(ret == 0, "Spi release failure: error %d", ret); } /** * @brief Read data from flash using spi octal quad mode * @details * - read data using spi octal quad mode * - check read buffer data whether correct */ ZTEST_USER(spi_quad, test_spi_octal_read) { int ret; /* read data using spi octal quad mode */ /* send octal read opcode using single mode */ memset(safbuf, 0, TEST_BUF_SIZE); safbuf[0] = SPI_OCTAL_QUAD_READ_DATA; txb[0].buf = &safbuf; txb[0].len = 1; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; rx_bufs.buffers = NULL; rx_bufs.count = 0U; spi_cfg_single.operation |= SPI_HOLD_ON_CS; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_single, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send octal quad read opcode " "spi_transceive failure: error %d", ret); /* send address using quad mode */ safbuf[0] = SPI_TEST_ADDRESS & 0xFFFFF0U; safbuf[3] = 0xFFU; txb[0].buf = &safbuf; txb[0].len = 4; tx_bufs.buffers = (const struct spi_buf *)&txb[0]; tx_bufs.count = 1U; memset(safbuf2, 0, TEST_BUF_SIZE); rxb.buf = &safbuf2; rxb.len = BUF_SIZE; rx_bufs.buffers = (const struct spi_buf *)&rxb; rx_bufs.count = 1U; ret = spi_transceive(spi_dev, (const struct spi_config *)&spi_cfg_quad, (const struct spi_buf_set *)&tx_bufs, (const struct spi_buf_set *)&rx_bufs); zassert_true(ret == 0, "Send quad read address spi_transceive " "failure: error %d", ret); /* check read buffer data whether correct */ zassert_true(memcmp(buffer_tx, safbuf2, BUF_SIZE) == 0, "Buffer read data is different to write data"); /* release spi device */ spi_cfg_single.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8) | SPI_LINES_SINGLE; ret = spi_release(spi_dev, (const struct spi_config *)&spi_cfg_single); zassert_true(ret == 0, "Spi release failure: error %d", ret); } void *spi_setup(void) { spi_single_init(); return NULL; } void *spi_single_setup(void) { spi_single_init(); /* The writing test goes * first berfore testing * the reading. */ test_spi_single_write(); return NULL; } void *spi_quad_setup(void) { spi_dual_init(); /* The writing test goes * first berfore testing * the reading. */ test_spi_quad_write(); return NULL; } ZTEST_SUITE(spi, NULL, spi_single_setup, NULL, NULL, NULL); ZTEST_SUITE(spi_quad, NULL, spi_quad_setup, NULL, NULL, NULL); ZTEST_SUITE(spi_sector_erase, NULL, spi_setup, NULL, NULL, NULL);