mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-16 11:28:54 +00:00
V1.0.5
This commit is contained in:
@@ -9,7 +9,7 @@ if GetDepend('AIC_QSPI_DRV_TEST') and GetDepend('RT_USING_FINSH'):
|
||||
src = Glob('test_qspidev.c')
|
||||
src += Glob('test_spibit.c')
|
||||
src += Glob('test_spi_async.c')
|
||||
if GetDepend('AIC_QSPI_DRV_V11'):
|
||||
if GetDepend('AIC_QSPI_DRV_V11') and GetDepend('AIC_CHIP_D13X'):
|
||||
src += Glob('test_spislave*.c')
|
||||
|
||||
group = DefineGroup('test-qspi', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
@@ -85,6 +85,18 @@ static void show_speed(char *msg, u32 len, u32 us)
|
||||
printf("%s: %d byte, %d us -> %d KB/s\n", msg, len, us, speed);
|
||||
}
|
||||
|
||||
static void hex_dump(uint8_t *data, unsigned long len)
|
||||
{
|
||||
unsigned long i = 0;
|
||||
printf("\n");
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i && (i % 16) == 0)
|
||||
printf("\n");
|
||||
printf("%02x ", data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int test_qspi_attach(int argc, char **argv)
|
||||
{
|
||||
char *bus_name, *dev_name;
|
||||
@@ -265,12 +277,18 @@ static void test_qspi_sendlen(int argc, char **argv)
|
||||
data_len = 0;
|
||||
data_len = strtoul(argv[2], NULL, 0);
|
||||
data = RT_NULL;
|
||||
printf("data len %ld\n", data_len);
|
||||
if (data_len) {
|
||||
align_len = roundup(data_len, CACHE_LINE_SIZE);
|
||||
align_len = 64;
|
||||
data = aicos_malloc_align(0, align_len, CACHE_LINE_SIZE);
|
||||
}
|
||||
rt_memset(&msg, 0, sizeof(msg));
|
||||
if (data == NULL) {
|
||||
printf("Low memory!\n");
|
||||
return;
|
||||
} else {
|
||||
printf("data len %ld\n", data_len);
|
||||
rt_memset(&msg, 0, sizeof(msg));
|
||||
}
|
||||
msg.instruction.content = cmd;
|
||||
msg.instruction.qspi_lines = 0;
|
||||
|
||||
@@ -286,7 +304,7 @@ static void test_qspi_sendlen(int argc, char **argv)
|
||||
|
||||
start_us = aic_get_time_us();
|
||||
ret = rt_qspi_transfer_message(g_qspi, &msg);
|
||||
show_speed("mtd_read speed", data_len, aic_get_time_us() - start_us);
|
||||
show_speed("qspi send speed", data_len, aic_get_time_us() - start_us);
|
||||
if (ret != data_len) {
|
||||
printf("Send data failed. ret 0x%x\n", (int)ret);
|
||||
}
|
||||
@@ -299,14 +317,12 @@ static void test_qspi_recvhex(int argc, char **argv)
|
||||
{
|
||||
char *pl;
|
||||
uint32_t line = 0, addrsiz = 0, addr = 0, dmycyc = 0;
|
||||
unsigned long i, data_len, align_len;
|
||||
unsigned long data_len, align_len;
|
||||
uint8_t *data, cmd;
|
||||
struct rt_qspi_message msg;
|
||||
|
||||
if (!g_qspi) {
|
||||
printf("QSPI device is not init yet.\n");
|
||||
return;
|
||||
}
|
||||
RT_ASSERT(g_qspi);
|
||||
|
||||
if (argc < 3) {
|
||||
printf("Argument is not correct, please see help for more information.\n");
|
||||
return;
|
||||
@@ -318,27 +334,20 @@ static void test_qspi_recvhex(int argc, char **argv)
|
||||
return;
|
||||
}
|
||||
cmd = (uint8_t)strtoul(argv[2], NULL, 16);
|
||||
addrsiz = 0;
|
||||
if (argc >= 4) {
|
||||
if (rt_memcmp(argv[3], "-", 1)) {
|
||||
addrsiz = (strlen(argv[3]) + 1) >> 1;
|
||||
addr = strtoul(argv[3], NULL, 16);
|
||||
} else {
|
||||
addrsiz = 0;
|
||||
addr = 0;
|
||||
}
|
||||
|
||||
if (argc >= 4 && rt_memcmp(argv[3], "-", 1)) {
|
||||
addrsiz = (strlen(argv[3]) + 1) >> 1;
|
||||
addr = strtoul(argv[3], NULL, 16);
|
||||
}
|
||||
dmycyc = 0;
|
||||
if (argc >= 5) {
|
||||
if (rt_memcmp(argv[4], "-", 1))
|
||||
dmycyc = strtoul(argv[4], NULL, 16);
|
||||
|
||||
if (argc >= 5 && rt_memcmp(argv[4], "-", 1)) {
|
||||
dmycyc = strtoul(argv[4], NULL, 16);
|
||||
}
|
||||
|
||||
data_len = 0;
|
||||
if (argc >= 6) {
|
||||
data_len = strtoul(argv[5], NULL, 16);
|
||||
}
|
||||
data = RT_NULL;
|
||||
if (data_len > 0) {
|
||||
if (argc >= 6 && strtoul(argv[5], NULL, 0) > 0) {
|
||||
data_len = strtoul(argv[5], NULL, 0);
|
||||
align_len = roundup(data_len, CACHE_LINE_SIZE);
|
||||
data = aicos_malloc_align(0, align_len, CACHE_LINE_SIZE);
|
||||
if (data == NULL) {
|
||||
@@ -366,13 +375,7 @@ static void test_qspi_recvhex(int argc, char **argv)
|
||||
rt_spi_release_bus((struct rt_spi_device *)g_qspi);
|
||||
|
||||
if (data) {
|
||||
printf("\n");
|
||||
for (i = 0; i < data_len; i++) {
|
||||
if (i && (i % 16) == 0)
|
||||
printf("\n");
|
||||
printf("%02x ", data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
hex_dump(data, data_len);
|
||||
aicos_free_align(0, data);
|
||||
}
|
||||
}
|
||||
@@ -560,7 +563,7 @@ static void cmd_test_qspi(int argc, char **argv)
|
||||
test_qspi_recv(argc - 1, &argv[1]);
|
||||
return;
|
||||
} else if (!rt_strcmp(argv[1], "slaverw")) {
|
||||
#ifdef AIC_QSPI_DRV_V11
|
||||
#ifdef AIC_CHIP_D13X
|
||||
if (!g_qspi) {
|
||||
printf("QSPI device is not init yet.\n");
|
||||
return;
|
||||
@@ -569,7 +572,7 @@ static void cmd_test_qspi(int argc, char **argv)
|
||||
return;
|
||||
#endif
|
||||
} else if (!rt_strcmp(argv[1], "send2slave")) {
|
||||
#ifdef AIC_QSPI_DRV_V11
|
||||
#ifdef AIC_CHIP_D13X
|
||||
if (!g_qspi) {
|
||||
printf("QSPI device is not init yet.\n");
|
||||
return;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Xuan.Wen <xuan.wen@artinchip.com>
|
||||
*/
|
||||
|
||||
#ifndef _AIC_QSPI_SLAVE_
|
||||
#define _AIC_QSPI_SLAVE_
|
||||
|
||||
/* Write flow:
|
||||
* 1BYTE 3BYTE 512
|
||||
* 1. WRITE ADDRESS DATA
|
||||
*
|
||||
* Read flow:
|
||||
* 1. LOAD ADDRESS
|
||||
* 2. GET_STATUS (Slave preparing data, should read N times)
|
||||
* 3. Read DATA ()
|
||||
*/
|
||||
|
||||
#define MEM_CMD_WRITE 0x10
|
||||
#define MEM_CMD_LOAD 0x20
|
||||
#define MEM_CMD_STATUS 0x21
|
||||
#define MEM_CMD_READ 0x22
|
||||
|
||||
#define WRITE_STATUS_VAL 0xF0F0F0F0
|
||||
#define LOAD_STATUS_VAL 0xF1F1F1F1
|
||||
|
||||
#define TEST_BUF_SIZE (512 * 1024)
|
||||
|
||||
/* All data should be 4 bytes aligned. */
|
||||
#define CMD_SIZE 4
|
||||
#define STATUS_SIZE 4
|
||||
#define PKT_SIZE TEST_BUF_SIZE
|
||||
// #define PKT_SIZE 256
|
||||
|
||||
int test_qspi_slave_controller_init(u32 id, u32 bus_width,
|
||||
qspi_slave_async_cb cb, void *priv,
|
||||
qspi_slave_handle *h);
|
||||
void test_qspi_slave_controller_deinit(qspi_slave_handle *h);
|
||||
#endif
|
||||
@@ -1,287 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Xuan.Wen <xuan.wen@artinchip.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <finsh.h>
|
||||
#include <rtconfig.h>
|
||||
#include <rtdevice.h>
|
||||
#include <aic_core.h>
|
||||
#include <aic_hal.h>
|
||||
#include <hal_qspi.h>
|
||||
#include <rtthread.h>
|
||||
#include "test_spislave.h"
|
||||
|
||||
#define RUN_STATE_IN 0
|
||||
#define RUN_STATE_OUT 1
|
||||
|
||||
#define MEM_STATE_IDLE 0
|
||||
#define MEM_STATE_CMD 1
|
||||
#define MEM_STATE_DATA 2
|
||||
|
||||
struct fakemem_state {
|
||||
int run_state;
|
||||
int mem_state;
|
||||
u32 qspi_id;
|
||||
u32 bus_width;
|
||||
qspi_slave_handle handle;
|
||||
u8 *data_buf;
|
||||
u8 *work_buf;
|
||||
};
|
||||
|
||||
static struct fakemem_state g_state;
|
||||
|
||||
#define USAGE \
|
||||
"fakemem help : Get this information.\n" \
|
||||
"fakemem start <spi id> <bus width>: Start fake slave device(mem) on SPI bus.\n" \
|
||||
"fakemem stop : Stop fake slave device.\n" \
|
||||
"example: standard spi by using QSPI1\n" \
|
||||
" fakemem start 1 1\n" \
|
||||
" fakemem stop\n" \
|
||||
" \n" \
|
||||
"example: dual spi by using QSPI1\n" \
|
||||
" fakemem start 1 2\n" \
|
||||
" fakemem stop\n"
|
||||
|
||||
static void qspi_usage(void)
|
||||
{
|
||||
printf("%s", USAGE);
|
||||
}
|
||||
|
||||
void slave_dump_data(char *msg, u8 *buf, u32 len)
|
||||
{
|
||||
printf("%s:\n", msg);
|
||||
for (u32 i = 0; i < len; i++) {
|
||||
if (i != 0 && (i % 16 == 0))
|
||||
printf("\n");
|
||||
printf("%02x ", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int read_cmd_start(struct fakemem_state *state, u8 *buf, u32 len)
|
||||
{
|
||||
struct qspi_transfer t;
|
||||
int ret;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
buf[0] = 0;
|
||||
t.rx_data = buf;
|
||||
t.data_len = len;
|
||||
|
||||
printf("%s, reset rx fifo\n", __func__);
|
||||
hal_qspi_slave_fifo_reset(&state->handle, HAL_QSPI_RX_FIFO);
|
||||
ret = hal_qspi_slave_transfer_async(&state->handle, &t);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_data_start(struct fakemem_state *state, u32 start_addr, u8 *buf)
|
||||
{
|
||||
struct qspi_transfer t;
|
||||
u32 offset, ready_to_read_flag;
|
||||
u8 *p, *status_data;
|
||||
|
||||
status_data = state->work_buf;
|
||||
memset(&t, 0, sizeof(t));
|
||||
offset = start_addr;
|
||||
|
||||
printf("Send load status + data\n");
|
||||
/* Read/Write data length required 4 bytes aligned */
|
||||
ready_to_read_flag = LOAD_STATUS_VAL;
|
||||
memcpy(&status_data[0], &ready_to_read_flag, 4);
|
||||
|
||||
/* Data need to following status flag, and required to send togather,
|
||||
* otherwise master won't know the start of data
|
||||
*/
|
||||
p = buf + (offset % TEST_BUF_SIZE);
|
||||
// printf("offset %d\n", offset);
|
||||
memcpy(&status_data[4], p, PKT_SIZE);
|
||||
t.tx_data = status_data;
|
||||
t.data_len = STATUS_SIZE + PKT_SIZE;
|
||||
|
||||
/* Clear TX FIFO before write new data */
|
||||
hal_qspi_slave_fifo_reset(&state->handle, HAL_QSPI_TX_FIFO);
|
||||
/* Set data to slave qspi, it will wait master's clock to send data out */
|
||||
hal_qspi_slave_transfer_async(&state->handle, &t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_write_ok(struct fakemem_state *state)
|
||||
{
|
||||
struct qspi_transfer t;
|
||||
u32 write_ok_flag;
|
||||
u8 *status;
|
||||
|
||||
status = state->work_buf;
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
printf("Send write status\n");
|
||||
/* Read/Write data length required 4 bytes aligned */
|
||||
write_ok_flag = WRITE_STATUS_VAL;
|
||||
memcpy(&status[0], &write_ok_flag, 4);
|
||||
t.tx_data = status;
|
||||
t.data_len = STATUS_SIZE;
|
||||
hal_qspi_slave_fifo_reset(&state->handle, HAL_QSPI_TX_FIFO);
|
||||
hal_qspi_slave_transfer_async(&state->handle, &t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qspi_slave_fakemem_async_callback(qspi_slave_handle *h, void *priv)
|
||||
{
|
||||
struct fakemem_state *state = priv;
|
||||
int status, cnt;
|
||||
u32 addr = 0;
|
||||
u8 cmd = 0;
|
||||
u8 *p;
|
||||
|
||||
status = hal_qspi_slave_get_status(&state->handle);
|
||||
cnt = 0;
|
||||
if (status == HAL_QSPI_STATUS_OK) {
|
||||
printf("%s, status %d\n", __func__, status);
|
||||
/*
|
||||
* status OK:
|
||||
* TRANSFER DONE or CS INVALID
|
||||
*/
|
||||
p = state->work_buf;
|
||||
if (state->run_state == RUN_STATE_IN) {
|
||||
if (state->mem_state == MEM_STATE_IDLE) {
|
||||
cnt = hal_qspi_slave_transfer_count(&state->handle);
|
||||
if (cnt < CMD_SIZE)
|
||||
return;
|
||||
printf("Got new command\n");
|
||||
slave_dump_data("Command", p, cnt);
|
||||
state->mem_state = MEM_STATE_CMD;
|
||||
}
|
||||
if (state->mem_state == MEM_STATE_CMD) {
|
||||
cmd = p[0];
|
||||
// addr = (p[1] << 16) | (p[2] << 8) | p[3];
|
||||
addr = 0;
|
||||
memcpy(&addr, &p[1], 3);
|
||||
state->mem_state = MEM_STATE_DATA;
|
||||
}
|
||||
if (state->mem_state == MEM_STATE_DATA) {
|
||||
if (cmd == MEM_CMD_WRITE) {
|
||||
if (cnt > CMD_SIZE) {
|
||||
p += CMD_SIZE;
|
||||
memcpy(state->data_buf + addr , p, cnt - CMD_SIZE);
|
||||
}
|
||||
|
||||
/* Stop to receive data now, switch to send out: write
|
||||
* status flag
|
||||
*/
|
||||
hal_qspi_slave_transfer_abort(&state->handle);
|
||||
send_write_ok(state);
|
||||
state->mem_state = MEM_STATE_IDLE;
|
||||
state->run_state = RUN_STATE_OUT;
|
||||
}
|
||||
if (cmd == MEM_CMD_LOAD) {
|
||||
/* Prepare data and ready to send out, next wait the host
|
||||
* to read all data
|
||||
*/
|
||||
hal_qspi_slave_transfer_abort(&state->handle);
|
||||
send_data_start(state, addr, state->data_buf);
|
||||
state->run_state = RUN_STATE_OUT;
|
||||
}
|
||||
}
|
||||
} else { /* (state->run_state == RUN_STATE_OUT) */
|
||||
/* Get the send-out data count */
|
||||
cnt = hal_qspi_slave_transfer_count(&state->handle);
|
||||
if ((cnt == STATUS_SIZE) || (cnt == (STATUS_SIZE + PKT_SIZE))) {
|
||||
state->mem_state = MEM_STATE_IDLE;
|
||||
state->run_state = RUN_STATE_IN;
|
||||
/* Send data is finished, prepare to wait new command */
|
||||
read_cmd_start(state, state->work_buf, TEST_BUF_SIZE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Error process */
|
||||
printf("%s, status %d\n", __func__, status);
|
||||
}
|
||||
}
|
||||
|
||||
static int test_fakemem_start(int argc, char **argv)
|
||||
{
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
if (argc < 2) {
|
||||
qspi_usage();
|
||||
return -1;
|
||||
}
|
||||
val = strtol(argv[1], NULL, 10);
|
||||
g_state.qspi_id = val;
|
||||
g_state.mem_state = MEM_STATE_IDLE;
|
||||
g_state.bus_width = 1; // Default is 1
|
||||
if (g_state.data_buf == NULL)
|
||||
g_state.data_buf =
|
||||
aicos_malloc_align(0, TEST_BUF_SIZE, CACHE_LINE_SIZE);
|
||||
memset(g_state.data_buf, 0, TEST_BUF_SIZE);
|
||||
if (g_state.work_buf == NULL)
|
||||
g_state.work_buf =
|
||||
aicos_malloc_align(0, TEST_BUF_SIZE, CACHE_LINE_SIZE);
|
||||
if (argc >= 3) {
|
||||
val = strtol(argv[2], NULL, 10);
|
||||
g_state.bus_width = val;
|
||||
}
|
||||
ret = test_qspi_slave_controller_init(g_state.qspi_id, g_state.bus_width,
|
||||
qspi_slave_fakemem_async_callback, &g_state,
|
||||
&g_state.handle);
|
||||
if (ret) {
|
||||
printf("QSPI Slave init failure.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start with waiting command */
|
||||
read_cmd_start(&g_state, g_state.work_buf, TEST_BUF_SIZE);
|
||||
g_state.run_state = RUN_STATE_IN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_fakemem_stop(int argc, char **argv)
|
||||
{
|
||||
test_qspi_slave_controller_deinit(&g_state.handle);
|
||||
g_state.run_state = RUN_STATE_IN;
|
||||
if (g_state.data_buf) {
|
||||
aicos_free_align(0, g_state.data_buf);
|
||||
g_state.data_buf = NULL;
|
||||
}
|
||||
if (g_state.work_buf) {
|
||||
aicos_free_align(0, g_state.work_buf);
|
||||
g_state.work_buf = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void test_qspi_slave_set_pinmux(void);
|
||||
static void cmd_test_qspislave_pinmux(int argc, char **argv)
|
||||
{
|
||||
test_qspi_slave_set_pinmux();
|
||||
}
|
||||
|
||||
static void cmd_test_qspislave(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
goto help;
|
||||
|
||||
if (!rt_strcmp(argv[1], "help")) {
|
||||
goto help;
|
||||
} else if (!rt_strcmp(argv[1], "start")) {
|
||||
test_fakemem_start(argc - 1, &argv[1]);
|
||||
return;
|
||||
} else if (!rt_strcmp(argv[1], "stop")) {
|
||||
test_fakemem_stop(argc - 1, &argv[1]);
|
||||
return;
|
||||
}
|
||||
help:
|
||||
qspi_usage();
|
||||
}
|
||||
|
||||
|
||||
MSH_CMD_EXPORT_ALIAS(cmd_test_qspislave, fakemem, Test QSPI Slave);
|
||||
MSH_CMD_EXPORT_ALIAS(cmd_test_qspislave_pinmux, qpinmux, Test QSPI Slave);
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Xuan.Wen <xuan.wen@artinchip.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <finsh.h>
|
||||
#include <rtconfig.h>
|
||||
#include <rtdevice.h>
|
||||
#include <aic_core.h>
|
||||
#include <aic_hal.h>
|
||||
#include <hal_qspi.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
struct spi_pinmux {
|
||||
unsigned char func;
|
||||
unsigned char bias;
|
||||
unsigned char drive;
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* Please change your pinmux setting according your board */
|
||||
static struct spi_pinmux spi_pinmux_config[] = {
|
||||
/* qspi1 */
|
||||
{ 3, PIN_PULL_UP, 3, "PD.4" }, // CS, default set to high
|
||||
{ 3, PIN_PULL_UP, 3, "PD.5" },
|
||||
{ 3, PIN_PULL_UP, 3, "PD.6" }, // SI
|
||||
{ 3, PIN_PULL_UP, 7, "PD.7" }, // CLK
|
||||
{ 3, PIN_PULL_UP, 3, "PD.8" },
|
||||
{ 3, PIN_PULL_UP, 3, "PD.9" },
|
||||
|
||||
/* qspi2 */
|
||||
{ 3, PIN_PULL_UP, 3, "PB.6" },
|
||||
{ 3, PIN_PULL_UP, 3, "PB.7" },
|
||||
{ 3, PIN_PULL_UP, 3, "PB.8" },
|
||||
{ 3, PIN_PULL_UP, 3, "PB.9" },
|
||||
{ 3, PIN_PULL_UP, 3, "PB.10" },
|
||||
{ 3, PIN_PULL_UP, 3, "PB.11" },
|
||||
|
||||
/* qspi3 */
|
||||
{ 3, PIN_PULL_UP, 3, "PD.0" },
|
||||
{ 3, PIN_PULL_UP, 3, "PD.1" }, //CS, default set to high
|
||||
{ 3, PIN_PULL_UP, 3, "PD.2" },
|
||||
{ 3, PIN_PULL_UP, 3, "PD.3" },
|
||||
};
|
||||
|
||||
static u32 qspi_clk_ids[4] = {CLK_QSPI0, CLK_QSPI1, CLK_QSPI2, CLK_QSPI3};
|
||||
static u32 qspi_irq_num[] = {QSPI0_IRQn, QSPI1_IRQn, QSPI2_IRQn, QSPI3_IRQn};
|
||||
static u32 qspi_input_clk[4] = {
|
||||
#ifdef AIC_USING_QSPI0
|
||||
[0] = AIC_DEV_QSPI0_MAX_SRC_FREQ_HZ,
|
||||
#endif
|
||||
#ifdef AIC_USING_QSPI1
|
||||
[1] = AIC_DEV_QSPI1_MAX_SRC_FREQ_HZ,
|
||||
#endif
|
||||
#ifdef AIC_USING_QSPI2
|
||||
[2] = AIC_DEV_QSPI2_MAX_SRC_FREQ_HZ,
|
||||
#endif
|
||||
#ifdef AIC_USING_QSPI3
|
||||
[3] = AIC_DEV_QSPI3_MAX_SRC_FREQ_HZ,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
void test_qspi_slave_set_pinmux(void)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
long pin = 0;
|
||||
unsigned int g;
|
||||
unsigned int p;
|
||||
|
||||
for (i=0; i<ARRAY_SIZE(spi_pinmux_config); i++) {
|
||||
pin = hal_gpio_name2pin(spi_pinmux_config[i].name);
|
||||
if (pin < 0)
|
||||
continue;
|
||||
g = GPIO_GROUP(pin);
|
||||
p = GPIO_GROUP_PIN(pin);
|
||||
hal_gpio_set_func(g, p, spi_pinmux_config[i].func);
|
||||
hal_gpio_set_bias_pull(g, p, spi_pinmux_config[i].bias);
|
||||
hal_gpio_set_drive_strength(g, p, spi_pinmux_config[i].drive);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t qspi_slave_irq_handler(int irq_num, void *arg)
|
||||
{
|
||||
qspi_slave_handle *h = arg;
|
||||
|
||||
rt_interrupt_enter();
|
||||
hal_qspi_slave_irq_handler(h);
|
||||
rt_interrupt_leave();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int test_qspi_slave_controller_init(u32 id, u32 bus_width,
|
||||
qspi_slave_async_cb cb, void *priv,
|
||||
qspi_slave_handle *h)
|
||||
{
|
||||
struct qspi_slave_config cfg;
|
||||
int ret;
|
||||
u32 clk_id, irq_num, clk_in;
|
||||
|
||||
clk_id = qspi_clk_ids[id];
|
||||
irq_num = qspi_irq_num[id];
|
||||
clk_in = qspi_input_clk[id];
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
|
||||
cfg.idx = id;
|
||||
cfg.clk_in_hz = clk_in;
|
||||
cfg.clk_id = clk_id;
|
||||
|
||||
/* Default is Mode0 */
|
||||
cfg.cpol = HAL_QSPI_CPOL_ACTIVE_HIGH;
|
||||
cfg.cpha = HAL_QSPI_CPHA_FIRST_EDGE;
|
||||
cfg.cs_polarity = HAL_QSPI_CS_POL_VALID_LOW;
|
||||
|
||||
ret = hal_qspi_slave_init(h, &cfg);
|
||||
if (ret) {
|
||||
pr_err("hal_qspi_slave_init failed. ret %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hal_qspi_slave_set_bus_width(h, bus_width);
|
||||
|
||||
ret = hal_qspi_slave_register_cb(h, cb, priv);
|
||||
if (ret) {
|
||||
pr_err("qspi register async callback failed.\n");
|
||||
return ret;
|
||||
}
|
||||
aicos_request_irq(irq_num, qspi_slave_irq_handler, 0, NULL, (void *)h);
|
||||
aicos_irq_enable(irq_num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_qspi_slave_controller_deinit(qspi_slave_handle *h)
|
||||
{
|
||||
hal_qspi_slave_deinit(h);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Xuan.Wen <xuan.wen@artinchip.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <finsh.h>
|
||||
#include <rtconfig.h>
|
||||
#include <rtdevice.h>
|
||||
#include <aic_core.h>
|
||||
#include <aic_hal.h>
|
||||
#include <hal_qspi.h>
|
||||
#include <rtthread.h>
|
||||
#include "test_spislave.h"
|
||||
|
||||
#define RUN_STATE_IN 0
|
||||
#define RUN_STATE_OUT 1
|
||||
|
||||
#define MEM_STATE_IDLE 0
|
||||
#define MEM_STATE_CMD 1
|
||||
#define MEM_STATE_DATA 2
|
||||
|
||||
struct qspirecv_state {
|
||||
u32 qspi_id;
|
||||
u32 bus_width;
|
||||
qspi_slave_handle handle;
|
||||
u8 *work_buf;
|
||||
};
|
||||
|
||||
static struct qspirecv_state g_state;
|
||||
|
||||
extern void slave_dump_data(char *msg, u8 *buf, u32 len);
|
||||
static void qspi_usage(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int recv_new_data(struct qspirecv_state *state, u8 *buf, u32 len)
|
||||
{
|
||||
struct qspi_transfer t;
|
||||
int ret;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.rx_data = buf;
|
||||
t.data_len = len;
|
||||
|
||||
// memset(buf, 0, len);
|
||||
// printf("%s, reset rx fifo\n", __func__);
|
||||
hal_qspi_slave_fifo_reset(&state->handle, HAL_QSPI_RX_FIFO);
|
||||
ret = hal_qspi_slave_transfer_async(&state->handle, &t);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qspirecv_slave_async_callback(qspi_slave_handle *h, void *priv)
|
||||
{
|
||||
struct qspirecv_state *state = priv;
|
||||
int status, cnt;
|
||||
u32 *p32, cksum;
|
||||
|
||||
status = hal_qspi_slave_get_status(&state->handle);
|
||||
cnt = 0;
|
||||
if (status == HAL_QSPI_STATUS_OK) {
|
||||
/*
|
||||
* status OK:
|
||||
* TRANSFER DONE or CS INVALID
|
||||
*/
|
||||
// p = state->work_buf;
|
||||
cnt = hal_qspi_slave_transfer_count(&state->handle);
|
||||
printf("%s, status %d, cnt %d\n", __func__, status, cnt);
|
||||
p32 = (void *)state->work_buf;
|
||||
cksum = 0;
|
||||
for (int i = 0; i<PKT_SIZE/4; i++) {
|
||||
cksum += *p32;
|
||||
p32++;
|
||||
}
|
||||
printf("cksum 0x%x\n", cksum);
|
||||
recv_new_data(state, state->work_buf, PKT_SIZE);
|
||||
// slave_dump_data("Data", p, cnt);
|
||||
} else {
|
||||
/* Error process */
|
||||
printf("%s, status %d\n", __func__, status);
|
||||
}
|
||||
}
|
||||
|
||||
static int test_qspirecv_start(int argc, char **argv)
|
||||
{
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
if (argc < 2) {
|
||||
qspi_usage();
|
||||
return -1;
|
||||
}
|
||||
val = strtol(argv[1], NULL, 10);
|
||||
g_state.qspi_id = val;
|
||||
g_state.bus_width = 1; // Default is 1
|
||||
if (g_state.work_buf == NULL)
|
||||
g_state.work_buf =
|
||||
aicos_malloc_align(0, TEST_BUF_SIZE, CACHE_LINE_SIZE);
|
||||
if (argc >= 3) {
|
||||
val = strtol(argv[2], NULL, 10);
|
||||
g_state.bus_width = val;
|
||||
}
|
||||
ret = test_qspi_slave_controller_init(g_state.qspi_id, g_state.bus_width,
|
||||
qspirecv_slave_async_callback, &g_state,
|
||||
&g_state.handle);
|
||||
if (ret) {
|
||||
printf("QSPI Slave init failure.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start with waiting command */
|
||||
recv_new_data(&g_state, g_state.work_buf, PKT_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_qspirecv_stop(int argc, char **argv)
|
||||
{
|
||||
test_qspi_slave_controller_deinit(&g_state.handle);
|
||||
if (g_state.work_buf) {
|
||||
aicos_free_align(0, g_state.work_buf);
|
||||
g_state.work_buf = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmd_test_qspislave_receiver(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
goto help;
|
||||
|
||||
if (!rt_strcmp(argv[1], "help")) {
|
||||
goto help;
|
||||
} else if (!rt_strcmp(argv[1], "start")) {
|
||||
test_qspirecv_start(argc - 1, &argv[1]);
|
||||
return;
|
||||
} else if (!rt_strcmp(argv[1], "stop")) {
|
||||
test_qspirecv_stop(argc - 1, &argv[1]);
|
||||
return;
|
||||
}
|
||||
help:
|
||||
qspi_usage();
|
||||
}
|
||||
|
||||
|
||||
MSH_CMD_EXPORT_ALIAS(cmd_test_qspislave_receiver, spirecv, Test QSPI Slave);
|
||||
@@ -1,238 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, ArtInChip Technology Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Authors: Xuan.Wen <xuan.wen@artinchip.com>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <finsh.h>
|
||||
#include <rtdevice.h>
|
||||
#include <aic_core.h>
|
||||
#include <drv_qspi.h>
|
||||
#include "test_spislave.h"
|
||||
|
||||
struct bus_cfg {
|
||||
u8 cmd; /* CMD bus width */
|
||||
u8 addr; /* Address bus width */
|
||||
u8 dmycyc; /* Dummy clock cycle */
|
||||
u8 data; /* Data bus width */
|
||||
};
|
||||
|
||||
extern void slave_dump_data(char *msg, u8 *buf, u32 len);
|
||||
|
||||
void master_tx(struct rt_qspi_device *qspi, u8 bus_width, u8 *buf, u32 datalen)
|
||||
{
|
||||
struct rt_qspi_message msg;
|
||||
struct bus_cfg cfg;
|
||||
rt_size_t ret;
|
||||
|
||||
cfg.cmd = 0;
|
||||
cfg.addr = 0;
|
||||
cfg.dmycyc = 0;
|
||||
cfg.data = bus_width;
|
||||
|
||||
rt_memset(&msg, 0, sizeof(msg));
|
||||
msg.qspi_data_lines = cfg.data;
|
||||
msg.parent.recv_buf = NULL;
|
||||
msg.parent.send_buf = buf;
|
||||
msg.parent.length = datalen;
|
||||
msg.parent.cs_take = 1;
|
||||
msg.parent.cs_release = 1;
|
||||
rt_spi_take_bus((struct rt_spi_device *)qspi);
|
||||
ret = rt_qspi_transfer_message(qspi, &msg);
|
||||
if (ret != datalen) {
|
||||
printf("master tx failed. ret 0x%x\n", ret);
|
||||
}
|
||||
rt_spi_release_bus((struct rt_spi_device *)qspi);
|
||||
}
|
||||
|
||||
void master_rx(struct rt_qspi_device *qspi, u8 bus_width, u8 *buf, u32 datalen)
|
||||
{
|
||||
struct rt_qspi_message msg;
|
||||
struct bus_cfg cfg;
|
||||
rt_size_t ret;
|
||||
|
||||
cfg.cmd = 0;
|
||||
cfg.addr = 0;
|
||||
cfg.dmycyc = 0;
|
||||
cfg.data = bus_width;
|
||||
|
||||
rt_memset(&msg, 0, sizeof(msg));
|
||||
msg.qspi_data_lines = cfg.data;
|
||||
msg.parent.recv_buf = buf;
|
||||
msg.parent.send_buf = NULL;
|
||||
msg.parent.length = datalen;
|
||||
msg.parent.cs_take = 1;
|
||||
msg.parent.cs_release = 1;
|
||||
rt_spi_take_bus((struct rt_spi_device *)qspi);
|
||||
ret = rt_qspi_transfer_message(qspi, &msg);
|
||||
if (ret != datalen) {
|
||||
printf("master tx failed. ret 0x%x\n", ret);
|
||||
}
|
||||
rt_spi_release_bus((struct rt_spi_device *)qspi);
|
||||
}
|
||||
|
||||
static void slave_get_status(struct rt_qspi_device *qspi, u8 bus_width, u8 *buf,
|
||||
u32 datalen)
|
||||
{
|
||||
master_rx(qspi, bus_width, buf, datalen);
|
||||
}
|
||||
|
||||
void slave_write(struct rt_qspi_device *qspi, u8 bus_width, u8 *buf, u32 datalen, u32 addr)
|
||||
{
|
||||
u8 *work_buf;
|
||||
u32 status;
|
||||
|
||||
work_buf = aicos_malloc_align(0, datalen + 4, CACHE_LINE_SIZE);
|
||||
|
||||
work_buf[0] = MEM_CMD_WRITE;
|
||||
memcpy(&work_buf[1], &addr, 3);
|
||||
memcpy(&work_buf[4], buf, datalen);
|
||||
master_tx(qspi, bus_width, work_buf, datalen + 4);
|
||||
|
||||
rt_thread_mdelay(10);
|
||||
do {
|
||||
status = 0;
|
||||
slave_get_status(qspi, bus_width, (void *)&status, 4);
|
||||
printf("write status 0x%x\n", status);
|
||||
rt_thread_mdelay(1000);
|
||||
} while (status != WRITE_STATUS_VAL);
|
||||
|
||||
aicos_free_align(0, work_buf);
|
||||
}
|
||||
|
||||
static void slave_load_data(struct rt_qspi_device *qspi, u8 bus_width, u32 addr)
|
||||
{
|
||||
u8 work_buf[4];
|
||||
|
||||
work_buf[0] = MEM_CMD_LOAD;
|
||||
memcpy(&work_buf[1], &addr, 3);
|
||||
master_tx(qspi, bus_width, work_buf, 4);
|
||||
}
|
||||
|
||||
static void slave_read_data(struct rt_qspi_device *qspi, u8 bus_width,
|
||||
u8 *buf, u32 datalen)
|
||||
{
|
||||
master_rx(qspi, bus_width, buf, datalen);
|
||||
}
|
||||
|
||||
void slave_read(struct rt_qspi_device *qspi, u8 bus_width, u8 *buf, u32 datalen,
|
||||
u32 addr)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
slave_load_data(qspi, bus_width, addr);
|
||||
rt_thread_mdelay(100);
|
||||
do {
|
||||
status = 0;
|
||||
slave_get_status(qspi, bus_width, (void *)&status, 4);
|
||||
printf("load status 0x%x\n", status);
|
||||
rt_thread_mdelay(1000);
|
||||
} while (status != LOAD_STATUS_VAL);
|
||||
|
||||
slave_read_data(qspi, bus_width, buf, datalen);
|
||||
}
|
||||
|
||||
void test_qspi_slaverw(struct rt_qspi_device *qspi, int argc, char **argv)
|
||||
{
|
||||
u8 *tx_buf, *rx_buf;
|
||||
u8 bus_width;
|
||||
unsigned long val;
|
||||
|
||||
bus_width = 1;
|
||||
|
||||
if (argc >= 2) {
|
||||
val = strtol(argv[1], NULL, 10);
|
||||
bus_width = (u8)val;
|
||||
}
|
||||
tx_buf = aicos_malloc_align(0, TEST_BUF_SIZE, CACHE_LINE_SIZE);
|
||||
rx_buf = aicos_malloc_align(0, TEST_BUF_SIZE, CACHE_LINE_SIZE);
|
||||
for (int i = 0; i < TEST_BUF_SIZE; i++) {
|
||||
tx_buf[i] = i % 256;
|
||||
}
|
||||
|
||||
printf("\nHOST: Write data to address 0\n");
|
||||
slave_write(qspi, bus_width, tx_buf, PKT_SIZE, 0);
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
printf("\nHOST: Write data to address 0\n");
|
||||
slave_write(qspi, bus_width, tx_buf, PKT_SIZE, 0);
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
|
||||
printf("\nHOST: Write data to address 0\n");
|
||||
slave_write(qspi, bus_width, tx_buf, PKT_SIZE, 0);
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
printf("\nHOST: Read data from address 0\n");
|
||||
memset(rx_buf, 0, PKT_SIZE);
|
||||
slave_read(qspi, bus_width, rx_buf, PKT_SIZE, 0);
|
||||
slave_dump_data("Read", rx_buf, PKT_SIZE);
|
||||
|
||||
rt_thread_mdelay(100);
|
||||
printf("\nHOST: Write data to address 0x%x\n", PKT_SIZE);
|
||||
slave_write(qspi, bus_width, tx_buf + PKT_SIZE, PKT_SIZE, PKT_SIZE);
|
||||
rt_thread_mdelay(100);
|
||||
printf("\nHOST: Read data from address 0x10\n");
|
||||
memset(rx_buf, 0, PKT_SIZE);
|
||||
slave_read(qspi, bus_width, rx_buf, PKT_SIZE, 0x10);
|
||||
slave_dump_data("Read", rx_buf, PKT_SIZE);
|
||||
|
||||
printf("\nHOST: Read data from address 0x01\n");
|
||||
memset(rx_buf, 0, PKT_SIZE);
|
||||
slave_read(qspi, bus_width, rx_buf, PKT_SIZE, 0x01);
|
||||
slave_dump_data("Read", rx_buf, PKT_SIZE);
|
||||
|
||||
printf("\nHOST: Read data from address 0x02\n");
|
||||
memset(rx_buf, 0, PKT_SIZE);
|
||||
slave_read(qspi, bus_width, rx_buf, PKT_SIZE, 0x02);
|
||||
slave_dump_data("Read", rx_buf, PKT_SIZE);
|
||||
|
||||
aicos_free_align(0, tx_buf);
|
||||
aicos_free_align(0, rx_buf);
|
||||
}
|
||||
|
||||
void test_qspi_send2slave(struct rt_qspi_device *qspi, int argc, char **argv)
|
||||
{
|
||||
u8 *tx_buf, *rx_buf;
|
||||
u8 bus_width;
|
||||
unsigned long val;
|
||||
u32 cksum, *p;
|
||||
|
||||
bus_width = 1;
|
||||
|
||||
if (argc >= 2) {
|
||||
val = strtol(argv[1], NULL, 10);
|
||||
bus_width = (u8)val;
|
||||
}
|
||||
tx_buf = aicos_malloc_align(0, TEST_BUF_SIZE, CACHE_LINE_SIZE);
|
||||
rx_buf = aicos_malloc_align(0, TEST_BUF_SIZE, CACHE_LINE_SIZE);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
printf("\nHOST: Write data to address 0, round %d\n", i);
|
||||
p = (void *)tx_buf;
|
||||
for (int j = 0; j < TEST_BUF_SIZE; j++) {
|
||||
//tx_buf[i] = 0xA << 4 | (i % 16);
|
||||
// tx_buf[i] = 0xA5;
|
||||
tx_buf[i] = (j + i) % 256;
|
||||
}
|
||||
tx_buf[0] = i;
|
||||
|
||||
cksum = 0;
|
||||
for (int i = 0; i < TEST_BUF_SIZE / 4; i++) {
|
||||
cksum += *p;
|
||||
p++;
|
||||
}
|
||||
printf("ckxsum 0x%x\n", cksum);
|
||||
master_tx(qspi, bus_width, tx_buf, PKT_SIZE);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
}
|
||||
|
||||
aicos_free_align(0, tx_buf);
|
||||
aicos_free_align(0, rx_buf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user