Skip to content

Commit

Permalink
applications: sdp: mspi: Ipc Hrt Connection
Browse files Browse the repository at this point in the history
  • Loading branch information
jaz1-nordic authored and mif1-nordic committed Jan 7, 2025
1 parent fd6a31a commit a5d9c59
Show file tree
Hide file tree
Showing 7 changed files with 724 additions and 628 deletions.
2 changes: 2 additions & 0 deletions applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ CONFIG_SYS_CLOCK_EXISTS=n

CONFIG_OUTPUT_DISASSEMBLY=y
CONFIG_COMMON_LIBC_MALLOC=n

CONFIG_COMPILER_OPT="-fshort-enums"
271 changes: 132 additions & 139 deletions applications/sdp/mspi/src/hrt/hrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,183 +6,176 @@
#include "hrt.h"
#include <hal/nrf_vpr_csr_vio.h>
#include <hal/nrf_vpr_csr_vtim.h>
#include <drivers/mspi/nrfe_mspi.h>
#include <zephyr/drivers/mspi.h>

#define CLK_FIRST_CYCLE_MULTIPLICATOR (3)
/*TODO: Jira ticket NRFX-6910 move this to nrf_vpr_csr_vio.h */

void write_single_by_word(volatile struct hrt_ll_xfer xfer_ll_params)
/** @brief Shift control configuration. */
typedef struct __packed
{
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(VIO(NRFE_MSPI_DQ0_PIN_NUMBER)));
uint8_t shift_count : 6;
uint8_t reserved_1 : 2;
nrf_vpr_csr_vio_shift_t out_mode : 3;
uint8_t reserved_2 : 1;
uint8_t frame_width : 5;
uint8_t reserved_3 : 3;
nrf_vpr_csr_vio_mode_in_t in_mode : 2;
uint16_t reserved_4 : 10;
} nrf_vpr_csr_vio_shift_ctrl_t;

/*TODO: Jira ticket NRFX-6910 move this to nrf_vpr_csr_vio.h */
NRF_STATIC_INLINE void nrf_vpr_csr_vio_shift_ctrl_buffered_set(nrf_vpr_csr_vio_shift_ctrl_t const * p_shift_ctrl)
{
nrf_csr_write(VPRCSR_NORDIC_SHIFTCTRLB, *(uint32_t*)p_shift_ctrl);
}

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);
}
static void hrt_tx(struct hrt_xfer_data *xfer_data, uint8_t frame_width, bool *counter_running, uint16_t counter_value)
{
if(xfer_data->words == 0)
{
return;
}

/* 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);
nrf_vpr_csr_vio_shift_ctrl_t shift_ctrl = {
.shift_count = BITS_IN_WORD / frame_width - 1,
.out_mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE,
.frame_width = frame_width,
.in_mode = NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS,
};

/* 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);
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl);

/* 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_data->words; i++) {

/* 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);
switch (xfer_data->words - i) {
case 1: /* Last transfer */
shift_ctrl.shift_count = xfer_data->last_word_clocks - 1;
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl);

/* 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);
xfer_data->vio_out_set(xfer_data->last_word);
break;
case 2: /* Last but one transfer.*/
shift_ctrl.shift_count = xfer_data->penultimate_word_clocks - 1;
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl);
default: /* Intentional fallthrough */
xfer_data->vio_out_set(((uint32_t *)xfer_data->data)[i]);
}

/* 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);
if ((i == 0) && (!*counter_running)) {
/* Start counter */
nrf_vpr_csr_vtim_simple_counter_set(0, counter_value);
*counter_running = true;
}
}

/* 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)
void hrt_write(struct hrt_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,
bool counter_running = false;
nrf_vpr_csr_vio_shift_ctrl_t shift_ctrl = {
.shift_count = 1,
.out_mode = NRF_VPR_CSR_VIO_SHIFT_NONE,
.frame_width = 4,
.in_mode = NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS,
};

nrf_vpr_csr_vio_mode_out_t out_mode = {
.mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE
};

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();
NRFX_ASSERT((xfer_ll_data.last_word_clocks != 1) || (xfer_ll_data.words == 1))

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)));
/* Configure clock and pins */
nrf_vpr_csr_vio_dir_set(xfer_ll_params->tx_direction_mask);

out = nrf_vpr_csr_vio_out_get();
for(uint8_t i=0; i<HRT_FE_MAX; i++) {

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);

/* 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->xfer_data[i].words == 0)
{
break;
}

switch(i) {
case HRT_FE_COMMAND:
out_mode.frame_width = xfer_ll_params->io_mode.command;
break;
case HRT_FE_ADDRESS:
out_mode.frame_width = xfer_ll_params->io_mode.address;
break;
case HRT_FE_DATA:
out_mode.frame_width = xfer_ll_params->io_mode.data;
break;
}
}

/* 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);
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_value);
nrf_vpr_csr_vio_mode_in_set(NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS);

nrf_vpr_csr_vio_mode_out_set(&out_mode);

switch(xfer_ll_params->xfer_data[i].words) {
case 1:
nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params->xfer_data[i].last_word_clocks);
break;
case 2:
nrf_vpr_csr_vio_shift_cnt_out_set(xfer_ll_params->xfer_data[i].penultimate_word_clocks);
break;
default:
nrf_vpr_csr_vio_shift_cnt_out_set(BITS_IN_WORD / out_mode.frame_width);
}

/* 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);
break;
}

/* 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));

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);
}
nrf_vpr_csr_vio_out_set(out);

/* Start counter */
nrf_vpr_csr_vtim_simple_counter_set(0, 3 * xfer_ll_params.counter_top);
/* Transfer command */
hrt_tx(&xfer_ll_params->xfer_data[HRT_FE_COMMAND], xfer_ll_params->io_mode.command, &counter_running, xfer_ll_params->counter_value);
/* Transfer address */
hrt_tx(&xfer_ll_params->xfer_data[HRT_FE_ADDRESS], xfer_ll_params->io_mode.address, &counter_running, xfer_ll_params->counter_value);
/* Transfer data */
hrt_tx(&xfer_ll_params->xfer_data[HRT_FE_DATA], xfer_ll_params->io_mode.data, &counter_running, xfer_ll_params->counter_value);

/* 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 (xfer_ll_params->eliminate_last_pulse) {

/* Clear all bits, wait until the last word is sent */
nrf_vpr_csr_vio_out_buffered_set(0);
/* Wait until the last word is sent */
while(nrf_vpr_csr_vio_shift_cnt_out_get() != 0){}

/* TODO: Jira ticket NRFX-6798 fix surplus edge problem for higher frequencies.
* This is a partial solution to surplus clock edge problem in modes 1 and 3.
* This solution works only for counter values above 20.
*/
nrf_vpr_csr_vtim_simple_wait_set(0, false, 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);
nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl);
nrf_vpr_csr_vio_out_buffered_reversed_word_set(0x00);

/* Stop counter */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP);

/* Disable CS */
if (!xfer_ll_params.ce_hold) {
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));

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);
}
nrf_vpr_csr_vio_out_set(out);
}

/* Stop counter */
nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP);
}
Loading

0 comments on commit a5d9c59

Please sign in to comment.