let lpc47m157 control its own serial devices

This commit is contained in:
espes 2013-08-24 16:11:26 +10:00
parent 4a23de0a88
commit 5cc6ebf9bd
1 changed files with 99 additions and 17 deletions

View File

@ -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;
}