15 #include "spi_host_regs.h"
22 dif_result_t spi_host_fifo_write_alias(const dif_spi_host_t *spi_host,
23 const
void *src, uint16_t len);
27 dif_result_t spi_host_fifo_read_alias(const dif_spi_host_t *spi_host,
void *dst,
30 static
void spi_host_reset(const dif_spi_host_t *spi_host) {
33 mmio_region_read32(spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET);
35 spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET,
42 mmio_region_read32(spi_host->base_addr, SPI_HOST_STATUS_REG_OFFSET);
50 mmio_region_read32(spi_host->base_addr, SPI_HOST_STATUS_REG_OFFSET);
53 }
while (txqd != 0 || rxqd != 0);
57 spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET,
61 static void spi_host_enable(
const dif_spi_host_t *spi_host,
bool enable) {
63 mmio_region_read32(spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET);
65 spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET,
71 if (spi_host == NULL) {
80 if (divider & ~(uint32_t)SPI_HOST_CONFIGOPTS_CLKDIV_MASK) {
84 spi_host_reset(spi_host);
88 config.chip_select.idle);
90 config.chip_select.trail);
92 config.chip_select.lead);
97 mmio_region_write32(spi_host->base_addr, SPI_HOST_CONFIGOPTS_REG_OFFSET, reg);
99 reg = mmio_region_read32(spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET);
104 mmio_region_write32(spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET, reg);
106 spi_host_enable(spi_host,
true);
112 if (spi_host == NULL) {
117 mmio_region_read32(spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET);
119 spi_host->base_addr, SPI_HOST_CONTROL_REG_OFFSET,
125 static void wait_ready(
const dif_spi_host_t *spi_host) {
129 mmio_region_read32(spi_host->base_addr, SPI_HOST_STATUS_REG_OFFSET);
134 static void wait_tx_fifo(
const dif_spi_host_t *spi_host) {
138 mmio_region_read32(spi_host->base_addr, SPI_HOST_STATUS_REG_OFFSET);
140 }
while (txqd == SPI_HOST_PARAM_TX_DEPTH);
143 static void wait_rx_fifo(
const dif_spi_host_t *spi_host) {
147 mmio_region_read32(spi_host->base_addr, SPI_HOST_STATUS_REG_OFFSET);
152 static inline void tx_fifo_write8(
const dif_spi_host_t *spi_host,
154 uint8_t *src = (uint8_t *)srcaddr;
155 wait_tx_fifo(spi_host);
156 mmio_region_write8(spi_host->base_addr, SPI_HOST_TXDATA_REG_OFFSET, *src);
159 static inline void tx_fifo_write32(
const dif_spi_host_t *spi_host,
161 wait_tx_fifo(spi_host);
162 uint32_t val =
read_32((
const void *)srcaddr);
163 mmio_region_write32(spi_host->base_addr, SPI_HOST_TXDATA_REG_OFFSET, val);
167 const void *src, uint16_t len) {
168 uintptr_t ptr = (uintptr_t)src;
169 if (spi_host == NULL || (src == NULL && len > 0)) {
175 tx_fifo_write8(spi_host, ptr);
182 tx_fifo_write32(spi_host, ptr);
189 tx_fifo_write8(spi_host, ptr);
199 uint8_t
alignas(uint64_t) data[8];
202 static void enqueue_byte(
queue_t *
queue, uint8_t data) {
206 static void enqueue_word(
queue_t *
queue, uint32_t data) {
207 if (
queue->length % (int32_t)
sizeof(uint32_t) == 0) {
211 for (
size_t i = 0; i <
sizeof(uint32_t); ++i) {
212 enqueue_byte(
queue, (uint8_t)data);
219 uint8_t val =
queue->data[0];
235 if (spi_host == NULL || (dst == NULL && len > 0)) {
239 uintptr_t ptr = (uintptr_t)dst;
247 if (
queue.length < 1) {
248 wait_rx_fifo(spi_host);
249 enqueue_word(&
queue, mmio_region_read32(spi_host->base_addr,
250 SPI_HOST_RXDATA_REG_OFFSET));
252 uint8_t *p = (uint8_t *)ptr;
253 *p = dequeue_byte(&
queue);
260 if (
queue.length < 4) {
261 wait_rx_fifo(spi_host);
262 enqueue_word(&
queue, mmio_region_read32(spi_host->base_addr,
263 SPI_HOST_RXDATA_REG_OFFSET));
272 if (
queue.length < 1) {
273 wait_rx_fifo(spi_host);
274 enqueue_word(&
queue, mmio_region_read32(spi_host->base_addr,
275 SPI_HOST_RXDATA_REG_OFFSET));
277 uint8_t *p = (uint8_t *)ptr;
278 *p = dequeue_byte(&
queue);
286 static void write_command_reg(
const dif_spi_host_t *spi_host, uint16_t length,
296 mmio_region_write32(spi_host->base_addr, SPI_HOST_COMMAND_REG_OFFSET, reg);
299 static void issue_opcode(
const dif_spi_host_t *spi_host,
301 wait_tx_fifo(spi_host);
302 mmio_region_write8(spi_host->base_addr, SPI_HOST_TXDATA_REG_OFFSET,
303 segment->opcode.opcode);
308 static void issue_address(
const dif_spi_host_t *spi_host,
310 wait_tx_fifo(spi_host);
316 mmio_region_write32(spi_host->base_addr, SPI_HOST_TXDATA_REG_OFFSET,
321 mmio_region_write32(spi_host->base_addr, SPI_HOST_TXDATA_REG_OFFSET,
324 write_command_reg(spi_host, length, segment->address.width,
328 static void issue_dummy(
const dif_spi_host_t *spi_host,
330 if (segment->dummy.length > 0) {
334 write_command_reg(spi_host, (uint16_t)segment->dummy.length,
340 static dif_result_t issue_data_phase(
const dif_spi_host_t *spi_host,
343 switch (segment->
type) {
345 write_command_reg(spi_host, (uint16_t)segment->tx.length,
348 spi_host_fifo_write_alias(spi_host, segment->tx.buf,
349 (uint16_t)segment->tx.length);
352 write_command_reg(spi_host, (uint16_t)segment->bidir.length,
355 spi_host_fifo_write_alias(spi_host, segment->bidir.txbuf,
356 (uint16_t)segment->bidir.length);
359 write_command_reg(spi_host, (uint16_t)segment->rx.length,
377 mmio_region_write32(spi_host->base_addr, SPI_HOST_CSID_REG_OFFSET, csid);
381 for (
size_t i = 0; i < length; ++i) {
382 bool last_segment = i == length - 1;
383 wait_ready(spi_host);
385 switch (segment->
type) {
387 issue_opcode(spi_host, segment, last_segment);
390 issue_address(spi_host, segment, last_segment);
393 issue_dummy(spi_host, segment, last_segment);
398 dif_result_t error = issue_data_phase(spi_host, segment, last_segment);
410 for (
size_t i = 0; i < length; ++i) {
412 switch (segment->
type) {
414 spi_host_fifo_read_alias(spi_host, segment->rx.buf,
415 (uint16_t)segment->rx.length);
418 spi_host_fifo_read_alias(spi_host, segment->bidir.rxbuf,
419 (uint16_t)segment->bidir.length);
436 mmio_region_read32(spi_host->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET);
442 mmio_region_write32(spi_host->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET,
449 if (spi_host == NULL || events == NULL) {
454 mmio_region_read32(spi_host->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET);
460 if (spi_host == NULL ||
status == NULL) {
465 mmio_region_read32(spi_host->base_addr, SPI_HOST_STATUS_REG_OFFSET);
477 status->least_significant_first =
494 if (spi_host == NULL) {
497 write_command_reg(spi_host, length, speed, direction, last_segment);
509 mmio_region_read32(spi_host->base_addr, SPI_HOST_ERROR_ENABLE_REG_OFFSET);
515 mmio_region_write32(spi_host->base_addr, SPI_HOST_ERROR_ENABLE_REG_OFFSET,
522 if (spi_host == NULL || errors == NULL) {
527 mmio_region_read32(spi_host->base_addr, SPI_HOST_ERROR_ENABLE_REG_OFFSET);
533 if (spi_host == NULL || error == NULL) {
538 mmio_region_read32(spi_host->base_addr, SPI_HOST_ERROR_STATUS_REG_OFFSET);
544 if (spi_host == NULL) {
551 mmio_region_read32(spi_host->base_addr, SPI_HOST_STATUS_REG_OFFSET);