diff --git a/applications/sdp/mspi/CMakeLists.txt b/applications/sdp/mspi/CMakeLists.txt new file mode 100644 index 000000000000..338d1d7ad562 --- /dev/null +++ b/applications/sdp/mspi/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(sdp_mspi) + +sdp_assembly_generate("${CMAKE_SOURCE_DIR}/src/hrt/hrt.c") +sdp_assembly_check("${CMAKE_SOURCE_DIR}/src/hrt/hrt.c") +sdp_assembly_prepare_install("${CMAKE_SOURCE_DIR}/src/hrt/hrt.c") + +target_sources(app PRIVATE src/main.c) +target_sources(app PRIVATE src/hrt/hrt.s) + +add_dependencies(app asm_check) diff --git a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf new file mode 100644 index 000000000000..6c1b7543e212 --- /dev/null +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf @@ -0,0 +1,46 @@ +# Single-threaded +CONFIG_MULTITHREADING=n +CONFIG_KERNEL_MEM_POOL=n +CONFIG_LOG=n + +# Drivers and peripherals +CONFIG_I2C=n +CONFIG_WATCHDOG=n +CONFIG_GPIO=n +CONFIG_PINCTRL=n +CONFIG_SPI=n +CONFIG_SERIAL=n +CONFIG_FLASH=n + +# Power management +CONFIG_PM=n + +# Interrupts +CONFIG_DYNAMIC_INTERRUPTS=n +CONFIG_IRQ_OFFLOAD=n +CONFIG_GEN_SW_ISR_TABLE=n + +# Memory protection +CONFIG_THREAD_STACK_INFO=n +CONFIG_THREAD_CUSTOM_DATA=n +CONFIG_FPU=n + +# Boot +CONFIG_BOOT_BANNER=n +CONFIG_NCS_BOOT_BANNER=n + +# Console +CONFIG_CONSOLE=n +CONFIG_UART_CONSOLE=n +CONFIG_STDOUT_CONSOLE=n +CONFIG_PRINTK=n +CONFIG_EARLY_CONSOLE=n + +# Build +CONFIG_SIZE_OPTIMIZATIONS=y + +# No timer support in the kernel +CONFIG_SYS_CLOCK_EXISTS=n + +CONFIG_OUTPUT_DISASSEMBLY=y +CONFIG_COMMON_LIBC_MALLOC=n diff --git a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay new file mode 100644 index 000000000000..4afa34f53f35 --- /dev/null +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +&gpio0 { + status = "disabled"; +}; + +&gpio1 { + status = "disabled"; +}; + +&gpio2 { + status = "disabled"; +}; + +&gpiote20 { + status = "disabled"; +}; + +&gpiote30 { + status = "disabled"; +}; + +&grtc { + status = "disabled"; +}; + +&uart20 { + status = "disabled"; +}; + +&uart30 { + status = "disabled"; +}; + +&pwm20 { + status = "disabled"; +}; diff --git a/applications/sdp/mspi/prj.conf b/applications/sdp/mspi/prj.conf new file mode 100644 index 000000000000..33d849aaadd3 --- /dev/null +++ b/applications/sdp/mspi/prj.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX=n +CONFIG_IPC_SERVICE=n +CONFIG_IPC_SERVICE_BACKEND_ICMSG=n diff --git a/applications/sdp/mspi/sample.yaml b/applications/sdp/mspi/sample.yaml new file mode 100644 index 000000000000..5baf87658636 --- /dev/null +++ b/applications/sdp/mspi/sample.yaml @@ -0,0 +1,12 @@ +sample: + name: SDP mSPI application + description: SDP mSPI application +common: + integration_platforms: + - nrf54l15dk/nrf54l15/cpuflpr +tests: + applications.sdp.mspi.icmsg: + build_only: true + sysbuild: true + platform_allow: nrf54l15dk/nrf54l15/cpuflpr + tags: ci_build sysbuild mspi diff --git a/applications/sdp/mspi/src/hrt/hrt.c b/applications/sdp/mspi/src/hrt/hrt.c new file mode 100644 index 000000000000..35e8bd3ff8bb --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include "hrt.h" +#include +#include + +#define CLK_FIRST_CYCLE_MULTIPLICATOR (3) + +void write_single_by_word(volatile struct hrt_ll_xfer xfer_ll_params) +{ + uint16_t dir; + uint16_t out; + nrf_vpr_csr_vio_config_t config; + nrf_vpr_csr_vio_mode_out_t out_mode = { + .mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE, + .frame_width = 1, + }; + + NRFX_ASSERT(xfer_ll_params.word_size <= MAX_WORD_SIZE); + /* Configuration step */ + dir = nrf_vpr_csr_vio_dir_get(); + + nrf_vpr_csr_vio_dir_set(dir | PIN_DIR_OUT_MASK(D0_PIN)); + + out = nrf_vpr_csr_vio_out_get(); + + nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(D0_PIN)); + + nrf_vpr_csr_vio_mode_out_set(&out_mode); + nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS); + + nrf_vpr_csr_vio_config_get(&config); + config.input_sel = false; + nrf_vpr_csr_vio_config_set(&config); + + /* Fix position of data if word size < MAX_WORD_SIZE, + * so that leading zeros would not be printed instead of data bits. + */ + if (xfer_ll_params.word_size < MAX_WORD_SIZE) { + for (uint8_t i = 0; i < xfer_ll_params.data_len; i++) { + xfer_ll_params.data_to_send[i] = + xfer_ll_params.data_to_send[i] + << (MAX_WORD_SIZE - xfer_ll_params.word_size); + } + } + + /* Counter settings */ + nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_RELOAD); + nrf_vpr_csr_vtim_simple_counter_top_set(0, xfer_ll_params.counter_top); + + /* Set number of shifts before OUTB needs to be updated. + * First shift needs to be increased by 1. + */ + nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params.word_size); + nrf_vpr_csr_vio_shift_cnt_out_buffered_set(xfer_ll_params.word_size - 1); + + /* Enable CS */ + out = nrf_vpr_csr_vio_out_get(); + out &= ~PIN_OUT_HIGH_MASK(CS_PIN); + out |= xfer_ll_params.ce_enable_state ? PIN_OUT_HIGH_MASK(CS_PIN) + : PIN_OUT_LOW_MASK(CS_PIN); + nrf_vpr_csr_vio_out_set(out); + + /* Start counter */ + nrf_vpr_csr_vtim_simple_counter_set(0, CLK_FIRST_CYCLE_MULTIPLICATOR * + xfer_ll_params.counter_top); + + /* Send data */ + for (uint8_t i = 0; i < xfer_ll_params.data_len; i++) { + nrf_vpr_csr_vio_out_buffered_reversed_byte_set(xfer_ll_params.data_to_send[i]); + } + + /* Clear all bits, wait until the last word is sent */ + nrf_vpr_csr_vio_out_buffered_set(0); + + /* Final configuration */ + out_mode.mode = NRF_VPR_CSR_VIO_SHIFT_NONE; + nrf_vpr_csr_vio_mode_out_buffered_set(&out_mode); + nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS); + + /* Disable CS */ + if (!xfer_ll_params.ce_hold) { + out = nrf_vpr_csr_vio_out_get(); + out &= ~(PIN_OUT_HIGH_MASK(CS_PIN) | PIN_OUT_HIGH_MASK(SCLK_PIN)); + out |= xfer_ll_params.ce_enable_state ? PIN_OUT_LOW_MASK(CS_PIN) + : PIN_OUT_HIGH_MASK(CS_PIN); + nrf_vpr_csr_vio_out_set(out); + } + + /* Stop counter */ + nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP); +} + +void write_quad_by_word(volatile struct hrt_ll_xfer xfer_ll_params) +{ + uint16_t dir; + uint16_t out; + nrf_vpr_csr_vio_config_t config; + nrf_vpr_csr_vio_mode_out_t out_mode = { + .mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE, + .frame_width = 4, + }; + + NRFX_ASSERT(xfer_ll_params.word_size % 4 == 0); + NRFX_ASSERT(xfer_ll_params.word_size <= MAX_WORD_SIZE); + /* Configuration step */ + dir = nrf_vpr_csr_vio_dir_get(); + + nrf_vpr_csr_vio_dir_set(dir | PIN_DIR_OUT_MASK(D0_PIN) | PIN_DIR_OUT_MASK(D1_PIN) | + PIN_DIR_OUT_MASK(D2_PIN) | PIN_DIR_OUT_MASK(D3_PIN)); + + out = nrf_vpr_csr_vio_out_get(); + + nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(D0_PIN) | PIN_OUT_LOW_MASK(D1_PIN) | + PIN_OUT_LOW_MASK(D2_PIN) | PIN_OUT_LOW_MASK(D3_PIN)); + + nrf_vpr_csr_vio_mode_out_set(&out_mode); + nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS); + + nrf_vpr_csr_vio_config_get(&config); + config.input_sel = false; + nrf_vpr_csr_vio_config_set(&config); + + /* Fix position of data if word size < MAX_WORD_SIZE, + * so that leading zeros would not be printed instead of data. + */ + if (xfer_ll_params.word_size < MAX_WORD_SIZE) { + for (uint8_t i = 0; i < xfer_ll_params.data_len; i++) { + xfer_ll_params.data_to_send[i] = + xfer_ll_params.data_to_send[i] + << (MAX_WORD_SIZE - xfer_ll_params.word_size); + } + } + + /* Counter settings */ + nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_RELOAD); + nrf_vpr_csr_vtim_simple_counter_top_set(0, xfer_ll_params.counter_top); + + /* Set number of shifts before OUTB needs to be updated. + * First shift needs to be increased by 1. + */ + nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params.word_size / 4); + nrf_vpr_csr_vio_shift_cnt_out_buffered_set(xfer_ll_params.word_size / 4 - 1); + + /* Enable CS */ + out = nrf_vpr_csr_vio_out_get(); + out &= ~PIN_OUT_HIGH_MASK(CS_PIN); + out |= xfer_ll_params.ce_enable_state ? PIN_OUT_HIGH_MASK(CS_PIN) + : PIN_OUT_LOW_MASK(CS_PIN); + nrf_vpr_csr_vio_out_set(out); + + /* Start counter */ + nrf_vpr_csr_vtim_simple_counter_set(0, 3 * xfer_ll_params.counter_top); + + /* Send data */ + for (uint8_t i = 0; i < xfer_ll_params.data_len; i++) { + nrf_vpr_csr_vio_out_buffered_reversed_byte_set(xfer_ll_params.data_to_send[i]); + } + + /* Clear all bits, wait until the last word is sent */ + nrf_vpr_csr_vio_out_buffered_set(0); + + /* Final configuration */ + out_mode.mode = NRF_VPR_CSR_VIO_SHIFT_NONE; + nrf_vpr_csr_vio_mode_out_buffered_set(&out_mode); + nrf_vpr_csr_vio_mode_in_buffered_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS); + + /* Disable CS */ + if (!xfer_ll_params.ce_hold) { + out = nrf_vpr_csr_vio_out_get(); + out &= ~(PIN_OUT_HIGH_MASK(CS_PIN) | PIN_OUT_HIGH_MASK(SCLK_PIN)); + out |= xfer_ll_params.ce_enable_state ? PIN_OUT_LOW_MASK(CS_PIN) + : PIN_OUT_HIGH_MASK(CS_PIN); + nrf_vpr_csr_vio_out_set(out); + } + + /* Stop counter */ + nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP); +} diff --git a/applications/sdp/mspi/src/hrt/hrt.h b/applications/sdp/mspi/src/hrt/hrt.h new file mode 100644 index 000000000000..c5e47618720d --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef _HRT_H__ +#define _HRT_H__ + +#include +#include + +#define SCLK_PIN 0 +#define D0_PIN 1 +#define D1_PIN 2 +#define D2_PIN 3 +#define D3_PIN 4 +#define CS_PIN 5 + +/* Max word size. */ +#define MAX_WORD_SIZE NRF_VPR_CSR_VIO_SHIFT_CNT_OUT_BUFFERED_MAX + +/* Macro for getting direction mask for specified pin and direction. */ +#define PIN_DIR_MASK(PIN_NUM, DIR) \ + (VPRCSR_NORDIC_DIR_PIN##PIN_NUM##_##DIR << VPRCSR_NORDIC_DIR_PIN##PIN_NUM##_Pos) + +/* Macro for getting output mask for specified pin. */ +#define PIN_DIR_OUT_MASK(PIN_NUM) PIN_DIR_MASK(PIN_NUM, OUTPUT) + +/* Macro for getting input mask for specified pin. */ +#define PIN_DIR_IN_MASK(PIN_NUM) PIN_DIR_MASK(PIN_NUM, INPUT) + +/* Macro for getting state mask for specified pin and state. */ +#define PIN_OUT_MASK(PIN_NUM, STATE) \ + (VPRCSR_NORDIC_OUT_PIN##PIN_NUM##_##STATE << VPRCSR_NORDIC_OUT_PIN##PIN_NUM##_Pos) + +/* Macro for getting high state mask for specified pin. */ +#define PIN_OUT_HIGH_MASK(PIN_NUM) PIN_OUT_MASK(PIN_NUM, HIGH) + +/* Macro for getting low state mask for specified pin. */ +#define PIN_OUT_LOW_MASK(PIN_NUM) PIN_OUT_MASK(PIN_NUM, LOW) + +/** @brief Low level transfer parameters. */ +struct hrt_ll_xfer { + /** @brief Top value of VTIM. This will determine clock frequency + * (SPI_CLOCK ~= CPU_CLOCK / (2 * TOP)). + */ + volatile uint8_t counter_top; + + /** @brief Word size of passed data, bits. */ + volatile uint8_t word_size; + + /** @brief Data to send, under each index there is data of length word_size. */ + volatile uint32_t *data_to_send; + + /** @brief Data length. */ + volatile uint8_t data_len; + + /** @brief If true chip enable pin will be left active after transfer */ + volatile uint8_t ce_hold; + + /** @brief Chip enable pin polarity in enabled state. */ + volatile bool ce_enable_state; +}; + +/** @brief Write on single line. + * + * Function to be used to write data on single data line (SPI). + * + * @param[in] xfer_ll_params Low level transfer parameters. + */ +void write_single_by_word(volatile struct hrt_ll_xfer xfer_ll_params); + +/** @brief Write on four lines. + * + * Function to be used to write data on quad data line (SPI). + * + * @param[in] xfer_ll_params Low level transfer parameters. + */ +void write_quad_by_word(volatile struct hrt_ll_xfer xfer_ll_params); + +#endif /* _HRT_H__ */ diff --git a/applications/sdp/mspi/src/hrt/hrt.s b/applications/sdp/mspi/src/hrt/hrt.s new file mode 100644 index 000000000000..5e9923fce21c --- /dev/null +++ b/applications/sdp/mspi/src/hrt/hrt.s @@ -0,0 +1,288 @@ + .file "hrt.c" + .option nopic + .attribute arch, "rv32e1p9_m2p0_c2p0_zicsr2p0" + .attribute unaligned_access, 0 + .attribute stack_align, 4 + .text + .section .text.write_single_by_word,"ax",@progbits + .align 1 + .globl write_single_by_word + .type write_single_by_word, @function +write_single_by_word: + #APP + csrr a5, 3009 + #NO_APP + ori a5,a5,2 + slli a5,a5,16 + srli a5,a5,16 + #APP + csrw 3009, a5 + csrr a5, 3008 + #NO_APP + slli a5,a5,16 + srli a5,a5,16 + #APP + csrw 3008, a5 + #NO_APP + li a5,65536 + addi a5,a5,4 + #APP + csrw 3043, a5 + csrw 3045, 0 + csrr a5, 1996 + #NO_APP + andi a5,a5,17 + #APP + csrw 1996, a5 + #NO_APP + lbu a4,1(a0) + li a5,31 + bleu a4,a5,.L8 +.L5: + #APP + csrw 2000, 2 + #NO_APP + lbu a5,0(a0) + andi a5,a5,0xff + #APP + csrr a4, 2003 + #NO_APP + li a3,-65536 + and a4,a4,a3 + or a5,a5,a4 + #APP + csrw 2003, a5 + #NO_APP + lbu a5,1(a0) + #APP + csrw 3022, a5 + #NO_APP + lbu a5,1(a0) + addi a5,a5,-1 + andi a5,a5,0xff + #APP + csrw 3023, a5 + csrr a5, 3008 + #NO_APP + lbu a4,10(a0) + andi a5,a5,-33 + slli a5,a5,16 + slli a4,a4,5 + srli a5,a5,16 + or a5,a5,a4 + #APP + csrw 3008, a5 + #NO_APP + lbu a5,0(a0) + li a4,3 + mul a5,a5,a4 + #APP + csrw 2005, a5 + #NO_APP + li a5,0 +.L3: + lbu a4,8(a0) + bgtu a4,a5,.L6 + #APP + csrw 3012, 0 + #NO_APP + li a5,65536 + #APP + csrw 3043, a5 + csrw 3045, 0 + #NO_APP + lbu a5,9(a0) + bne a5,zero,.L7 + #APP + csrr a5, 3008 + #NO_APP + lbu a4,10(a0) + andi a5,a5,-34 + slli a5,a5,16 + xori a4,a4,1 + slli a4,a4,5 + srli a5,a5,16 + or a5,a5,a4 + #APP + csrw 3008, a5 + #NO_APP +.L7: + #APP + csrw 2000, 0 + #NO_APP + ret +.L4: + lw a4,4(a0) + slli t1,a5,2 + addi a5,a5,1 + add a4,a4,t1 + lw a3,0(a4) + lbu a2,1(a0) + lw a4,4(a0) + andi a5,a5,0xff + sub a2,a1,a2 + add a4,a4,t1 + sll a3,a3,a2 + sw a3,0(a4) +.L2: + lbu a4,8(a0) + bgtu a4,a5,.L4 + j .L5 +.L8: + li a5,0 + li a1,32 + j .L2 +.L6: + lw a4,4(a0) + slli a3,a5,2 + add a4,a4,a3 + lw a4,0(a4) + #APP + csrw 3016, a4 + #NO_APP + addi a5,a5,1 + andi a5,a5,0xff + j .L3 + .size write_single_by_word, .-write_single_by_word + .section .text.write_quad_by_word,"ax",@progbits + .align 1 + .globl write_quad_by_word + .type write_quad_by_word, @function +write_quad_by_word: + #APP + csrr a5, 3009 + #NO_APP + ori a5,a5,30 + slli a5,a5,16 + srli a5,a5,16 + #APP + csrw 3009, a5 + csrr a5, 3008 + #NO_APP + slli a5,a5,16 + srli a5,a5,16 + #APP + csrw 3008, a5 + #NO_APP + li a5,262144 + addi a5,a5,4 + #APP + csrw 3043, a5 + csrw 3045, 0 + csrr a5, 1996 + #NO_APP + andi a5,a5,17 + #APP + csrw 1996, a5 + #NO_APP + lbu a4,1(a0) + li a5,31 + bleu a4,a5,.L16 +.L13: + #APP + csrw 2000, 2 + #NO_APP + lbu a5,0(a0) + andi a5,a5,0xff + #APP + csrr a4, 2003 + #NO_APP + li a3,-65536 + and a4,a4,a3 + or a5,a5,a4 + #APP + csrw 2003, a5 + #NO_APP + lbu a5,1(a0) + srli a5,a5,2 + #APP + csrw 3022, a5 + #NO_APP + lbu a5,1(a0) + srli a5,a5,2 + addi a5,a5,-1 + andi a5,a5,0xff + #APP + csrw 3023, a5 + csrr a5, 3008 + #NO_APP + lbu a4,10(a0) + andi a5,a5,-33 + slli a5,a5,16 + slli a4,a4,5 + srli a5,a5,16 + or a5,a5,a4 + #APP + csrw 3008, a5 + #NO_APP + lbu a5,0(a0) + li a4,3 + mul a5,a5,a4 + #APP + csrw 2005, a5 + #NO_APP + li a5,0 +.L11: + lbu a4,8(a0) + bgtu a4,a5,.L14 + #APP + csrw 3012, 0 + #NO_APP + li a5,262144 + #APP + csrw 3043, a5 + csrw 3045, 0 + #NO_APP + lbu a5,9(a0) + bne a5,zero,.L15 + #APP + csrr a5, 3008 + #NO_APP + lbu a4,10(a0) + andi a5,a5,-34 + slli a5,a5,16 + xori a4,a4,1 + slli a4,a4,5 + srli a5,a5,16 + or a5,a5,a4 + #APP + csrw 3008, a5 + #NO_APP +.L15: + #APP + csrw 2000, 0 + #NO_APP + ret +.L12: + lw a4,4(a0) + slli t1,a5,2 + addi a5,a5,1 + add a4,a4,t1 + lw a3,0(a4) + lbu a2,1(a0) + lw a4,4(a0) + andi a5,a5,0xff + sub a2,a1,a2 + add a4,a4,t1 + sll a3,a3,a2 + sw a3,0(a4) +.L10: + lbu a4,8(a0) + bgtu a4,a5,.L12 + j .L13 +.L16: + li a5,0 + li a1,32 + j .L10 +.L14: + lw a4,4(a0) + slli a3,a5,2 + add a4,a4,a3 + lw a4,0(a4) + #APP + csrw 3016, a4 + #NO_APP + addi a5,a5,1 + andi a5,a5,0xff + j .L11 + .size write_quad_by_word, .-write_quad_by_word diff --git a/applications/sdp/mspi/src/main.c b/applications/sdp/mspi/src/main.c new file mode 100644 index 000000000000..69a85649a489 --- /dev/null +++ b/applications/sdp/mspi/src/main.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "./hrt/hrt.h" + +#include +#include +#include +#include +#include + +#include + +#define MAX_DATA_LEN 256 + +#define XFER_COMMAND_IDX (0) +#define XFER_ADDRESS_IDX (1) +#define XFER_DATA_IDX (2) + +#define HRT_IRQ_PRIORITY 2 +#define HRT_VEVIF_IDX_WRITE_SINGLE 17 +#define HRT_VEVIF_IDX_WRITE_QUAD 18 + +/* How many words are needed for given amount of bytes.*/ +#define WORDS_FOR_BYTES(bytes) ((bytes - 1) / 4 + 1) + +#define VEVIF_IRQN(vevif) VEVIF_IRQN_1(vevif) +#define VEVIF_IRQN_1(vevif) VPRCLIC_##vevif##_IRQn + +struct mspi_config { + uint8_t *data; + uint8_t data_len; + uint8_t word_size; +}; + +struct mspi_dev_config { + enum mspi_io_mode io_mode; + enum mspi_ce_polarity ce_polarity; + uint32_t read_cmd; + uint32_t write_cmd; + uint8_t cmd_length; /* Command length in bits. */ + uint8_t addr_length; /* Address length in bits. */ +}; + +static struct mspi_dev_config mspi_dev_configs; + +uint32_t data_buffer[MAX_DATA_LEN + 2]; + +volatile struct hrt_ll_xfer xfer_ll_params = { + .counter_top = 4, + .word_size = 4, + .data_to_send = NULL, + .data_len = 0, + .ce_hold = false, + .ce_enable_state = false, +}; + +void configure_clock(enum mspi_cpp_mode cpp_mode) +{ + nrf_vpr_csr_vio_config_t vio_config = { + .input_sel = 0, + .stop_cnt = 0, + }; + + nrf_vpr_csr_vio_dir_set(PIN_DIR_OUT_MASK(SCLK_PIN)); + + switch (cpp_mode) { + case MSPI_CPP_MODE_0: { + vio_config.clk_polarity = 0; + nrf_vpr_csr_vio_out_set(PIN_OUT_LOW_MASK(SCLK_PIN)); + break; + } + case MSPI_CPP_MODE_1: { + vio_config.clk_polarity = 1; + nrf_vpr_csr_vio_out_set(PIN_OUT_LOW_MASK(SCLK_PIN)); + break; + } + case MSPI_CPP_MODE_2: { + vio_config.clk_polarity = 1; + nrf_vpr_csr_vio_out_set(PIN_OUT_HIGH_MASK(SCLK_PIN)); + break; + } + case MSPI_CPP_MODE_3: { + vio_config.clk_polarity = 0; + nrf_vpr_csr_vio_out_set(PIN_OUT_HIGH_MASK(SCLK_PIN)); + break; + } + } + + nrf_vpr_csr_vio_config_set(&vio_config); +} + +void prepare_and_send_data(uint8_t *data, uint8_t data_length) +{ + memcpy(&(data_buffer[2]), data, data_length); + + /* Send command */ + xfer_ll_params.ce_hold = true; + xfer_ll_params.word_size = mspi_dev_configs.cmd_length; + xfer_ll_params.data_len = 1; + xfer_ll_params.data_to_send = data_buffer; + + if (mspi_dev_configs.io_mode == MSPI_IO_MODE_QUAD) { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_QUAD)); + } else { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_SINGLE)); + } + + /* Send address */ + xfer_ll_params.word_size = mspi_dev_configs.addr_length; + xfer_ll_params.data_to_send = data_buffer + XFER_ADDRESS_IDX; + + if (mspi_dev_configs.io_mode == MSPI_IO_MODE_SINGLE || + mspi_dev_configs.io_mode == MSPI_IO_MODE_QUAD_1_1_4) { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_SINGLE)); + } else { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_QUAD)); + } + + /* Send data */ + xfer_ll_params.ce_hold = false; + xfer_ll_params.word_size = 32; + /* TODO: this system needs to be fixed as for now, + * there are problems when (data_length%4) != 0 + */ + xfer_ll_params.data_len = WORDS_FOR_BYTES(data_length); + xfer_ll_params.data_to_send = data_buffer + XFER_DATA_IDX; + + if (mspi_dev_configs.io_mode == MSPI_IO_MODE_SINGLE) { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_SINGLE)); + } else { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_QUAD)); + } +} + +__attribute__((interrupt)) void hrt_handler_write_single(void) +{ + xfer_ll_params.ce_enable_state = (mspi_dev_configs.ce_polarity == MSPI_CE_ACTIVE_HIGH); + + write_single_by_word(xfer_ll_params); +} + +__attribute__((interrupt)) void hrt_handler_write_quad(void) +{ + xfer_ll_params.ce_enable_state = (mspi_dev_configs.ce_polarity == MSPI_CE_ACTIVE_HIGH); + + write_quad_by_word(xfer_ll_params); +} + +int main(void) +{ + uint16_t direction; + uint16_t output; + + /* This is temporary sample data. */ + uint8_t data[30] = {0xa3, 0x21, 0x54, 0x3a, 0x55, 0xa5, 0x45, 0x35, 0x34, 0x23, + 0xa3, 0xad, 0x97, 0xb2, 0x56, 0x54, 0x38, 0x88, 0x0, 0x5, + 0x33, 0x6, 0x34, 0x6, 0x57, 0x7, 0xbb, 0xba, 0xa3, 0xf6}; + + /* This pin initialization is temporary until code is merged with app with GPIO + * initialization + */ + nrf_gpio_pin_dir_t dir = NRF_GPIO_PIN_DIR_OUTPUT; + nrf_gpio_pin_input_t input = NRF_GPIO_PIN_INPUT_DISCONNECT; + nrf_gpio_pin_pull_t pull = NRF_GPIO_PIN_NOPULL; + nrf_gpio_pin_drive_t drive = NRF_GPIO_PIN_E0E1; + + IRQ_DIRECT_CONNECT(HRT_VEVIF_IDX_WRITE_SINGLE, HRT_IRQ_PRIORITY, hrt_handler_write_single, + 0); + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_SINGLE), true); + + IRQ_DIRECT_CONNECT(HRT_VEVIF_IDX_WRITE_QUAD, HRT_IRQ_PRIORITY, hrt_handler_write_quad, 0); + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE_QUAD), true); + + nrf_vpr_csr_rtperiph_enable_set(true); + + /* This pin initialization is temporary until code is merged with app with GPIO + * initialization + */ + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, SCLK_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, D0_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, D1_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, D2_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, D3_PIN), &dir, &input, &pull, &drive, NULL); + nrfy_gpio_reconfigure(NRF_GPIO_PIN_MAP(2, CS_PIN), &dir, &input, &pull, &drive, NULL); + + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, SCLK_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, D0_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, D1_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, D2_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, D3_PIN), NRF_GPIO_PIN_SEL_VPR); + nrfy_gpio_pin_control_select(NRF_GPIO_PIN_MAP(2, CS_PIN), NRF_GPIO_PIN_SEL_VPR); + + configure_clock(MSPI_CPP_MODE_0); + + direction = nrf_vpr_csr_vio_dir_get(); + + nrf_vpr_csr_vio_dir_set(direction | PIN_DIR_OUT_MASK(CS_PIN)); + + output = nrf_vpr_csr_vio_out_get(); + + nrf_vpr_csr_vio_out_set(output | PIN_OUT_HIGH_MASK(CS_PIN)); + + mspi_dev_configs.ce_polarity = MSPI_CE_ACTIVE_LOW; + mspi_dev_configs.io_mode = MSPI_IO_MODE_SINGLE; + mspi_dev_configs.cmd_length = 32; + mspi_dev_configs.addr_length = 32; + + /* This is here only temporarly to set command and address parameters. */ + data_buffer[XFER_COMMAND_IDX] = 0xe5b326c1; + data_buffer[XFER_ADDRESS_IDX] = 0xaabbccdd; + + prepare_and_send_data(data, 30); + + mspi_dev_configs.io_mode = MSPI_IO_MODE_QUAD; + + prepare_and_send_data(data, 30); + + while (true) { + k_cpu_idle(); + } + + return 0; +} diff --git a/applications/sdp/mspi/sysbuild.conf b/applications/sdp/mspi/sysbuild.conf new file mode 100644 index 000000000000..6408669a8474 --- /dev/null +++ b/applications/sdp/mspi/sysbuild.conf @@ -0,0 +1 @@ +SB_CONFIG_PARTITION_MANAGER=n diff --git a/cmake/sdp.cmake b/cmake/sdp.cmake index bbe5100533da..573ffe0e1c1e 100644 --- a/cmake/sdp.cmake +++ b/cmake/sdp.cmake @@ -37,10 +37,10 @@ function(sdp_assembly_generate hrt_srcs) endif() get_filename_component(src_filename ${hrt_src} NAME_WE) # filename without extension add_custom_command(TARGET asm_gen + PRE_BUILD BYPRODUCTS ${src_filename}-temp.s COMMAND ${CMAKE_C_COMPILER} ${compiler_options} ${hrt_opts} -S ${hrt_src} -o ${src_filename}-temp.s COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_NRF_MODULE_DIR}/scripts/sdp/remove_comments.py ${src_filename}-temp.s - DEPENDS ${hrt_src} COMMAND_EXPAND_LISTS COMMENT "Generating ASM file for ${hrt_src}" )