blob: 0542682cb72380cc6bfd21b8051d1412da5980b1 [file]
#include "sw/device/lib/spi_display/spi_display.h"
#include "hw/ip/spi_host/data/spi_host_regs.h" // Generated.
#include "sw/device/lib/spi_display/DEV_Config.h"
#include "sw/device/lib/spi_display/LCD_Driver.h"
#include "sw/device/lib/util.h"
dif_result_t spi_display_init(spi_display_t* spi_display,
dif_spi_host_t* spi_host,
dif_tlul_mailbox_t* mailbox) {
spi_display->spi_host = spi_host;
spi_display->mailbox = mailbox;
spi_display->gpio_write_done = false;
spi_display->spi_idle_seen = false;
// Set the SPI_EVENT interrupt, and enable the idle event.
uint32_t intr_enable =
mmio_region_read32(spi_host->base_addr, SPI_HOST_INTR_ENABLE_REG_OFFSET);
intr_enable =
bitfield_bit32_write(intr_enable, SPI_HOST_INTR_ENABLE_SPI_EVENT_BIT, 1);
mmio_region_write32(spi_host->base_addr, SPI_HOST_INTR_ENABLE_REG_OFFSET,
intr_enable);
uint32_t event_enable =
mmio_region_read32(spi_host->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET);
event_enable =
bitfield_bit32_write(event_enable, SPI_HOST_EVENT_ENABLE_IDLE_BIT, 1);
mmio_region_write32(spi_host->base_addr, SPI_HOST_EVENT_ENABLE_REG_OFFSET,
event_enable);
// TODO(atv): Dependency inject our SPI functions?
LCD_Init(spi_display);
return kDifOk;
}
dif_result_t spi_display_irq_init(spi_display_t* spi_display,
const dif_rv_plic_t* plic,
dif_rv_plic_irq_id_t irq_id,
dif_rv_plic_target_t target) {
CHECK_DIF_OK(
dif_rv_plic_irq_set_enabled(plic, irq_id, target, kDifToggleEnabled));
CHECK_DIF_OK(
dif_rv_plic_irq_set_priority(plic, irq_id, kDifRvPlicMaxPriority));
return kDifOk;
}
dif_result_t spi_display_spi_irq_handler(spi_display_t* spi_display) {
mmio_region_write32(spi_display->spi_host->base_addr,
SPI_HOST_INTR_STATE_REG_OFFSET,
mmio_region_read32(spi_display->spi_host->base_addr,
SPI_HOST_INTR_STATE_REG_OFFSET));
spi_display->spi_idle_seen = true;
return kDifOk;
}
dif_result_t spi_display_smc_mailbox_irq_handler(spi_display_t* spi_display) {
uint32_t message;
CHECK_DIF_OK(dif_tlul_mailbox_irq_acknowledge(spi_display->mailbox,
kDifTlulMailboxIrqRtirq));
CHECK_DIF_OK(dif_tlul_mailbox_read_message(spi_display->mailbox, &message));
spi_display->gpio_write_done = true;
return kDifOk;
}
void spi_display_byte_write(spi_display_t* spi_display, uint8_t value) {
dif_spi_host_segment_t transaction[] = {
{
.type = kDifSpiHostSegmentTypeTx,
.tx =
{
.width = kDifSpiHostWidthStandard,
.buf = &value,
.length = sizeof(value),
},
},
};
CHECK_DIF_OK(dif_spi_host_transaction(spi_display->spi_host, /*csid=*/0,
transaction, ARRAYSIZE(transaction)));
}
void spi_display_block_write(spi_display_t* spi_display, const uint8_t* buffer,
size_t bytes) {
dif_spi_host_segment_t transaction[] = {
{
.type = kDifSpiHostSegmentTypeTx,
.tx =
{
.width = kDifSpiHostWidthStandard,
.buf = 0,
.length = 0,
},
},
};
size_t remaining = bytes;
size_t offset = 0;
while (remaining) {
size_t tx_len = MIN(256, remaining);
transaction[0].tx.length = tx_len;
transaction[0].tx.buf = buffer + offset;
spi_display->spi_idle_seen = false;
CHECK_DIF_OK(dif_spi_host_transaction(spi_display->spi_host, 0, transaction,
ARRAYSIZE(transaction)));
while (!spi_display->spi_idle_seen) {
asm volatile("wfi");
}
spi_display->spi_idle_seen = false;
offset += tx_len;
remaining -= tx_len;
}
}
void spi_display_gpio_write(spi_display_t* spi_display, UWORD pin,
UBYTE value) {
// Don't worry about it since the hardware controls it.
if (pin == DEV_CS_PIN) {
return;
}
uint32_t msg = ((pin & 0xFFFF) << 16) | (value & 0xFFFF);
spi_display->gpio_write_done = false;
CHECK_DIF_OK(dif_tlul_mailbox_send_message(spi_display->mailbox, &msg));
while (!spi_display->gpio_write_done) {
asm volatile("wfi");
}
spi_display->gpio_write_done = false;
}
// Implementations needed for LCD_Driver.cpp
void DEV_Delay_ms(void* ctx, UWORD value) {
spi_display_t* spi_display = (spi_display_t*)ctx;
busy_spin_micros(value * 1000);
}
void DEV_SPI_BLOCK_WRITE(void* ctx, const uint8_t* buffer, size_t bytes) {
spi_display_t* spi_display = (spi_display_t*)ctx;
spi_display_block_write(ctx, buffer, bytes);
}
void DEV_SPI_WRITE(void* ctx, UBYTE value) {
spi_display_t* spi_display = (spi_display_t*)ctx;
spi_display_byte_write(ctx, value);
}
void DEV_Digital_Write(void* ctx, UWORD pin, UBYTE value) {
spi_display_t* spi_display = (spi_display_t*)ctx;
spi_display_gpio_write(ctx, pin, value);
}