5 #include "sw/device/lib/testing/test_framework/ottf_console.h"
11 #include "sw/device/lib/base/status.h"
16 #include "sw/device/lib/runtime/irq.h"
18 #include "sw/device/lib/testing/spi_device_testutils.h"
19 #include "sw/device/lib/testing/test_framework/check.h"
20 #include "sw/device/lib/testing/test_framework/ottf_isrs.h"
21 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
24 #include "dt/dt_rv_plic.h"
25 #include "dt/dt_uart.h"
27 #include "spi_device_regs.h"
29 #define MODULE_ID MAKE_MODULE_ID('o', 't', 'c')
38 kSpiDeviceRxCommitWait = 63,
42 kFlowControlLowWatermark = 4,
43 kFlowControlHighWatermark = 8,
53 static dif_uart_t ottf_console_uart;
62 static volatile ottf_console_flow_control_t flow_control_state;
63 static volatile uint32_t flow_control_irqs;
65 void *ottf_console_get(
void) {
67 case kOttfConsoleSpiDevice:
68 return &ottf_console_spi_device;
70 return &ottf_console_uart;
74 static status_t uart_getc(
void *io) {
75 const dif_uart_t *uart = (
const dif_uart_t *)io;
78 TRY(ottf_console_flow_control(uart, kOttfConsoleFlowControlAuto));
79 return OK_STATUS(
byte);
89 static status_t spi_device_getc(
void *io) {
90 static size_t index = 0;
91 static upload_info_t info = {0};
93 if (index == info.data_len) {
94 memset(&info, 0,
sizeof(upload_info_t));
95 CHECK_STATUS_OK(spi_device_testutils_wait_for_upload(spi_device, &info));
100 return OK_STATUS(info.data[index++]);
104 const uint8_t kBootMagicPattern[4] = {0x02, 0xb0, 0xfe, 0xca};
105 const uint8_t kEmptyPattern[4] = {0};
107 for (
size_t i = 0; i < SPI_DEVICE_PARAM_SRAM_READ_BUFFER_DEPTH; i++) {
114 upload_info_t info = {0};
115 CHECK_STATUS_OK(spi_device_testutils_wait_for_upload(spi_device, &info));
117 for (
size_t i = 0; i < SPI_DEVICE_PARAM_SRAM_READ_BUFFER_DEPTH; i++) {
125 void ottf_console_init(
void) {
129 case kOttfConsoleUart:
132 if (base_addr == 0) {
133 CHECK(kOttfTestConfig.
console.
type == kOttfConsoleUart);
134 base_addr = dt_uart_primary_reg_block(kDtUart0);
137 ottf_console_configure_uart(base_addr);
141 case (kOttfConsoleSpiDevice):
142 ottf_console_configure_spi_device(base_addr);
144 getc = spi_device_getc;
147 CHECK(
false,
"unsupported OTTF console interface.");
152 void ottf_console_configure_uart(uintptr_t base_addr) {
155 CHECK(
kUartBaudrate <= UINT32_MAX,
"kUartBaudrate must fit in uint32_t");
157 "kClockFreqPeripheralHz must fit in uint32_t");
171 ottf_console_flow_control_enable();
175 void ottf_console_configure_spi_device(uintptr_t base_addr) {
177 &ottf_console_spi_device));
179 &ottf_console_spi_device,
188 .
opcode = kSpiDeviceFlashOpReadStatus1,
192 .payload_dir_to_host =
true,
196 .opcode = kSpiDeviceFlashOpReadStatus2,
200 .payload_dir_to_host =
true,
204 .opcode = kSpiDeviceFlashOpReadStatus3,
208 .payload_dir_to_host =
true,
212 .opcode = kSpiDeviceFlashOpReadJedec,
216 .payload_dir_to_host =
true,
220 .opcode = kSpiDeviceFlashOpReadSfdp,
224 .payload_dir_to_host =
true,
228 .opcode = kSpiDeviceFlashOpReadNormal,
232 .payload_dir_to_host =
true,
235 for (
size_t i = 0; i <
ARRAYSIZE(read_commands); ++i) {
236 uint8_t slot = (uint8_t)i + kSpiDeviceReadCommandSlotBase;
243 .
opcode = kSpiDeviceFlashOpPageProgram,
246 .payload_dir_to_host =
false,
248 .set_busy_status =
true,
251 for (
size_t i = 0; i <
ARRAYSIZE(write_commands); ++i) {
252 uint8_t slot = (uint8_t)i + kSpiDeviceWriteCommandSlotBase;
256 spi_device_wait_for_sync(&ottf_console_spi_device);
260 static uint32_t get_flow_control_watermark_plic_id(
void) {
261 for (
size_t i = 0; i < kDtUartCount; i++) {
262 dt_uart_t uart = (dt_uart_t)i;
264 return dt_uart_irq_to_plic_id(uart, kDtUartIrqRxWatermark);
267 return dt_uart_irq_to_plic_id(kDtUart0, kDtUartIrqRxWatermark);
270 void ottf_console_flow_control_enable(
void) {
271 dif_uart_t *uart = (dif_uart_t *)ottf_console_get();
273 CHECK_DIF_OK(dif_uart_irq_set_enabled(uart, kDifUartIrqRxWatermark,
284 get_flow_control_watermark_plic_id(),
287 flow_control_state = kOttfConsoleFlowControlAuto;
288 irq_global_ctrl(
true);
289 irq_external_ctrl(
true);
291 ottf_console_flow_control((dif_uart_t *)ottf_console_get(),
292 kOttfConsoleFlowControlResume);
296 static status_t manage_flow_control(
const dif_uart_t *uart,
297 ottf_console_flow_control_t ctrl) {
298 if (flow_control_state == kOttfConsoleFlowControlNone) {
299 return OK_STATUS((int32_t)flow_control_state);
301 if (ctrl == kOttfConsoleFlowControlAuto) {
304 if (avail < kFlowControlLowWatermark &&
305 flow_control_state != kOttfConsoleFlowControlResume) {
308 CHECK_DIF_OK(dif_uart_irq_set_enabled(uart, kDifUartIrqRxWatermark,
310 ctrl = kOttfConsoleFlowControlResume;
311 }
else if (avail >= kFlowControlHighWatermark &&
312 flow_control_state != kOttfConsoleFlowControlPause) {
313 ctrl = kOttfConsoleFlowControlPause;
316 CHECK_DIF_OK(dif_uart_irq_set_enabled(uart, kDifUartIrqRxWatermark,
319 return OK_STATUS((int32_t)flow_control_state);
322 uint8_t
byte = (uint8_t)ctrl;
324 flow_control_state = ctrl;
325 return OK_STATUS((int32_t)flow_control_state);
328 bool ottf_console_flow_control_isr(uint32_t *exc_info) {
329 dif_uart_t *uart = (dif_uart_t *)ottf_console_get();
330 flow_control_irqs += 1;
332 CHECK_DIF_OK(dif_uart_irq_is_pending(uart, kDifUartIrqRxWatermark, &rx));
334 manage_flow_control(uart, kOttfConsoleFlowControlAuto);
335 CHECK_DIF_OK(dif_uart_irq_acknowledge(uart, kDifUartIrqRxWatermark));
343 status_t ottf_console_flow_control(
const dif_uart_t *uart,
344 ottf_console_flow_control_t ctrl) {
345 dif_uart_irq_enable_snapshot_t snapshot;
346 CHECK_DIF_OK(dif_uart_irq_disable_all(uart, &snapshot));
347 status_t s = manage_flow_control(uart, ctrl);
348 CHECK_DIF_OK(dif_uart_irq_restore_all(uart, &snapshot));
352 uint32_t ottf_console_get_flow_control_irqs(
void) {
return flow_control_irqs; }
354 static bool spi_tx_last_data_chunk(upload_info_t *info) {
355 const static size_t kSpiTxTerminateMagicAddress = 0x100;
356 return info->address == kSpiTxTerminateMagicAddress;
359 size_t ottf_console_spi_device_read(
size_t buf_size, uint8_t *
const buf) {
360 size_t received_data_len = 0;
362 memset(&info, 0,
sizeof(upload_info_t));
363 while (!spi_tx_last_data_chunk(&info)) {
365 spi_device_testutils_wait_for_upload(&ottf_console_spi_device, &info));
366 if (received_data_len < buf_size) {
367 size_t remaining_buf_size = buf_size - received_data_len;
368 size_t bytes_to_copy = remaining_buf_size < info.data_len
371 memcpy(buf + received_data_len, info.data, bytes_to_copy);
374 received_data_len += info.data_len;
376 &ottf_console_spi_device, 0x00));
379 return received_data_len;
382 status_t ottf_console_putbuf(
void *io,
const char *buf,
size_t len) {
383 size_t written_len = sink(io, buf, len);
384 if (len != written_len) {
385 return DATA_LOSS((int32_t)(len - written_len));
387 return OK_STATUS((int32_t)len);
390 status_t ottf_console_getc(
void *io) {
return getc(io); }