From 5cc6ebf9bd6cb75078a3bd2abe91cfe495deb75b Mon Sep 17 00:00:00 2001 From: espes Date: Sat, 24 Aug 2013 16:11:26 +1000 Subject: [PATCH] let lpc47m157 control its own serial devices --- hw/xbox/lpc47m157.c | 116 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 17 deletions(-) diff --git a/hw/xbox/lpc47m157.c b/hw/xbox/lpc47m157.c index 266a41470e..b40176c380 100644 --- a/hw/xbox/lpc47m157.c +++ b/hw/xbox/lpc47m157.c @@ -18,16 +18,12 @@ */ #include "hw/isa/isa.h" +#include "hw/char/serial.h" +#include "sysemu/sysemu.h" +#include "sysemu/char.h" +#include "qapi/qmp/qerror.h" - -#define ENTER_CONFIG_KEY 0x55 -#define EXIT_CONFIG_KEY 0xAA - -#define MAX_CONFIG_REG 0x30 -#define CONFIG_DEVICE_NUMBER 0x07 -#define CONFIG_PORT_LOW 0x26 -#define CONFIG_PORT_HIGH 0x27 - +#define MAX_DEVICE 0xC #define DEVICE_FDD 0x0 #define DEVICE_PARALLEL_PORT 0x3 #define DEVICE_SERIAL_PORT_1 0x4 @@ -37,8 +33,20 @@ #define DEVICE_PME 0xA #define DEVICE_MPU_401 0xB +#define ENTER_CONFIG_KEY 0x55 +#define EXIT_CONFIG_KEY 0xAA + +#define MAX_CONFIG_REG 0x30 +#define MAX_DEVICE_REGS 0xFF + +#define CONFIG_DEVICE_NUMBER 0x07 +#define CONFIG_PORT_LOW 0x26 +#define CONFIG_PORT_HIGH 0x27 + +#define CONFIG_DEVICE_ACTIVATE 0x30 #define CONFIG_DEVICE_BASE_ADDRESS_HIGH 0x60 #define CONFIG_DEVICE_BASE_ADDRESS_LOW 0x61 +#define CONFIG_DEVICE_INETRRUPT 0x70 #define DEBUG_LPC47M157 @@ -51,11 +59,41 @@ typedef struct LPC47M157State { uint32_t selected_reg; uint8_t config_regs[MAX_CONFIG_REG]; + uint8_t device_regs[MAX_DEVICE][MAX_DEVICE_REGS]; + + struct { + bool active; + SerialState state; + } serial[2]; } LPC47M157State; #define LPC47M157_DEVICE(obj) \ OBJECT_CHECK(LPC47M157State, (obj), "lpc47m157") +static void update_devices(LPC47M157State *s) +{ + ISADevice *isadev = ISA_DEVICE(s); + + /* init serial devices */ + for (int i=0; i<2; i++) { + uint8_t *dev = s->device_regs[DEVICE_SERIAL_PORT_1 + i]; + if (dev[CONFIG_DEVICE_ACTIVATE] && !s->serial[i].active) { + + uint32_t iobase = (dev[CONFIG_DEVICE_BASE_ADDRESS_HIGH] << 8) + | dev[CONFIG_DEVICE_BASE_ADDRESS_LOW]; + uint32_t irq = dev[CONFIG_DEVICE_INETRRUPT]; + + SerialState *ss = &s->serial[i].state; + if (irq != 0) { + isa_init_irq(isadev, &ss->irq, irq); + } + isa_register_ioport(isadev, &ss->io, iobase); + + s->serial[i].active = true; + } + } +} + static void lpc47m157_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { @@ -72,19 +110,23 @@ static void lpc47m157_io_write(void *opaque, hwaddr addr, uint64_t val, } else if (val == EXIT_CONFIG_KEY) { assert(s->configuration_mode); s->configuration_mode = false; + + update_devices(s); } else { s->selected_reg = val; } } else if (addr == 1) { //DATA_PORT if (s->selected_reg < MAX_CONFIG_REG) { - //global configuration register + /* global configuration register */ s->config_regs[s->selected_reg] = val; } else { - if (s->config_regs[CONFIG_DEVICE_NUMBER] == DEVICE_SERIAL_PORT_1) { - - } else { - assert(false); - } + /* device register */ + assert(s->config_regs[CONFIG_DEVICE_NUMBER] < MAX_DEVICE); + uint8_t* dev = s->device_regs[s->config_regs[CONFIG_DEVICE_NUMBER]]; + dev[s->selected_reg] = val; +#ifdef DEBUG_LPC47M157 + printf("lpc47m157 dev %x . %x = %llx\n", s->config_regs[CONFIG_DEVICE_NUMBER], s->selected_reg, val); +#endif } } else { assert(false); @@ -102,7 +144,9 @@ static uint64_t lpc47m157_io_read(void *opaque, hwaddr addr, unsigned int size) if (s->selected_reg < MAX_CONFIG_REG) { val = s->config_regs[s->selected_reg]; } else { - + assert(s->config_regs[CONFIG_DEVICE_NUMBER] < MAX_DEVICE); + uint8_t* dev = s->device_regs[s->config_regs[CONFIG_DEVICE_NUMBER]]; + val = dev[s->selected_reg]; } } else { assert(false); @@ -136,15 +180,53 @@ static void lpc47m157_realize(DeviceState *dev, Error **errp) memory_region_init_io(&s->io, OBJECT(s), &lpc47m157_io_ops, s, "lpc47m157", 2); isa_register_ioport(isa, &s->io, iobase); + + /* init serial cores */ + for (int i=0; i<2; i++) { + CharDriverState *chr = serial_hds[i]; + if (chr == NULL) { + char name[5]; + snprintf(name, sizeof(name), "ser%d", i); + chr = qemu_chr_new(name, "null", NULL); + } + + SerialState *ss = &s->serial[i].state; + ss->chr = chr; + ss->baudbase = 115200; + + Error *err = NULL; + serial_realize_core(ss, &err); + if (err != NULL) { + qerror_report_err(err); + error_free(err); + exit(1); + } + + memory_region_init_io(&ss->io, OBJECT(s), + &serial_io_ops, ss, "serial", 8); + } } +static const VMStateDescription vmstate_lpc47m157= { + .name = "lpc47m157", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(serial[0].state, LPC47M157State, 0, + vmstate_serial, SerialState), + VMSTATE_STRUCT(serial[1].state, LPC47M157State, 0, + vmstate_serial, SerialState), + VMSTATE_END_OF_LIST() + } +}; + static void lpc47m157_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = lpc47m157_realize; + dc->vmsd = &vmstate_lpc47m157; //dc->reset = pc87312_reset; - //dc->vmsd = &vmstate_pc87312; //dc->props = pc87312_properties; }