hw/arm: add experimental iPhone 5 A6 platform

This commit is contained in:
2026-08-31 02:16:31 +02:00
parent cf256aa081
commit 47977dd34a
34 changed files with 4524 additions and 0 deletions
+239
View File
@@ -0,0 +1,239 @@
#include "qemu/osdep.h"
#include "hw/core/sysbus.h"
#include "hw/core/irq.h"
#include "hw/core/qdev-properties-system.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "chardev/char-fe.h"
#define TYPE_S5L8950X_UART "s5l8950x-uart"
OBJECT_DECLARE_SIMPLE_TYPE(S5L8950XUartState, S5L8950X_UART)
struct S5L8950XUartState {
SysBusDevice parent_obj;
MemoryRegion iomem;
CharFrontend chr;
uint32_t ulcon;
uint32_t ucon;
uint32_t ufcon;
uint32_t umcon;
uint32_t ubrdiv;
uint32_t ufracval;
uint8_t rx_fifo[16];
int rx_count;
qemu_irq irq;
};
#define UART_ULCON 0x00
#define UART_UCON 0x04
#define UART_UFCON 0x08
#define UART_UMCON 0x0C
#define UART_UTRSTAT 0x10
#define UART_UERSTAT 0x14
#define UART_UFSTAT 0x18
#define UART_UMSTAT 0x1C
#define UART_UTXH 0x20
#define UART_URXH 0x24
#define UART_UBRDIV 0x28
#define UART_UFRACVAL 0x2C
static void s5l8950x_uart_update_irq(S5L8950XUartState *s)
{
if (s->rx_count > 0) {
qemu_irq_raise(s->irq);
} else {
qemu_irq_lower(s->irq);
}
}
static uint64_t s5l8950x_uart_read(void *opaque, hwaddr offset, unsigned size)
{
S5L8950XUartState *s = S5L8950X_UART(opaque);
uint32_t val = 0;
switch (offset) {
case UART_ULCON:
val = s->ulcon;
break;
case UART_UCON:
val = s->ucon;
break;
case UART_UFCON:
val = s->ufcon;
break;
case UART_UMCON:
val = s->umcon;
break;
case UART_UTRSTAT:
/* Bit 0: rx ready, Bit 1: tx buf empty, Bit 2: tx empty */
val = 0x6 | (s->rx_count > 0 ? 1 : 0);
break;
case UART_UERSTAT:
val = 0;
break;
case UART_UFSTAT:
/* Return rx count in low bits, no tx fifo used here */
val = s->rx_count & 0xf;
break;
case UART_UMSTAT:
val = 0;
break;
case UART_UTXH:
break;
case UART_URXH:
if (s->rx_count > 0) {
val = s->rx_fifo[0];
s->rx_count--;
memmove(s->rx_fifo, s->rx_fifo + 1, s->rx_count);
s5l8950x_uart_update_irq(s);
}
break;
case UART_UBRDIV:
val = s->ubrdiv;
break;
case UART_UFRACVAL:
val = s->ufracval;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Unimplemented read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
}
return val;
}
static void s5l8950x_uart_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
{
S5L8950XUartState *s = S5L8950X_UART(opaque);
unsigned char c;
switch (offset) {
case UART_ULCON:
s->ulcon = val;
break;
case UART_UCON:
s->ucon = val;
break;
case UART_UFCON:
s->ufcon = val;
break;
case UART_UMCON:
s->umcon = val;
break;
case UART_UTRSTAT:
case UART_UERSTAT:
case UART_UFSTAT:
case UART_UMSTAT:
/* Read-only registers */
break;
case UART_UTXH:
c = val & 0xFF;
qemu_chr_fe_write_all(&s->chr, &c, 1);
break;
case UART_URXH:
break;
case UART_UBRDIV:
s->ubrdiv = val;
break;
case UART_UFRACVAL:
s->ufracval = val;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: Unimplemented write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
}
}
static const MemoryRegionOps s5l8950x_uart_ops = {
.read = s5l8950x_uart_read,
.write = s5l8950x_uart_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static int s5l8950x_uart_can_receive(void *opaque)
{
S5L8950XUartState *s = S5L8950X_UART(opaque);
return sizeof(s->rx_fifo) - s->rx_count;
}
static void s5l8950x_uart_receive(void *opaque, const uint8_t *buf, int size)
{
S5L8950XUartState *s = S5L8950X_UART(opaque);
int i;
for (i = 0; i < size && s->rx_count < sizeof(s->rx_fifo); i++) {
s->rx_fifo[s->rx_count++] = buf[i];
}
s5l8950x_uart_update_irq(s);
}
static void s5l8950x_uart_reset(DeviceState *dev)
{
S5L8950XUartState *s = S5L8950X_UART(dev);
s->ulcon = 0;
s->ucon = 0;
s->ufcon = 0;
s->umcon = 0;
s->ubrdiv = 0;
s->ufracval = 0;
s->rx_count = 0;
s5l8950x_uart_update_irq(s);
}
static void s5l8950x_uart_realize(DeviceState *dev, Error **errp)
{
S5L8950XUartState *s = S5L8950X_UART(dev);
qemu_chr_fe_set_handlers(&s->chr, s5l8950x_uart_can_receive,
s5l8950x_uart_receive, NULL, NULL,
s, NULL, true);
}
static void s5l8950x_uart_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
S5L8950XUartState *s = S5L8950X_UART(obj);
memory_region_init_io(&s->iomem, obj, &s5l8950x_uart_ops, s,
TYPE_S5L8950X_UART, 0x100);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
}
static const Property s5l8950x_uart_properties[] = {
DEFINE_PROP_CHR("chardev", S5L8950XUartState, chr),
};
static void s5l8950x_uart_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_legacy_reset(dc, s5l8950x_uart_reset);
dc->realize = s5l8950x_uart_realize;
device_class_set_props(dc, s5l8950x_uart_properties);
}
static const TypeInfo s5l8950x_uart_info = {
.name = TYPE_S5L8950X_UART,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(S5L8950XUartState),
.instance_init = s5l8950x_uart_init,
.class_init = s5l8950x_uart_class_init,
};
static void s5l8950x_uart_register_types(void)
{
type_register_static(&s5l8950x_uart_info);
}
type_init(s5l8950x_uart_register_types)