diff --git a/applications/sdp/mspi/CMakeLists.txt b/applications/sdp/mspi/CMakeLists.txt index 338d1d7ad562..3bf82cf56770 100644 --- a/applications/sdp/mspi/CMakeLists.txt +++ b/applications/sdp/mspi/CMakeLists.txt @@ -14,6 +14,6 @@ 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) +target_sources(app PRIVATE src/hrt/hrt.c) 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 index 6c1b7543e212..4a8a0c4d05c6 100644 --- a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf @@ -44,3 +44,5 @@ CONFIG_SYS_CLOCK_EXISTS=n CONFIG_OUTPUT_DISASSEMBLY=y CONFIG_COMMON_LIBC_MALLOC=n + +CONFIG_COMPILER_OPT="-fshort-enums" \ No newline at end of file diff --git a/applications/sdp/mspi/sample.yaml b/applications/sdp/mspi/sample.yaml index 9eba8063d713..a3c84c2d6056 100644 --- a/applications/sdp/mspi/sample.yaml +++ b/applications/sdp/mspi/sample.yaml @@ -10,3 +10,5 @@ tests: sysbuild: true platform_allow: nrf54l15dk/nrf54l15/cpuflpr tags: ci_build sysbuild mspi + required_snippets: + - sdp-mspi diff --git a/applications/sdp/mspi/src/hrt/hrt.c b/applications/sdp/mspi/src/hrt/hrt.c index b4588856e1e9..a26ccc81e225 100644 --- a/applications/sdp/mspi/src/hrt/hrt.c +++ b/applications/sdp/mspi/src/hrt/hrt.c @@ -6,183 +6,102 @@ #include "hrt.h" #include #include +#include +#include -#define CLK_FIRST_CYCLE_MULTIPLICATOR (3) - -void write_single_by_word(volatile struct hrt_ll_xfer xfer_ll_params) +void hrt_write(volatile struct hrt_ll_xfer xfer_ll_params) { - uint16_t dir; + uint8_t shift_count; 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, + .mode = NRF_VPR_CSR_VIO_SHIFT_NONE, .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(VIO(NRFE_MSPI_DQ0_PIN_NUMBER))); + NRFX_ASSERT((xfer_ll_params.last_word_clocks != 1) || (xfer_ll_params.words == 1)) + /* Enable CS */ out = nrf_vpr_csr_vio_out_get(); - nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ0_PIN_NUMBER))); - - 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); - } + if (xfer_ll_params.ce_polarity == MSPI_CE_ACTIVE_LOW) { + out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_LOW); + } else { + out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_HIGH); } - - /* 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(VIO(NRFE_MSPI_CS0_PIN_NUMBER)); - out |= xfer_ll_params.ce_enable_state ? PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER)) - : PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER)); 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); + for (uint32_t i = 0; i < xfer_ll_params.words; i++) { + switch (xfer_ll_params.words - i) { + case 1: /* Last transfer */ + nrf_vpr_csr_vio_shift_cnt_out_buffered_set(xfer_ll_params.last_word_clocks - + 1); + switch (xfer_ll_params.bit_order) { + case HRT_BO_NORMAL: + nrf_vpr_csr_vio_out_buffered_set(xfer_ll_params.last_word); + break; + case HRT_BO_REVERSED_BYTE: + nrf_vpr_csr_vio_out_buffered_reversed_byte_set( + xfer_ll_params.last_word); + break; + case HRT_BO_REVERSED_WORD: + nrf_vpr_csr_vio_out_buffered_reversed_word_set( + xfer_ll_params.last_word); + break; + } + break; + case 2: /* Last but one transfer.*/ + nrf_vpr_csr_vio_shift_cnt_out_buffered_set( + xfer_ll_params.penultimate_word_clocks - 1); + + /* Intentional fallthrough. */ + default: + switch (xfer_ll_params.bit_order) { + case HRT_BO_NORMAL: + nrf_vpr_csr_vio_out_buffered_set( + ((uint32_t *)xfer_ll_params.data)[i]); + break; + case HRT_BO_REVERSED_BYTE: + nrf_vpr_csr_vio_out_buffered_reversed_byte_set( + ((uint32_t *)xfer_ll_params.data)[i]); + break; + case HRT_BO_REVERSED_WORD: + nrf_vpr_csr_vio_out_buffered_reversed_word_set( + ((uint32_t *)xfer_ll_params.data)[i]); + break; + } + } - /* 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]); + if (i == 0) { + /* Start counter */ + nrf_vpr_csr_vtim_simple_counter_set(0, + xfer_ll_params.counter_initial_value); + /* Wait for first clock cycle */ + shift_count = nrf_vpr_csr_vio_shift_cnt_out_get(); + while (nrf_vpr_csr_vio_shift_cnt_out_get() == shift_count) { + } + } } /* 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(VIO(NRFE_MSPI_CS0_PIN_NUMBER)) | - PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_SCK_PIN_NUMBER))); - out |= xfer_ll_params.ce_enable_state - ? PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER)) - : PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER)); - 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(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)) | - PIN_DIR_OUT_MASK(VIO(NRFE_MSPI_DQ1_PIN_NUMBER)) | - PIN_DIR_OUT_MASK(VIO(NRFE_MSPI_DQ2_PIN_NUMBER)) | - PIN_DIR_OUT_MASK(VIO(NRFE_MSPI_DQ3_PIN_NUMBER))); - - out = nrf_vpr_csr_vio_out_get(); - - nrf_vpr_csr_vio_out_set(out | PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)) | - PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ1_PIN_NUMBER)) | - PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ2_PIN_NUMBER)) | - PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_DQ3_PIN_NUMBER))); - - 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); + out = nrf_vpr_csr_vio_out_get(); - /* 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); + if (xfer_ll_params.ce_polarity == MSPI_CE_ACTIVE_LOW) { + out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_HIGH); + } else { + out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_LOW); } - } - - /* 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(VIO(NRFE_MSPI_CS0_PIN_NUMBER)); - out |= xfer_ll_params.ce_enable_state ? PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER)) - : PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER)); - 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(VIO(NRFE_MSPI_CS0_PIN_NUMBER)) | - PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_SCK_PIN_NUMBER))); - out |= xfer_ll_params.ce_enable_state - ? PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER)) - : PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER)); nrf_vpr_csr_vio_out_set(out); } /* Stop counter */ nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP); -} +} \ No newline at end of file diff --git a/applications/sdp/mspi/src/hrt/hrt.h b/applications/sdp/mspi/src/hrt/hrt.h index 94b88a515796..e3156c80d4ef 100644 --- a/applications/sdp/mspi/src/hrt/hrt.h +++ b/applications/sdp/mspi/src/hrt/hrt.h @@ -10,67 +10,83 @@ #include #include #include +#include -/* Max word size. */ -#define MAX_WORD_SIZE NRF_VPR_CSR_VIO_SHIFT_CNT_OUT_BUFFERED_MAX +#define BIT_SET_VALUE(var, pos, value) ((var & (~(1 << pos))) | (value << pos)) -/* 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) +#define VPRCSR_NORDIC_OUT_HIGH 1 +#define VPRCSR_NORDIC_OUT_LOW 0 -/* Macro for getting output mask for specified pin. */ -#define PIN_DIR_OUT_MASK(PIN_NUM) PIN_DIR_MASK(PIN_NUM, OUTPUT) +#define VPRCSR_NORDIC_DIR_OUTPUT 1 +#define VPRCSR_NORDIC_DIR_INPUT 0 -/* Macro for getting input mask for specified pin. */ -#define PIN_DIR_IN_MASK(PIN_NUM) PIN_DIR_MASK(PIN_NUM, INPUT) +#define BITS_IN_WORD 32 +#define BITS_IN_BYTE 8 -/* 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) +enum hrt_bit_order { + HRT_BO_NORMAL, + HRT_BO_REVERSED_BYTE, + HRT_BO_REVERSED_WORD +}; /** @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)). + + /** @brief Timer initial value, + * time which passes beetwen chip enable and first data clock + */ + uint16_t counter_initial_value; + + /** @brief Buffer for RX/TX data */ + uint8_t *data; + + /** @brief CEIL(buffer_length_bits/32) + */ + uint32_t words; + + /** @brief Amount of clock pulses for last word. + * Due to hardware limitation, in case when last word clock pulse count is 1, + * the penultimate word has to share its bits with last word, + * for example: + * buffer length = 36bits, + * io_mode = QUAD, + * last_word_clocks would be:(buffer_length%32)/QUAD = 1 + * so: + * penultimate_word_clocks = 32-BITS_IN_BYTE + * last_word_clocks = (buffer_length%32)/QUAD + BITS_IN_BYTE + * last_word = penultimate_word>>24 | last_word<<8 */ - volatile uint8_t counter_top; + uint8_t last_word_clocks; - /** @brief Word size of passed data, bits. */ - volatile uint8_t word_size; + /** @brief Amount of clock pulses for penultimate word. + * For more info see last_word_clocks. + */ + uint8_t penultimate_word_clocks; + + /** @brief Value of last word. + * For more info see last_word_clocks. + */ + uint32_t last_word; - /** @brief Data to send, under each index there is data of length word_size. */ - volatile uint32_t *data_to_send; + /** @brief Bit transfer order. */ + enum hrt_bit_order bit_order; - /** @brief Data length. */ - volatile uint8_t data_len; + /** @brief Number of CE VIO pin */ + uint8_t ce_vio; /** @brief If true chip enable pin will be left active after transfer */ - volatile uint8_t ce_hold; + uint8_t ce_hold; /** @brief Chip enable pin polarity in enabled state. */ - volatile bool ce_enable_state; + enum mspi_ce_polarity ce_polarity; }; -/** @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. +/** @brief Write. * - * Function to be used to write data on quad data line (SPI). + * Function to be used to write data on SPI. * * @param[in] xfer_ll_params Low level transfer parameters. */ -void write_quad_by_word(volatile struct hrt_ll_xfer xfer_ll_params); +void hrt_write(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 index 5e9923fce21c..0682c7b3b234 100644 --- a/applications/sdp/mspi/src/hrt/hrt.s +++ b/applications/sdp/mspi/src/hrt/hrt.s @@ -4,85 +4,35 @@ .attribute unaligned_access, 0 .attribute stack_align, 4 .text - .section .text.write_single_by_word,"ax",@progbits + .section .text.hrt_write,"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 + .globl hrt_write + .type hrt_write, @function +hrt_write: + #APP + csrr a3, 3008 + #NO_APP + lbu a5,23(a0) + bne a5,zero,.L2 + lbu a5,21(a0) + lbu a4,21(a0) + li a5,1 + sll a5,a5,a4 + not a5,a5 + and a5,a5,a3 +.L22: 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 a4,0 li a5,0 -.L3: - lbu a4,8(a0) - bgtu a4,a5,.L6 + li a2,1 + li a1,2 +.L4: + lw a3,8(a0) + bgtu a3,a5,.L17 #APP csrw 3012, 0 #NO_APP @@ -91,198 +41,130 @@ write_single_by_word: csrw 3043, a5 csrw 3045, 0 #NO_APP - lbu a5,9(a0) - bne a5,zero,.L7 + lbu a5,22(a0) + bne a5,zero,.L18 #APP - csrr a5, 3008 + csrr a3, 3008 #NO_APP - lbu a4,10(a0) - andi a5,a5,-34 + lbu a5,23(a0) + bne a5,zero,.L19 + lbu a5,21(a0) + li a4,1 + lbu a2,21(a0) + sll a5,a4,a5 + not a5,a5 + and a5,a5,a3 + sll a4,a4,a2 + or a5,a5,a4 +.L26: 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: +.L18: #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 + lbu a5,21(a0) + li a4,1 + lbu a2,21(a0) + sll a5,a4,a5 + not a5,a5 + and a5,a5,a3 + sll a4,a4,a2 or a5,a5,a4 + j .L22 +.L17: + lw a3,8(a0) + sub a3,a3,a5 + beq a3,a2,.L5 + beq a3,a1,.L6 +.L7: + lbu t1,20(a0) + andi a3,t1,0xff + beq t1,a2,.L12 + beq a3,a1,.L13 + bne a3,zero,.L11 + lw a3,4(a0) + add a3,a3,a4 + lw a3,0(a3) + j .L23 +.L5: + lbu a3,12(a0) + addi a3,a3,-1 + andi a3,a3,0xff #APP - csrw 3008, a5 + csrw 3023, a3 #NO_APP - lbu a5,0(a0) - li a4,3 - mul a5,a5,a4 + lbu t1,20(a0) + andi a3,t1,0xff + beq t1,a2,.L8 + beq a3,a1,.L9 + bne a3,zero,.L11 + lw a3,16(a0) +.L23: #APP - csrw 2005, a5 + csrw 3012, a3 #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 + lhu a3,0(a0) #APP - csrr a5, 3008 + csrw 2005, a3 + csrr t1, 3022 #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 + andi t1,t1,0xff +.L16: #APP - csrw 3008, a5 + csrr a3, 3022 #NO_APP + andi a3,a3,0xff + beq t1,a3,.L16 .L15: + addi a5,a5,1 + addi a4,a4,4 + j .L4 +.L8: + lw a3,16(a0) +.L25: #APP - csrw 2000, 0 + csrw 3016, a3 #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) + j .L11 +.L9: + lw a3,16(a0) +.L24: #APP - csrw 3016, a4 + csrw 3017, a3 #NO_APP - addi a5,a5,1 - andi a5,a5,0xff j .L11 - .size write_quad_by_word, .-write_quad_by_word +.L6: + lbu a3,13(a0) + addi a3,a3,-1 + andi a3,a3,0xff + #APP + csrw 3023, a3 + #NO_APP + j .L7 +.L12: + lw a3,4(a0) + add a3,a3,a4 + lw a3,0(a3) + j .L25 +.L13: + lw a3,4(a0) + add a3,a3,a4 + lw a3,0(a3) + j .L24 +.L19: + lbu a5,21(a0) + lbu a4,21(a0) + li a5,1 + sll a5,a5,a4 + not a5,a5 + and a5,a5,a3 + j .L26 + .size hrt_write, .-hrt_write diff --git a/applications/sdp/mspi/src/main.c b/applications/sdp/mspi/src/main.c index 2aa528dae0ab..5fd282621bed 100644 --- a/applications/sdp/mspi/src/main.c +++ b/applications/sdp/mspi/src/main.c @@ -12,26 +12,31 @@ #include #include +#include #include -#include +#include -#define MAX_DATA_LEN 256 +#include -#define XFER_COMMAND_IDX (0) -#define XFER_ADDRESS_IDX (1) -#define XFER_DATA_IDX (2) +/************************************************* + * DEFINES + *************************************************/ +#define CE_PINS_MAX 9 +#define DATA_PINS_MAX 8 -#define HRT_IRQ_PRIORITY 2 -#define HRT_VEVIF_IDX_WRITE_SINGLE 17 -#define HRT_VEVIF_IDX_WRITE_QUAD 18 +#define HRT_IRQ_PRIORITY 2 +#define HRT_VEVIF_IDX_WRITE 18 -/* How many words are needed for given amount of bytes.*/ -#define WORDS_FOR_BYTES(bytes) ((bytes - 1) / 4 + 1) +#define PINCTL_PIN_NUM_MASK 0x0fU #define VEVIF_IRQN(vevif) VEVIF_IRQN_1(vevif) #define VEVIF_IRQN_1(vevif) VPRCLIC_##vevif##_IRQn +/************************************************* + * TYPEDEFS, ENUMS, STRUCTS + *************************************************/ + typedef struct __packed { uint8_t opcode; struct mspi_cfg cfg; @@ -52,208 +57,476 @@ typedef struct __packed { struct mspi_xfer_packet packet; } nrfe_mspi_xfer_packet_t; -struct mspi_config { - uint8_t *data; - uint8_t data_len; - uint8_t word_size; +enum base_io_mode { + BASE_IO_MODE_SINGLE, + BASE_IO_MODE_DUAL, + BASE_IO_MODE_QUAD, + BASE_IO_MODE_OCTAL }; -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. */ +struct xfer_io_mode_cfg { + enum base_io_mode command; + enum base_io_mode address; + enum base_io_mode data; }; -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, +/************************************************* + * LOCAL VARIABLES + *************************************************/ + +static const uint8_t pin_to_vio_map[] = { + 4, /* Physical pin 0 */ + 0, /* Physical pin 1 */ + 1, /* Physical pin 2 */ + 3, /* Physical pin 3 */ + 2, /* Physical pin 4 */ + 5, /* Physical pin 5 */ + 6, /* Physical pin 6 */ + 7, /* Physical pin 7 */ + 8, /* Physical pin 8 */ + 9, /* Physical pin 9 */ + 10, /* Physical pin 10 */ }; +static volatile uint8_t ce_vios_count; +static volatile uint8_t ce_vios[CE_PINS_MAX]; +static volatile uint8_t data_vios_count; +static volatile uint8_t data_vios[DATA_PINS_MAX]; +static volatile struct mspi_cfg nrfe_mspi_cfg; +static volatile struct mspi_dev_cfg nrfe_mspi_dev_cfg; +static volatile struct mspi_xfer nrfe_mspi_xfer; +static volatile struct mspi_xfer_packet nrfe_mspi_xfer_packet; +static volatile struct hrt_ll_xfer xfer_ll_params; + static struct ipc_ept ep; static atomic_t ipc_atomic_sem = ATOMIC_INIT(0); -static void process_packet(const void *data, size_t len, void *priv); +/************************************************* + * GLOBAL FUNCTION PROTOTYPES + *************************************************/ -static void ep_bound(void *priv) +__attribute__((interrupt)) void hrt_handler_write(void); + +int main(void); + +/************************************************* + * LOCAL FUNCTION PROTOTYPES + *************************************************/ + +static struct xfer_io_mode_cfg get_io_modes(enum mspi_io_mode mode); + +static void ep_bound(void *priv); + +static void ep_recv(const void *data, size_t len, void *priv); + +static void ll_prepare_transfer(enum base_io_mode xfer_mode, uint32_t data_length); + +static void configure_clock(enum mspi_cpp_mode cpp_mode); + +static void prepare_and_send_data(); + +static void process_packet(const void *data, size_t len); + +static int backend_init(void); + +/************************************************* + * GLOBAL FUNCTION IMPLEMENTATIONS + *************************************************/ + +__attribute__((interrupt)) void hrt_handler_write(void) { - (void)priv; + hrt_write(xfer_ll_params); +} - atomic_set_bit(&ipc_atomic_sem, NRFE_MSPI_EP_BOUNDED); +int main(void) +{ + int ret = backend_init(); + + if (ret < 0) { + return 0; + } + + IRQ_DIRECT_CONNECT(HRT_VEVIF_IDX_WRITE, HRT_IRQ_PRIORITY, hrt_handler_write, 0); + nrf_vpr_clic_int_enable_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE), true); + + nrf_vpr_csr_rtperiph_enable_set(true); + + while (true) { + k_cpu_idle(); + } + + return 0; } -static struct ipc_ept_cfg ep_cfg = { - .cb = { - .bound = ep_bound, - .received = process_packet, - }, -}; +/************************************************* + * LOCAL FUNCTION IMPLEMENTATIONS + *************************************************/ + +static struct xfer_io_mode_cfg get_io_modes(enum mspi_io_mode mode) +{ + struct xfer_io_mode_cfg xfer_mode; + + switch (nrfe_mspi_dev_cfg.io_mode) { + case MSPI_IO_MODE_SINGLE: + xfer_mode.command = BASE_IO_MODE_SINGLE; + xfer_mode.address = BASE_IO_MODE_SINGLE; + xfer_mode.data = BASE_IO_MODE_SINGLE; + break; + case MSPI_IO_MODE_DUAL: + xfer_mode.command = BASE_IO_MODE_DUAL; + xfer_mode.address = BASE_IO_MODE_DUAL; + xfer_mode.data = BASE_IO_MODE_DUAL; + break; + case MSPI_IO_MODE_DUAL_1_1_2: + xfer_mode.command = BASE_IO_MODE_SINGLE; + xfer_mode.address = BASE_IO_MODE_SINGLE; + xfer_mode.data = BASE_IO_MODE_DUAL; + break; + case MSPI_IO_MODE_DUAL_1_2_2: + xfer_mode.command = BASE_IO_MODE_SINGLE; + xfer_mode.address = BASE_IO_MODE_DUAL; + xfer_mode.data = BASE_IO_MODE_DUAL; + break; + case MSPI_IO_MODE_QUAD: + xfer_mode.command = BASE_IO_MODE_QUAD; + xfer_mode.address = BASE_IO_MODE_QUAD; + xfer_mode.data = BASE_IO_MODE_QUAD; + break; + case MSPI_IO_MODE_QUAD_1_1_4: + xfer_mode.command = BASE_IO_MODE_SINGLE; + xfer_mode.address = BASE_IO_MODE_SINGLE; + xfer_mode.data = BASE_IO_MODE_QUAD; + break; + case MSPI_IO_MODE_QUAD_1_4_4: + xfer_mode.command = BASE_IO_MODE_SINGLE; + xfer_mode.address = BASE_IO_MODE_QUAD; + xfer_mode.data = BASE_IO_MODE_QUAD; + break; + case MSPI_IO_MODE_OCTAL: + xfer_mode.command = BASE_IO_MODE_OCTAL; + xfer_mode.address = BASE_IO_MODE_OCTAL; + xfer_mode.data = BASE_IO_MODE_OCTAL; + break; + case MSPI_IO_MODE_OCTAL_1_1_8: + xfer_mode.command = BASE_IO_MODE_SINGLE; + xfer_mode.address = BASE_IO_MODE_SINGLE; + xfer_mode.data = BASE_IO_MODE_OCTAL; + break; + case MSPI_IO_MODE_OCTAL_1_8_8: + xfer_mode.command = BASE_IO_MODE_SINGLE; + xfer_mode.address = BASE_IO_MODE_OCTAL; + xfer_mode.data = BASE_IO_MODE_OCTAL; + break; + case MSPI_IO_MODE_HEX: + case MSPI_IO_MODE_HEX_8_8_16: + case MSPI_IO_MODE_HEX_8_16_16: + case MSPI_IO_MODE_MAX: + default: + /* TODO: Jira ticket: NRFX-6875 error*/ + break; + } -static void process_packet(const void *data, size_t len, void *priv) + return xfer_mode; +} + +static void ep_bound(void *priv) +{ + atomic_set_bit(&ipc_atomic_sem, NRFE_MSPI_EP_BOUNDED); +} + +static void ep_recv(const void *data, size_t len, void *priv) { (void)priv; - (void)len; - nrfe_mspi_flpr_response_t response; - uint8_t opcode = *(uint8_t *)data; - response.opcode = opcode; + process_packet(data, len); +} - switch (opcode) { - case NRFE_MSPI_CONFIG_PINS: { - /* TODO: Process pinctrl config data - * nrfe_mspi_pinctrl_soc_pin_t *pins_cfg = (nrfe_mspi_pinctrl_soc_pin_t *)data; - * response.opcode = pins_cfg->opcode; - * - * for (uint8_t i = 0; i < NRFE_MSPI_PINS_MAX; i++) { - * uint32_t psel = NRF_GET_PIN(pins_cfg->pin[i]); - * uint32_t fun = NRF_GET_FUN(pins_cfg->pin[i]); - * NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&psel); - * } - */ +static void ll_prepare_transfer(enum base_io_mode xfer_mode, uint32_t data_length) +{ + 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, + }; + + dir = nrf_vpr_csr_vio_dir_get(); + out = nrf_vpr_csr_vio_out_get(); + + switch (xfer_mode) { + case BASE_IO_MODE_SINGLE: + out_mode.frame_width = 1; break; - } - case NRFE_MSPI_CONFIG_CTRL: { - /* TODO: Process controller config data - * nrfe_mspi_cfg_t *cfg = (nrfe_mspi_cfg_t *)data; - * response.opcode = cfg->opcode; - */ + case BASE_IO_MODE_DUAL: + out_mode.frame_width = 2; break; - } - case NRFE_MSPI_CONFIG_DEV: { - /* TODO: Process device config data - * nrfe_mspi_dev_cfg_t *cfg = (nrfe_mspi_dev_cfg_t *)data; - * response.opcode = cfg->opcode; - */ + case BASE_IO_MODE_QUAD: + out_mode.frame_width = 4; break; - } - case NRFE_MSPI_CONFIG_XFER: { - /* TODO: Process xfer config data - * nrfe_mspi_xfer_t *xfer = (nrfe_mspi_xfer_t *)data; - * response.opcode = xfer->opcode; - */ + case BASE_IO_MODE_OCTAL: + out_mode.frame_width = 8; break; } - case NRFE_MSPI_TX: - case NRFE_MSPI_TXRX: { - nrfe_mspi_xfer_packet_t *packet = (nrfe_mspi_xfer_packet_t *)data; - response.opcode = packet->opcode; + NRFX_ASSERT(data_vios_count >= out_mode.frame_width); + NRFX_ASSERT(data_length % out_mode.frame_width == 0) - if (packet->packet.dir == MSPI_RX) { - /* TODO: Process received data */ - } else if (packet->packet.dir == MSPI_TX) { - /* TODO: Send data */ - } - break; + uint16_t direction = (nrfe_mspi_xfer_packet.dir == MSPI_TX) ? VPRCSR_NORDIC_DIR_OUTPUT + : VPRCSR_NORDIC_DIR_INPUT; + + for (uint8_t i = 0; i < out_mode.frame_width; i++) { + dir = BIT_SET_VALUE(dir, data_vios[i], direction); + out = BIT_SET_VALUE(out, data_vios[i], VPRCSR_NORDIC_OUT_LOW); } - default: - response.opcode = NRFE_MSPI_WRONG_OPCODE; - break; + + dir = BIT_SET_VALUE(dir, xfer_ll_params.ce_vio, VPRCSR_NORDIC_DIR_OUTPUT); + + if (nrfe_mspi_dev_cfg.ce_polarity == MSPI_CE_ACTIVE_LOW) { + out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_HIGH); + } else { + out = BIT_SET_VALUE(out, xfer_ll_params.ce_vio, VPRCSR_NORDIC_OUT_LOW); } - ipc_service_send(&ep, (const void *)&response.opcode, sizeof(response)); + nrf_vpr_csr_vio_dir_set(dir); + nrf_vpr_csr_vio_out_set(out); + + 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); + + /* Counter settings */ + nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_RELOAD); + /* TODO: Jira ticket: NRFX-6703 + * Top value of VTIM. This will determine clock frequency + * (SPI_CLOCK ~= CPU_CLOCK / (2 * TOP)). + * Calculate this value based on frequency + */ + nrf_vpr_csr_vtim_simple_counter_top_set(0, 40); + + /* 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(BITS_IN_WORD / out_mode.frame_width); + nrf_vpr_csr_vio_shift_cnt_out_buffered_set(BITS_IN_WORD / out_mode.frame_width - 1); + + uint8_t last_word_length = data_length % BITS_IN_WORD; + uint8_t penultimate_word_length = BITS_IN_WORD; + + xfer_ll_params.words = NRFX_CEIL_DIV(data_length, BITS_IN_WORD); + xfer_ll_params.last_word = ((uint32_t *)xfer_ll_params.data)[xfer_ll_params.words - 1]; + + /* Due to hardware limitations it is not possible to send only 1 clock cycle. + * Therefore when data_length%32==1 last word is sent shorter (24bits) + * and the remaining byte and 1 bit is sent together. + */ + if (last_word_length == 0) { + + last_word_length = BITS_IN_WORD; + xfer_ll_params.last_word = + ((uint32_t *)xfer_ll_params.data)[xfer_ll_params.words - 1]; + + } else if ((last_word_length / out_mode.frame_width == 1) && (xfer_ll_params.words > 1)) { + + penultimate_word_length -= BITS_IN_BYTE; + last_word_length += BITS_IN_BYTE; + xfer_ll_params.last_word = + ((uint32_t *)xfer_ll_params.data)[xfer_ll_params.words - 2] >> + (BITS_IN_WORD - BITS_IN_BYTE) | + ((uint32_t *)xfer_ll_params.data)[xfer_ll_params.words - 1] << BITS_IN_BYTE; + } + + xfer_ll_params.last_word_clocks = last_word_length / out_mode.frame_width; + xfer_ll_params.penultimate_word_clocks = penultimate_word_length / out_mode.frame_width; + + if (xfer_ll_params.words == 1) { + nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params.last_word_clocks); + } else if (xfer_ll_params.words == 2) { + nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params.penultimate_word_clocks); + } } -void configure_clock(enum mspi_cpp_mode cpp_mode) +static 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(VIO(NRFE_MSPI_SCK_PIN_NUMBER))); + uint16_t out = nrf_vpr_csr_vio_out_get(); switch (cpp_mode) { case MSPI_CPP_MODE_0: { vio_config.clk_polarity = 0; - nrf_vpr_csr_vio_out_set(PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_SCK_PIN_NUMBER))); + out = BIT_SET_VALUE(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], + VPRCSR_NORDIC_OUT_LOW); break; } case MSPI_CPP_MODE_1: { vio_config.clk_polarity = 1; - nrf_vpr_csr_vio_out_set(PIN_OUT_LOW_MASK(VIO(NRFE_MSPI_SCK_PIN_NUMBER))); + out = BIT_SET_VALUE(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], + VPRCSR_NORDIC_OUT_LOW); break; } case MSPI_CPP_MODE_2: { vio_config.clk_polarity = 1; - nrf_vpr_csr_vio_out_set(PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_SCK_PIN_NUMBER))); + out = BIT_SET_VALUE(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], + VPRCSR_NORDIC_OUT_HIGH); break; } case MSPI_CPP_MODE_3: { vio_config.clk_polarity = 0; - nrf_vpr_csr_vio_out_set(PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_SCK_PIN_NUMBER))); + out = BIT_SET_VALUE(out, pin_to_vio_map[NRFE_MSPI_SCK_PIN_NUMBER], + VPRCSR_NORDIC_OUT_HIGH); break; } } - + nrf_vpr_csr_vio_out_set(out); nrf_vpr_csr_vio_config_set(&vio_config); } -void prepare_and_send_data(uint8_t *data, uint8_t data_length) +static void prepare_and_send_data() { - memcpy(&(data_buffer[2]), data, data_length); + NRFX_ASSERT(nrfe_mspi_dev_cfg.ce_num < ce_vios_count); + + struct xfer_io_mode_cfg xfer_modes = get_io_modes(nrfe_mspi_dev_cfg.io_mode); + uint32_t data; /* 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)); - } + /* TODO: Jira ticket: NRFX-6703 + * Device waits this time after setting CE and before sending + * first bit, make this value dependent on dummy cycles. + */ + xfer_ll_params.counter_initial_value = 120; + data = nrfe_mspi_xfer_packet.cmd << (BITS_IN_WORD - nrfe_mspi_dev_cfg.cmd_length); + xfer_ll_params.data = (uint8_t *)&data; + xfer_ll_params.ce_vio = ce_vios[nrfe_mspi_dev_cfg.ce_num]; + xfer_ll_params.ce_hold = nrfe_mspi_xfer.hold_ce; + xfer_ll_params.ce_polarity = nrfe_mspi_dev_cfg.ce_polarity; + xfer_ll_params.bit_order = HRT_BO_REVERSED_WORD; + + ll_prepare_transfer(xfer_modes.command, nrfe_mspi_dev_cfg.cmd_length); + + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE)); /* Send address */ - xfer_ll_params.word_size = mspi_dev_configs.addr_length; - xfer_ll_params.data_to_send = data_buffer + XFER_ADDRESS_IDX; + data = nrfe_mspi_xfer_packet.address << (BITS_IN_WORD - nrfe_mspi_dev_cfg.addr_length); + xfer_ll_params.data = (uint8_t *)&data; - 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)); - } + ll_prepare_transfer(xfer_modes.address, nrfe_mspi_dev_cfg.addr_length); + + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE)); /* 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.bit_order = HRT_BO_REVERSED_BYTE; + /* TODO: Jira ticket: NRFX-6876 use read buffer that is appended to packet in NRFE_MSPI_TXRX, + * this is not possible now due to alignment problems */ - xfer_ll_params.data_len = WORDS_FOR_BYTES(data_length); - xfer_ll_params.data_to_send = data_buffer + XFER_DATA_IDX; + xfer_ll_params.data = nrfe_mspi_xfer_packet.data_buf; - 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)); - } + ll_prepare_transfer(xfer_modes.data, nrfe_mspi_xfer_packet.num_bytes * BITS_IN_BYTE); + + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE)); } -__attribute__((interrupt)) void hrt_handler_write_single(void) +static void process_packet(const void *data, size_t len) { - xfer_ll_params.ce_enable_state = (mspi_dev_configs.ce_polarity == MSPI_CE_ACTIVE_HIGH); + (void)len; + uint16_t dir; + uint16_t out; + nrfe_mspi_flpr_response_t response; + uint8_t opcode = *(uint8_t *)data; - write_single_by_word(xfer_ll_params); -} + switch (opcode) { + case NRFE_MSPI_CONFIG_PINS: { + nrfe_mspi_pinctrl_soc_pin_t *pins_cfg = (nrfe_mspi_pinctrl_soc_pin_t *)data; -__attribute__((interrupt)) void hrt_handler_write_quad(void) -{ - xfer_ll_params.ce_enable_state = (mspi_dev_configs.ce_polarity == MSPI_CE_ACTIVE_HIGH); + response.opcode = pins_cfg->opcode; + + ce_vios_count = 0; + data_vios_count = 0; + dir = 0; + out = 0; + + for (uint8_t i = 0; i < NRFE_MSPI_PINS_MAX; i++) { + uint32_t psel = NRF_GET_PIN(pins_cfg->pin[i]); + uint32_t fun = NRF_GET_FUN(pins_cfg->pin[i]); + + uint8_t pin_number = psel & PINCTL_PIN_NUM_MASK; + + if (pin_number >= sizeof(pin_to_vio_map)) { + /* TODO: Jira ticket: NRFX-6875 error*/ + return; + } + + dir = BIT_SET_VALUE(dir, pin_to_vio_map[pin_number], + VPRCSR_NORDIC_DIR_OUTPUT); + + if ((fun >= NRF_FUN_SDP_MSPI_CS0) && (fun <= NRF_FUN_SDP_MSPI_CS4)) { + + NRFX_ASSERT(pin_number < sizeof(pin_to_vio_map)) + ce_vios[ce_vios_count] = pin_to_vio_map[pin_number]; + ce_vios_count++; + + /* TODO: Jira ticket: NRFX-6876 Get CE disabled states and set them, + * they need to be passed from app + */ + } else if ((fun >= NRF_FUN_SDP_MSPI_DQ0) && (fun <= NRF_FUN_SDP_MSPI_DQ7)) { + + NRFX_ASSERT(pin_number < sizeof(pin_to_vio_map)) + data_vios[data_vios_count] = pin_to_vio_map[pin_number]; + data_vios_count++; + } + } + nrf_vpr_csr_vio_dir_set(dir); + nrf_vpr_csr_vio_out_set(0); + break; + } + case NRFE_MSPI_CONFIG_CTRL: { + nrfe_mspi_cfg_t *cfg = (nrfe_mspi_cfg_t *)data; + + response.opcode = cfg->opcode; + nrfe_mspi_cfg = cfg->cfg; + break; + } + case NRFE_MSPI_CONFIG_DEV: { + nrfe_mspi_dev_cfg_t *cfg = (nrfe_mspi_dev_cfg_t *)data; + response.opcode = cfg->opcode; + nrfe_mspi_dev_cfg = cfg->cfg; - write_quad_by_word(xfer_ll_params); + configure_clock(nrfe_mspi_dev_cfg.cpp); + break; + } + case NRFE_MSPI_CONFIG_XFER: { + nrfe_mspi_xfer_t *xfer = (nrfe_mspi_xfer_t *)data; + + response.opcode = xfer->opcode; + nrfe_mspi_xfer = xfer->xfer; + break; + } + case NRFE_MSPI_TX: + case NRFE_MSPI_TXRX: { + nrfe_mspi_xfer_packet_t *packet = (nrfe_mspi_xfer_packet_t *)data; + + response.opcode = packet->opcode; + nrfe_mspi_xfer_packet = packet->packet; + + if (packet->packet.dir == MSPI_RX) { + /* TODO: Jira ticket: NRFX-6877 Process received data */ + } else if (packet->packet.dir == MSPI_TX) { + prepare_and_send_data(); + } + break; + } + default: + response.opcode = NRFE_MSPI_WRONG_OPCODE; + break; + } + + ipc_service_send(&ep, (const void *)&response.opcode, sizeof(response)); } static int backend_init(void) @@ -261,6 +534,13 @@ static int backend_init(void) int ret = 0; const struct device *ipc0_instance; volatile uint32_t delay = 0; + struct ipc_ept_cfg ep_cfg = { + .cb = + { + .bound = ep_bound, + .received = ep_recv, + }, + }; #if !defined(CONFIG_SYS_CLOCK_EXISTS) /* Wait a little bit for IPC service to be ready on APP side */ @@ -287,47 +567,3 @@ static int backend_init(void) return 0; } - -int main(void) -{ - int ret = 0; - uint16_t direction; - uint16_t output; - - ret = backend_init(); - if (ret < 0) { - return 0; - } - - 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); - - configure_clock(MSPI_CPP_MODE_0); - - direction = nrf_vpr_csr_vio_dir_get(); - nrf_vpr_csr_vio_dir_set(direction | PIN_DIR_OUT_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER))); - - output = nrf_vpr_csr_vio_out_get(); - nrf_vpr_csr_vio_out_set(output | PIN_OUT_HIGH_MASK(VIO(NRFE_MSPI_CS0_PIN_NUMBER))); - - /* This initialization is temporary until code is merged with APP core part */ - 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; - - data_buffer[XFER_COMMAND_IDX] = 0xe5b326c1; - data_buffer[XFER_ADDRESS_IDX] = 0xaabbccdd; - - while (true) { - k_cpu_idle(); - } - - return 0; -} diff --git a/drivers/mspi/mspi_nrfe.c b/drivers/mspi/mspi_nrfe.c index 41477d707eea..ffffcc16b848 100644 --- a/drivers/mspi/mspi_nrfe.c +++ b/drivers/mspi/mspi_nrfe.c @@ -401,9 +401,11 @@ static int check_io_mode(enum mspi_io_mode io_mode) { switch (io_mode) { case MSPI_IO_MODE_SINGLE: + case MSPI_IO_MODE_DUAL: case MSPI_IO_MODE_QUAD: case MSPI_IO_MODE_QUAD_1_1_4: case MSPI_IO_MODE_QUAD_1_4_4: + case MSPI_IO_MODE_OCTAL: break; default: LOG_ERR("IO mode %d not supported", io_mode); @@ -733,14 +735,38 @@ static int check_pins_config(const struct pinctrl_dev_config *config, uint8_t id return -ENOTSUP; } break; - case NRF_FUN_SDP_MSPI_CS1: /* TODO: Support more CS */ - case NRF_FUN_SDP_MSPI_CS2: - case NRF_FUN_SDP_MSPI_CS3: - case NRF_FUN_SDP_MSPI_CS4: case NRF_FUN_SDP_MSPI_DQ4: /* Only single and QSPI modes are supported */ + if (psel != NRFE_MSPI_DQ4_PIN_NUMBER) { + LOG_ERR("Wrong DQ4 GPIO pin number: %d! Needs to be = %d.", psel, + NRFE_MSPI_DQ4_PIN_NUMBER); + return -ENOTSUP; + } + break; case NRF_FUN_SDP_MSPI_DQ5: + if (psel != NRFE_MSPI_DQ5_PIN_NUMBER) { + LOG_ERR("Wrong DQ5 GPIO pin number: %d! Needs to be = %d.", psel, + NRFE_MSPI_DQ5_PIN_NUMBER); + return -ENOTSUP; + } + break; case NRF_FUN_SDP_MSPI_DQ6: + if (psel != NRFE_MSPI_DQ6_PIN_NUMBER) { + LOG_ERR("Wrong DQ6 GPIO pin number: %d! Needs to be = %d.", psel, + NRFE_MSPI_DQ6_PIN_NUMBER); + return -ENOTSUP; + } + break; case NRF_FUN_SDP_MSPI_DQ7: + if (psel != NRFE_MSPI_DQ7_PIN_NUMBER) { + LOG_ERR("Wrong DQ7 GPIO pin number: %d! Needs to be = %d.", psel, + NRFE_MSPI_DQ7_PIN_NUMBER); + return -ENOTSUP; + } + break; + case NRF_FUN_SDP_MSPI_CS1: /* TODO: Support more CS */ + case NRF_FUN_SDP_MSPI_CS2: + case NRF_FUN_SDP_MSPI_CS3: + case NRF_FUN_SDP_MSPI_CS4: default: LOG_ERR("Not supported function: %d for GPIO pin number: %d!", fun, psel); return -ENOTSUP; diff --git a/include/drivers/mspi/nrfe_mspi.h b/include/drivers/mspi/nrfe_mspi.h index 467b6806739c..a2d8e6ce1635 100644 --- a/include/drivers/mspi/nrfe_mspi.h +++ b/include/drivers/mspi/nrfe_mspi.h @@ -14,28 +14,24 @@ extern "C" { #endif #ifdef CONFIG_SOC_NRF54L15 + #define NRFE_MSPI_PORT_NUMBER 2 /* Physical port number */ #define NRFE_MSPI_SCK_PIN_NUMBER 1 /* Physical pins number on port 2 */ #define NRFE_MSPI_DQ0_PIN_NUMBER 2 #define NRFE_MSPI_DQ1_PIN_NUMBER 4 #define NRFE_MSPI_DQ2_PIN_NUMBER 3 #define NRFE_MSPI_DQ3_PIN_NUMBER 0 -#define NRFE_MSPI_CS0_PIN_NUMBER 5 -#define NRFE_MSPI_PINS_MAX 6 - -#define NRFE_MSPI_SCK_PIN_NUMBER_VIO 0 /* FLPR VIO SCLK pin number */ -#define NRFE_MSPI_DQ0_PIN_NUMBER_VIO 1 -#define NRFE_MSPI_DQ1_PIN_NUMBER_VIO 2 -#define NRFE_MSPI_DQ2_PIN_NUMBER_VIO 3 -#define NRFE_MSPI_DQ3_PIN_NUMBER_VIO 4 -#define NRFE_MSPI_CS0_PIN_NUMBER_VIO 5 +#define NRFE_MSPI_DQ4_PIN_NUMBER 5 +#define NRFE_MSPI_DQ5_PIN_NUMBER 6 +#define NRFE_MSPI_DQ6_PIN_NUMBER 7 +#define NRFE_MSPI_DQ7_PIN_NUMBER 8 +#define NRFE_MSPI_CS0_PIN_NUMBER 9 +#define NRFE_MSPI_PINS_MAX 10 -#define VIO(_pin_) _pin_##_VIO #else #error "Unsupported SoC for SDP MSPI" #endif -#define NRFE_MSPI_MAX_CE_PINS_COUNT 5 /* Ex. CE0 CE1 CE2 CE3 CE4 */ /** @brief eMSPI opcodes. */ enum nrfe_mspi_opcode { diff --git a/scripts/twister/alt/zephyr/tests/drivers/mspi/api/testcase.yaml b/scripts/twister/alt/zephyr/tests/drivers/mspi/api/testcase.yaml index 8248dc26ec00..1e0db0ee313b 100644 --- a/scripts/twister/alt/zephyr/tests/drivers/mspi/api/testcase.yaml +++ b/scripts/twister/alt/zephyr/tests/drivers/mspi/api/testcase.yaml @@ -12,7 +12,8 @@ tests: - apollo3p_evb integration_platforms: - native_sim - drivers.mspi.sdp: + + drivers.mspi.api.emspi: tags: - drivers - mspi diff --git a/snippets/sdp/mspi/flpr.conf b/snippets/sdp/mspi/flpr.conf new file mode 100644 index 000000000000..5db8be05d329 --- /dev/null +++ b/snippets/sdp/mspi/flpr.conf @@ -0,0 +1,3 @@ +CONFIG_MBOX=y +CONFIG_IPC_SERVICE=y +CONFIG_IPC_SERVICE_BACKEND_ICMSG=y diff --git a/snippets/sdp/mspi/snippet.yml b/snippets/sdp/mspi/snippet.yml index 5c82c4655978..76d30ab6949c 100644 --- a/snippets/sdp/mspi/snippet.yml +++ b/snippets/sdp/mspi/snippet.yml @@ -11,6 +11,9 @@ boards: append: EXTRA_DTC_OVERLAY_FILE: sdp-mspi-app.overlay EXTRA_CONF_FILE: app.conf + /.*/cpuflpr/: + append: + EXTRA_CONF_FILE: flpr.conf /.*/nrf54l15/cpuapp/: append: EXTRA_DTC_OVERLAY_FILE: soc/nrf54l15_cpuapp.overlay diff --git a/snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay b/snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay index 07f040a1fd9a..c2630b8a2bbe 100644 --- a/snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay +++ b/snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay @@ -79,7 +79,11 @@ , , , - ; + , + , + , + , + ; nordic,drive-mode = ; }; }; @@ -90,7 +94,11 @@ , , , - ; + , + , + , + , + ; low-power-enable; }; };