Files
qemu-xteink/hw/ssi/esp32c3_spi2.c
T

102 lines
2.6 KiB
C

/*
* ESP32-C3 general-purpose SPI2 controller
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "hw/ssi/esp32c3_spi2.h"
#define SPI2_CMD 0x000
#define SPI2_MS_DLEN 0x01c
#define SPI2_W0 0x098
#define SPI2_CMD_USR BIT(24)
#define SPI2_DLEN_MASK 0x3ffff
#define SPI2_BUFFER_SIZE 64
static void esp32c3_spi2_transfer(ESP32C3Spi2State *s)
{
size_t bytes = (s->regs[SPI2_MS_DLEN / 4] & SPI2_DLEN_MASK) / 8 + 1;
bytes = MIN(bytes, SPI2_BUFFER_SIZE);
for (size_t i = 0; i < bytes; i++) {
uint32_t *word = &s->regs[SPI2_W0 / 4 + i / 4];
unsigned shift = (i % 4) * 8;
uint8_t tx = *word >> shift;
uint8_t rx = ssi_transfer(s->bus, tx);
*word = (*word & ~(0xffu << shift)) | ((uint32_t)rx << shift);
}
}
static uint64_t esp32c3_spi2_read(void *opaque, hwaddr addr, unsigned size)
{
ESP32C3Spi2State *s = ESP32C3_SPI2(opaque);
return s->regs[addr / 4];
}
static void esp32c3_spi2_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
ESP32C3Spi2State *s = ESP32C3_SPI2(opaque);
if (addr == SPI2_CMD) {
if (value & SPI2_CMD_USR) {
esp32c3_spi2_transfer(s);
}
s->regs[SPI2_CMD / 4] = 0;
return;
}
s->regs[addr / 4] = value;
}
static const MemoryRegionOps esp32c3_spi2_ops = {
.read = esp32c3_spi2_read,
.write = esp32c3_spi2_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void esp32c3_spi2_reset_hold(Object *obj, ResetType type)
{
ESP32C3Spi2State *s = ESP32C3_SPI2(obj);
memset(s->regs, 0, sizeof(s->regs));
}
static void esp32c3_spi2_init(Object *obj)
{
ESP32C3Spi2State *s = ESP32C3_SPI2(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &esp32c3_spi2_ops, s,
TYPE_ESP32C3_SPI2, ESP32C3_SPI2_IO_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
s->bus = ssi_create_bus(DEVICE(s), "spi");
}
static void esp32c3_spi2_class_init(ObjectClass *klass, void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
rc->phases.hold = esp32c3_spi2_reset_hold;
}
static const TypeInfo esp32c3_spi2_info = {
.name = TYPE_ESP32C3_SPI2,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ESP32C3Spi2State),
.instance_init = esp32c3_spi2_init,
.class_init = esp32c3_spi2_class_init,
};
static void esp32c3_spi2_register_types(void)
{
type_register_static(&esp32c3_spi2_info);
}
type_init(esp32c3_spi2_register_types)