Progress on some components

This commit is contained in:
Martijn de Vos committed 2024-11-24 14:59:21 +01:00
1 parent 29e927ab33
commit 8fae8122ad
11 files changed
+626 -13

No files matched your search

+29 -1
View File
@@ -66,7 +66,7 @@ static void atv4_cpu_reset(void *opaque)
static void atv4_memory_setup(MachineState *machine, MemoryRegion *sysmem, AddressSpace *nsas)
{
// ATV4MachineState *nms = ATV4_MACHINE(machine);
allocate_ram(sysmem, "unknown1", UNKNOWN1_MEM_BASE, 0x200000);
allocate_ram(sysmem, "sram", SRAM_MEM_BASE, SRAM_LENGTH);
allocate_ram(sysmem, "unknown2", UNKNOWN2_MEM_BASE, 0x1000);
allocate_ram(sysmem, "unknown3", UNKNOWN3_MEM_BASE, 0x20);
@@ -135,6 +135,34 @@ static void atv4_machine_init(MachineState *machine)
nms->ausb_state = ausb_state;
memory_region_add_subregion(sysmem, AUSB_MEM_BASE, &ausb_state->iomem);
// init the AUSB Widget
dev = qdev_new("atv4.ausbwidget");
ATV4AUSBWidgetState *ausb_widget_state = ATV4_AUSB_WIDGET(dev);
nms->ausb_widget_state = ausb_widget_state;
memory_region_add_subregion(sysmem, AUSB_WIDGET_MEM_BASE, &ausb_widget_state->iomem);
// init the ANCs
dev = qdev_new("atv4.anc");
ATV4ANCState *anc0_state = ATV4_ANC(dev);
nms->anc0_state = anc0_state;
memory_region_add_subregion(sysmem, PPNNPL_MEM_BASE, &anc0_state->ppnnpl_iomem);
memory_region_add_subregion(sysmem, ANC0_MEM_BASE, &anc0_state->anc_iomem);
dev = qdev_new("atv4.anc");
ATV4ANCState *anc1_state = ATV4_ANC(dev);
nms->anc1_state = anc1_state;
memory_region_add_subregion(sysmem, PPNNPL_MEM_BASE, &anc1_state->ppnnpl_iomem);
memory_region_add_subregion(sysmem, ANC1_MEM_BASE, &anc1_state->anc_iomem);
// init spis
uint64_t spi_bases[] = { SPI0_MEM_BASE, SPI1_MEM_BASE, SPI2_MEM_BASE, SPI3_MEM_BASE };
for(int i = 0; i < 4; i++) {
set_spi_base(i);
dev = sysbus_create_simple("atv4.spi", spi_bases[i], 0); // TODO set the right IRQ!
ATV4SPIState *spi_state = ATV4_SPI(dev);
nms->spi_state[i] = spi_state;
}
qemu_register_reset(atv4_cpu_reset, nms);
}
+61
View File
@@ -0,0 +1,61 @@
#include "hw/arm/atv4_anc.h"
static uint64_t atv4_anc_read(void *opaque, hwaddr addr, unsigned size)
{
ATV4ANCState *s = (ATV4ANCState *) opaque;
switch(addr)
{
default:
return 0x0;
}
}
static void atv4_anc_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
ATV4ANCState *s = (ATV4ANCState *) opaque;
switch(addr)
{
default:
return;
}
}
static const MemoryRegionOps atv4_anc_ops = {
.read = atv4_anc_read,
.write = atv4_anc_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void atv4_anc_init(Object *obj)
{
ATV4ANCState *s = ATV4_ANC(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->ppnnpl_iomem, obj, &atv4_anc_ops, s, TYPE_ATV4_ANC, 0x100); // TODO hard-coded anc_ops call, should change
sysbus_init_mmio(sbd, &s->ppnnpl_iomem);
memory_region_init_io(&s->anc_iomem, obj, &atv4_anc_ops, s, TYPE_ATV4_ANC, 0x3000);
sysbus_init_mmio(sbd, &s->anc_iomem);
}
static void atv4_anc_class_init(ObjectClass *klass, void *data)
{
}
static const TypeInfo atv4_anc_type_info = {
.name = TYPE_ATV4_ANC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ATV4ANCState),
.instance_init = atv4_anc_init,
.class_init = atv4_anc_class_init,
};
static void atv4_anc_register_types(void)
{
type_register_static(&atv4_anc_type_info);
}
type_init(atv4_anc_register_types)
+58
View File
@@ -0,0 +1,58 @@
#include "hw/arm/atv4_ausb_widget.h"
static uint64_t atv4_ausb_widget_read(void *opaque, hwaddr addr, unsigned size)
{
ATV4AUSBWidgetState *s = (ATV4AUSBWidgetState *) opaque;
switch(addr)
{
default:
return 0x0;
}
}
static void atv4_ausb_widget_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
ATV4AUSBWidgetState *s = (ATV4AUSBWidgetState *) opaque;
switch(addr)
{
default:
return;
}
}
static const MemoryRegionOps atv4_ausb_widget_ops = {
.read = atv4_ausb_widget_read,
.write = atv4_ausb_widget_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void atv4_ausb_widget_init(Object *obj)
{
ATV4AUSBWidgetState *s = ATV4_AUSB_WIDGET(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &atv4_ausb_widget_ops, s, TYPE_ATV4_AUSB_WIDGET, 0x100);
sysbus_init_mmio(sbd, &s->iomem);
}
static void atv4_ausb_widget_class_init(ObjectClass *klass, void *data)
{
}
static const TypeInfo atv4_ausb_widget_type_info = {
.name = TYPE_ATV4_AUSB_WIDGET,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ATV4AUSBWidgetState),
.instance_init = atv4_ausb_widget_init,
.class_init = atv4_ausb_widget_class_init,
};
static void atv4_ausb_widget_register_types(void)
{
type_register_static(&atv4_ausb_widget_type_info);
}
type_init(atv4_ausb_widget_register_types)
+9 -9
View File
@@ -214,21 +214,21 @@ static void atv4_pmgr_soc_write(void *opaque, hwaddr addr, uint64_t value, unsig
{
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
ATV4PMGRState *s = (struct ATV4PMGRState *) opaque;
switch(addr) {
default:
break;
}
s->scratch[addr] = value;
}
static uint64_t atv4_pmgr_scratch_read(void *opaque, hwaddr addr, unsigned size)
{
//fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr);
printf("%s: offset = 0x%08x\n", __func__, addr);
ATV4PMGRState *s = (struct ATV4PMGRState *) opaque;
switch (addr) {
case 0x0 ... 0x60:
// TODO return the right scratch configuration
case 0x0:
return s->scratch[0] | (BOOT_DEVICE_NAND << 8);
break;
case 0x4 ... 0xC:
return s->scratch[addr];
default:
hw_error("%s: reading from unknown PMGR SCRATCH register 0x%08x\n", __func__, addr);
}
@@ -238,7 +238,7 @@ static uint64_t atv4_pmgr_scratch_read(void *opaque, hwaddr addr, unsigned size)
static void atv4_pmgr_scratch_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
{
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
ATV4PMGRState *s = (struct ATV4PMGRState *) opaque;
switch(addr) {
+328
View File
@@ -0,0 +1,328 @@
/*
* S5L8900 SPI Emulation
*
* by cmw
*/
#include "hw/arm/atv4_spi.h"
static int apple_spi_word_size(ATV4SPIState *s)
{
switch (R_CFG_WORD_SIZE(REG(s, R_CFG))) {
case R_CFG_WORD_SIZE_8B:
return 1;
case R_CFG_WORD_SIZE_16B:
return 2;
case R_CFG_WORD_SIZE_32B:
return 4;
default:
break;
}
g_assert_not_reached();
}
static void apple_spi_update_xfer_tx(ATV4SPIState *s)
{
if (fifo8_is_empty(&s->tx_fifo)) {
REG(s, R_STATUS) |= R_STATUS_TXEMPTY;
}
}
static void apple_spi_update_xfer_rx(ATV4SPIState *s)
{
if (!fifo8_is_empty(&s->rx_fifo)) {
REG(s, R_STATUS) |= R_STATUS_RXREADY;
}
}
static void apple_spi_update_irq(ATV4SPIState *s)
{
uint32_t irq = 0;
uint32_t mask = 0;
if (REG(s, R_CFG) & R_CFG_IE_RXREADY) {
mask |= R_STATUS_RXREADY;
}
if (REG(s, R_CFG) & R_CFG_IE_TXEMPTY) {
mask |= R_STATUS_TXEMPTY;
}
if (REG(s, R_CFG) & R_CFG_IE_COMPLETE) {
mask |= R_STATUS_COMPLETE;
}
if (REG(s, R_STATUS) & mask) {
irq = 1;
}
if (irq != s->last_irq) {
s->last_irq = irq;
qemu_set_irq(s->irq, irq);
}
}
static void apple_spi_update_cs(ATV4SPIState *s)
{
BusState *b = BUS(s->spi);
BusChild *kid = QTAILQ_FIRST(&b->children);
if (kid) {
// TODO GPIO not properly setup yet
//qemu_set_irq(qdev_get_gpio_in_named(kid->child, SSI_GPIO_CS, 0), (REG(s, R_PIN) & R_PIN_CS) != 0);
}
}
static void apple_spi_cs_set(void *opaque, int pin, int level)
{
ATV4SPIState *s = ATV4_SPI(opaque);
if (level) {
REG(s, R_PIN) |= R_PIN_CS;
} else {
REG(s, R_PIN) &= ~R_PIN_CS;
}
apple_spi_update_cs(s);
}
static void apple_spi_run(ATV4SPIState *s)
{
uint32_t tx;
uint32_t rx;
if (!(REG(s, R_CTRL) & R_CTRL_RUN)) {
return;
}
if (REG(s, R_RXCNT) == 0 && REG(s, R_TXCNT) == 0) {
return;
}
apple_spi_update_xfer_tx(s);
//printf("TX queue: %d, RX queue: %d\n", REG(s, R_TXCNT), REG(s, R_RXCNT));
//printf("TX buffer size: %d, RX buffer size: %d\n", fifo8_num_used(&s->tx_fifo), fifo8_num_used(&s->rx_fifo));
while (REG(s, R_TXCNT) && !fifo8_is_empty(&s->tx_fifo)) {
tx = (uint32_t)fifo8_pop(&s->tx_fifo);
rx = ssi_transfer(s->spi, tx);
REG(s, R_TXCNT)--;
apple_spi_update_xfer_tx(s);
if (REG(s, R_RXCNT) > 0) {
if (fifo8_is_full(&s->rx_fifo)) {
hw_error("Rx buffer overflow: %d\n", fifo8_num_free(&s->rx_fifo));
qemu_log_mask(LOG_GUEST_ERROR, "%s: rx overflow\n", __func__);
REG(s, R_STATUS) |= R_STATUS_RXOVERFLOW;
} else {
fifo8_push(&s->rx_fifo, (uint8_t)rx);
REG(s, R_RXCNT)--;
apple_spi_update_xfer_rx(s);
}
}
}
// fetch the remaining bytes by sending sentinel bytes.
while (!fifo8_is_full(&s->rx_fifo) && (REG(s, R_RXCNT) > 0) && (REG(s, R_CFG) & R_CFG_AGD)) {
rx = ssi_transfer(s->spi, 0xff);
if (fifo8_is_full(&s->rx_fifo)) {
hw_error("Rx buffer overflow: %d\n", fifo8_num_free(&s->rx_fifo));
qemu_log_mask(LOG_GUEST_ERROR, "%s: rx overflow\n", __func__);
REG(s, R_STATUS) |= R_STATUS_RXOVERFLOW;
break;
} else {
fifo8_push(&s->rx_fifo, (uint8_t)rx);
REG(s, R_RXCNT)--;
apple_spi_update_xfer_rx(s);
}
}
if (REG(s, R_RXCNT) == 0 && REG(s, R_TXCNT) == 0) {
REG(s, R_STATUS) |= R_STATUS_COMPLETE;
}
//printf("<after> TX buffer size: %d, RX buffer size: %d\n", fifo8_num_used(&s->tx_fifo), fifo8_num_used(&s->rx_fifo));
}
static uint64_t atv4_spi_read(void *opaque, hwaddr addr, unsigned size)
{
ATV4SPIState *s = ATV4_SPI(opaque);
//printf("%s (base %d): read from location 0x%08x\n", __func__, s->base, addr);
uint32_t r;
bool run = false;
r = s->regs[addr >> 2];
switch (addr) {
case R_RXDATA: {
const uint8_t *buf = NULL;
int word_size = apple_spi_word_size(s);
uint32_t num = 0;
if (fifo8_is_empty(&s->rx_fifo)) {
hw_error("Rx buffer underflow\n");
qemu_log_mask(LOG_GUEST_ERROR, "%s: rx underflow\n", __func__);
r = 0;
break;
}
buf = fifo8_pop_buf(&s->rx_fifo, word_size, &num);
memcpy(&r, buf, num);
if (fifo8_is_empty(&s->rx_fifo)) {
run = true;
}
break;
}
case R_STATUS: {
int val = 0;
val |= (fifo8_num_used(&s->tx_fifo) << R_STATUS_TXFIFO_SHIFT);
val |= (fifo8_num_used(&s->rx_fifo) << R_STATUS_RXFIFO_SHIFT);
r |= val;
break;
}
default:
break;
}
if (run) {
apple_spi_run(s);
}
apple_spi_update_irq(s);
return r;
}
static void atv4_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
{
ATV4SPIState *s = ATV4_SPI(opaque);
//printf("%s (base %d): writing 0x%08x to 0x%08x\n", __func__, s->base, data, addr);
uint32_t r = data;
uint32_t *mmio = &REG(s, addr);
uint32_t old = *mmio;
bool cs_flg = false;
bool run = false;
switch (addr) {
case R_CTRL:
if (r & R_CTRL_TX_RESET) {
fifo8_reset(&s->tx_fifo);
}
if (r & R_CTRL_RX_RESET) {
fifo8_reset(&s->rx_fifo);
}
if (r & R_CTRL_RUN && !fifo8_is_empty(&s->tx_fifo)) {
run = true;
}
break;
case R_STATUS:
run = true;
r = old & (~r);
break;
case R_PIN:
cs_flg = true;
break;
case R_TXDATA ... R_TXDATA + 3: {
int word_size = apple_spi_word_size(s);
if (fifo8_is_full(&s->tx_fifo) || fifo8_num_free(&s->tx_fifo) < word_size) {
hw_error("Tx buffer overflow: %d\n", fifo8_num_free(&s->tx_fifo));
}
fifo8_push_all(&s->tx_fifo, (uint8_t *)&r, word_size);
break;
case R_CFG:
run = true;
break;
}
default:
break;
}
*mmio = r;
if (cs_flg) {
apple_spi_update_cs(s);
}
if (run) {
apple_spi_run(s);
}
if(addr == R_STATUS) {
apple_spi_update_xfer_tx(s);
apple_spi_update_xfer_rx(s);
}
apple_spi_update_irq(s);
}
static const MemoryRegionOps spi_ops = {
.read = atv4_spi_read,
.write = atv4_spi_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void atv4_spi_reset(DeviceState *d)
{
ATV4SPIState *s = (ATV4SPIState *)d;
memset(s->regs, 0, sizeof(s->regs));
fifo8_reset(&s->tx_fifo);
fifo8_reset(&s->rx_fifo);
}
static uint32_t base_addr = 0;
void set_spi_base(uint32_t base)
{
base_addr = base;
}
static void atv4_spi_realize(DeviceState *dev, struct Error **errp)
{
ATV4SPIState *s = ATV4_SPI(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
char bus_name[32] = { 0 };
snprintf(bus_name, sizeof(bus_name), "%s.bus", dev->id);
s->spi = ssi_create_bus(dev, (const char *)bus_name);
sysbus_init_irq(sbd, &s->irq);
sysbus_init_irq(sbd, &s->cs_line);
qdev_init_gpio_in_named(dev, apple_spi_cs_set, SSI_GPIO_CS, 1);
char name[5];
snprintf(name, 5, "spi%d", base_addr);
memory_region_init_io(&s->iomem, OBJECT(s), &spi_ops, s, name, 0x100);
sysbus_init_mmio(sbd, &s->iomem);
s->base = base_addr;
fifo8_create(&s->tx_fifo, R_FIFO_TX_DEPTH);
fifo8_create(&s->rx_fifo, R_FIFO_RX_DEPTH);
// // create the peripheral
// switch(s->base) {
// case 0:
// {
// DeviceState *dev = ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI);
// IPodTouchNORSPIState *nor = IPOD_TOUCH_NOR_SPI(dev);
// s->nor = nor;
// break;
// }
// case 1:
// break;
// case 4:
// {
// DeviceState *dev = ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_MULTITOUCH);
// IPodTouchMultitouchState *mt = IPOD_TOUCH_MULTITOUCH(dev);
// s->mt = mt;
// break;
// }
// }
}
static void atv4_spi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = atv4_spi_realize;
dc->reset = atv4_spi_reset;
}
static const TypeInfo atv4_spi_info = {
.name = TYPE_ATV4_SPI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ATV4SPIState),
.class_init = atv4_spi_class_init,
};
static void atv4_spi_register_types(void)
{
type_register_static(&atv4_spi_info);
}
type_init(atv4_spi_register_types)
+1 -1
View File
@@ -65,7 +65,7 @@ arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c'))
arm_ss.add(when: 'CONFIG_ATV4', if_true: files('atv4.c', 'atv4_chipid.c', 'atv4_pmgr.c', 'atv4_gpio.c', 'atv4_ausb.c'))
arm_ss.add(when: 'CONFIG_ATV4', if_true: files('atv4.c', 'atv4_chipid.c', 'atv4_pmgr.c', 'atv4_gpio.c', 'atv4_ausb.c', 'atv4_ausb_widget.c', 'atv4_spi.c', 'atv4_anc.c'))
system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
+20 -2
View File
@@ -10,6 +10,9 @@
#include "hw/arm/atv4_pmgr.h"
#include "hw/arm/atv4_gpio.h"
#include "hw/arm/atv4_ausb.h"
#include "hw/arm/atv4_ausb_widget.h"
#include "hw/arm/atv4_spi.h"
#include "hw/arm/atv4_anc.h"
#define TYPE_ATV4 "ATV4"
@@ -20,12 +23,23 @@
#define ATV4_MACHINE(obj) \
OBJECT_CHECK(ATV4MachineState, (obj), TYPE_ATV4_MACHINE)
#define NUM_SPI_PORTS 4
#define SRAM_LENGTH 0x400000 // 4MB
// memory addresses
#define VROM_MEM_BASE 0x100000000
#define UNKNOWN1_MEM_BASE 0x180000000
#define SRAM_MEM_BASE 0x180000000
#define UNKNOWN2_MEM_BASE 0x202220000
#define UNKNOWN3_MEM_BASE 0x202240000
#define AUSB_MEM_BASE 0x20c900000
#define PPNNPL_MEM_BASE 0x208081000
#define ANC0_MEM_BASE 0x208800000
#define ANC1_MEM_BASE 0x208900000
#define SPI0_MEM_BASE 0x20a080000
#define SPI1_MEM_BASE 0x20a084000
#define SPI2_MEM_BASE 0x20a088000
#define SPI3_MEM_BASE 0x20a08C000
#define AUSB_MEM_BASE 0x20c000000
#define AUSB_WIDGET_MEM_BASE 0x20c900000
#define PMGR_MEM_BASE 0x20e000000
#define AIC_MEM_BASE 0x20e100000
#define GPIO_MEM_BASE 0x20e300000
@@ -55,6 +69,10 @@ typedef struct {
ATV4PMGRState *pmgr_state;
ATV4GPIOState *gpio_state;
ATV4AUSBState *ausb_state;
ATV4AUSBWidgetState *ausb_widget_state;
ATV4SPIState *spi_state[4];
ATV4ANCState *anc0_state;
ATV4ANCState *anc1_state;
ATV4_CPREG_VAR_DEF(REG0);
ATV4_CPREG_VAR_DEF(REG1);
ATV4_CPREG_VAR_DEF(REG2);
+17
View File
@@ -0,0 +1,17 @@
#ifndef HW_ARM_ATV4_ANC_H
#define HW_ARM_ATV4_ANC_H
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#define TYPE_ATV4_ANC "atv4.anc"
OBJECT_DECLARE_SIMPLE_TYPE(ATV4ANCState, ATV4_ANC)
typedef struct ATV4ANCState {
SysBusDevice busdev;
MemoryRegion ppnnpl_iomem;
MemoryRegion anc_iomem;
} ATV4ANCState;
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef HW_ARM_ATV4_AUSB_WIDGET_H
#define HW_ARM_ATV4_AUSB_WIDGET_H
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#define TYPE_ATV4_AUSB_WIDGET "atv4.ausbwidget"
OBJECT_DECLARE_SIMPLE_TYPE(ATV4AUSBWidgetState, ATV4_AUSB_WIDGET)
typedef struct ATV4AUSBWidgetState {
SysBusDevice busdev;
MemoryRegion iomem;
} ATV4AUSBWidgetState;
#endif
+11
View File
@@ -5,6 +5,16 @@
#include "hw/hw.h"
#include "hw/sysbus.h"
enum boot_device {
BOOT_DEVICE_NOR = 0,
BOOT_DEVICE_SPI,
BOOT_DEVICE_NAND,
BOOT_DEVICE_NVME,
BOOT_DEVICE_USBDFU,
BOOT_DEVICE_TBTDFU,
BOOT_DEVICE_XMODEM,
};
#define TYPE_ATV4_PMGR "atv4.pmgr"
#define TYPE_ATV4_PMGR_VOLMAN "atv4.pmgr.volman"
#define TYPE_ATV4_PMGR_PS "atv4.pmgr.ps"
@@ -173,6 +183,7 @@ typedef struct ATV4PMGRState {
MemoryRegion scratch_iomem;
MemoryRegion pwrgate_iomem;
uint64_t pll_bypass_cfg[6];
uint64_t scratch[0x4];
} ATV4PMGRState;
#endif
+76
View File
@@ -0,0 +1,76 @@
#ifndef HW_ARM_ATV4_SPI_H
#define HW_ARM_ATV4_SPI_H
#include "qemu/osdep.h"
#include "qemu/fifo8.h"
#include "qemu/log.h"
#include "hw/platform-bus.h"
#include "hw/hw.h"
#include "hw/irq.h"
#include "hw/ssi/ssi.h"
#define TYPE_ATV4_SPI "atv4.spi"
OBJECT_DECLARE_SIMPLE_TYPE(ATV4SPIState, ATV4_SPI)
#define R_CTRL 0x000
#define R_CTRL_RUN (1 << 0)
#define R_CTRL_TX_RESET (1 << 2)
#define R_CTRL_RX_RESET (1 << 3)
#define R_CFG 0x004
#define R_CFG_AGD (1 << 0)
#define R_CFG_CPHA (1 << 1)
#define R_CFG_CPOL (1 << 2)
#define R_CFG_IE_RXREADY (1 << 7)
#define R_CFG_IE_TXEMPTY (1 << 8)
#define R_CFG_WORD_SIZE(_x) (((_x) >> 15) & 0x3)
#define R_CFG_WORD_SIZE_8B 0
#define R_CFG_WORD_SIZE_16B 1
#define R_CFG_WORD_SIZE_32B 2
#define R_CFG_IE_COMPLETE (1 << 21)
#define R_STATUS 0x008
#define R_STATUS_RXREADY (1 << 0)
#define R_STATUS_TXEMPTY (1 << 1)
#define R_STATUS_RXOVERFLOW (1 << 3)
#define R_STATUS_COMPLETE (1 << 22)
#define R_STATUS_TXFIFO_SHIFT (6)
#define R_STATUS_RXFIFO_SHIFT (11)
#define R_PIN 0x00c
#define R_PIN_CS (1 << 1)
#define R_TXDATA 0x010
#define R_RXDATA 0x020
#define R_CLKDIV 0x030
#define R_CLKDIV_MAX 0x7ff
#define R_RXCNT 0x034
#define R_WORD_DELAY 0x038
#define R_TXCNT 0x04c
#define R_FIFO_TX_DEPTH 50000
#define R_FIFO_RX_DEPTH 16
#define REG(_s,_v) ((_s)->regs[(_v)>>2])
#define MMIO_SIZE (0x4000)
typedef struct ATV4SPIState {
SysBusDevice parent_obj;
MemoryRegion iomem;
SSIBus *spi;
qemu_irq irq;
uint32_t last_irq;
qemu_irq cs_line;
uint32_t regs[MMIO_SIZE >> 2];
uint8_t base;
Fifo8 rx_fifo;
Fifo8 tx_fifo;
} ATV4SPIState;
void set_spi_base(uint32_t base);
#endif