blob: 287addf4461702c29616aad0de91c6464fb39986 [file] [log] [blame]
/*
* Copyright (c) 2020 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/drivers/spi.h>
#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));
struct spi_buf_set tx_bufs, rx_bufs;
struct spi_buf txb[MAX_TX_BUF], rxb;
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;
spi_cfg_single.slave = 0;
spi_cfg_single.cs = NULL;
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_sec_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;
spi_cfg_dual.slave = 0;
spi_cfg_dual.cs = NULL;
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;
spi_cfg_quad.slave = 0;
spi_cfg_quad.cs = NULL;
/* 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);