Message ID | c2915d0d2f3966ddb92005129b680727a69a3bcd.1487522123.git.balaton@eik.bme.hu (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 19 February 2017 at 16:35, BALATON Zoltan <balaton@eik.bme.hu> wrote: > Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> > --- > hw/display/sm501.c | 133 +++++++++++++++++++++++++++++++++++---------------- > hw/sh4/r2d.c | 11 ++++- > include/hw/devices.h | 5 -- > 3 files changed, 101 insertions(+), 48 deletions(-) > > diff --git a/hw/display/sm501.c b/hw/display/sm501.c > index 4eb085c..b592022 100644 > --- a/hw/display/sm501.c > +++ b/hw/display/sm501.c > @@ -58,8 +58,8 @@ > #define SM501_DPRINTF(fmt, ...) do {} while (0) > #endif > > - > #define MMIO_BASE_OFFSET 0x3e00000 > +#define MMIO_SIZE 0x200000 > > /* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */ > > @@ -464,6 +464,7 @@ typedef struct SM501State { > uint32_t local_mem_size_index; > uint8_t *local_mem; > MemoryRegion local_mem_region; > + MemoryRegion mmio_region; > uint32_t last_width; > uint32_t last_height; > > @@ -1396,20 +1397,14 @@ static const GraphicHwOps sm501_ops = { > .gfx_update = sm501_update_display, > }; > > -void sm501_init(MemoryRegion *address_space_mem, uint32_t base, > - uint32_t local_mem_bytes, qemu_irq irq, Chardev *chr) > +static void sm501_init(SM501State *s, DeviceState *dev, uint32_t base, > + uint32_t local_mem_bytes) > { > - SM501State *s; > - DeviceState *dev; > - MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1); > - MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1); > - MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1); > - > - /* allocate management data region */ > - s = g_new0(SM501State, 1); > + MemoryRegion *mr; > + > s->base = base; > s->local_mem_size_index = get_local_mem_size_index(local_mem_bytes); > - SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s), > + SM501_DPRINTF("sm501 local mem size=%x. index=%d\n", get_local_mem_size(s), > s->local_mem_size_index); > s->system_control = 0x00100000; /* 2D engine FIFO empty */ > s->misc_control = SM501_MISC_IRQ_INVERT; /* assumes SH, active=low */ > @@ -1417,46 +1412,102 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, > s->dc_crt_control = 0x00010000; > > /* allocate local memory */ > - memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local", > + memory_region_init_ram(&s->local_mem_region, OBJECT(dev), "sm501.local", > local_mem_bytes, &error_fatal); > vmstate_register_ram_global(&s->local_mem_region); > memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA); > s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region); > - memory_region_add_subregion(address_space_mem, base, &s->local_mem_region); > - > - /* map mmio */ > - memory_region_init_io(sm501_system_config, NULL, &sm501_system_config_ops, > - s, "sm501-system-config", 0x6c); > - memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET, > - sm501_system_config); > - memory_region_init_io(sm501_disp_ctrl, NULL, &sm501_disp_ctrl_ops, s, > + > + /* allocate mmio */ > + memory_region_init(&s->mmio_region, OBJECT(dev), "sm501.mmio", MMIO_SIZE); > + mr = g_new(MemoryRegion, 1); There's no need to dynamically allocate any of these memory regions; just make them be MemoryRegion fields inside SM501State. > + memory_region_init_io(mr, OBJECT(dev), &sm501_system_config_ops, s, > + "sm501-system-config", 0x6c); > + memory_region_add_subregion(&s->mmio_region, SM501_SYS_CONFIG, mr); > + mr = g_new(MemoryRegion, 1); > + memory_region_init_io(mr, OBJECT(dev), &sm501_disp_ctrl_ops, s, > "sm501-disp-ctrl", 0x1000); > - memory_region_add_subregion(address_space_mem, > - base + MMIO_BASE_OFFSET + SM501_DC, > - sm501_disp_ctrl); > - memory_region_init_io(sm501_2d_engine, NULL, &sm501_2d_engine_ops, s, > + memory_region_add_subregion(&s->mmio_region, SM501_DC, mr); > + mr = g_new(MemoryRegion, 1); > + memory_region_init_io(mr, OBJECT(dev), &sm501_2d_engine_ops, s, > "sm501-2d-engine", 0x54); > - memory_region_add_subregion(address_space_mem, > - base + MMIO_BASE_OFFSET + SM501_2D_ENGINE, > - sm501_2d_engine); > + memory_region_add_subregion(&s->mmio_region, SM501_2D_ENGINE, mr); > + > + /* create qemu graphic console */ > + s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); > +} > + > +#define TYPE_SYSBUS_SM501 "sysbus-sm501" > +#define SYSBUS_SM501(obj) \ > + OBJECT_CHECK(SM501SysBusState, (obj), TYPE_SYSBUS_SM501) > + > +typedef struct { > + /*< private >*/ > + SysBusDevice parent_obj; > + /*< public >*/ > + SM501State state; > + uint32_t vram_size; > + uint32_t base; > + void *chr_state; > +} SM501SysBusState; > + > +static void sm501_realize_sysbus(DeviceState *dev, Error **errp) > +{ > + SM501SysBusState *s = SYSBUS_SM501(dev); > + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > + DeviceState *usb_dev; > + > + sm501_init(&s->state, dev, s->base, s->vram_size); > + sysbus_init_mmio(sbd, &s->state.local_mem_region); > + sysbus_init_mmio(sbd, &s->state.mmio_region); > > /* bridge to usb host emulation module */ > - dev = qdev_create(NULL, "sysbus-ohci"); > - qdev_prop_set_uint32(dev, "num-ports", 2); > - qdev_prop_set_uint64(dev, "dma-offset", base); > - qdev_init_nofail(dev); > - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, > - base + MMIO_BASE_OFFSET + SM501_USB_HOST); > - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); > + usb_dev = qdev_create(NULL, "sysbus-ohci"); > + qdev_prop_set_uint32(usb_dev, "num-ports", 2); > + qdev_prop_set_uint64(usb_dev, "dma-offset", s->base); > + qdev_init_nofail(usb_dev); Why is a display controller device creating a USB controller? This looks like something that should be being done by the board. > + memory_region_add_subregion(&s->state.mmio_region, SM501_USB_HOST, > + sysbus_mmio_get_region(SYS_BUS_DEVICE(usb_dev), 0)); > + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev)); > > /* bridge to serial emulation module */ > - if (chr) { > - serial_mm_init(address_space_mem, > - base + MMIO_BASE_OFFSET + SM501_UART0, 2, > + if (s->chr_state) { > + serial_mm_init(&s->state.mmio_region, SM501_UART0, 2, > NULL, /* TODO : chain irq to IRL */ > - 115200, chr, DEVICE_NATIVE_ENDIAN); > + 115200, s->chr_state, DEVICE_NATIVE_ENDIAN); > } > +} Similarly, what's going on here with the serial? > > - /* create qemu graphic console */ > - s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); > +static Property sm501_sysbus_properties[] = { > + DEFINE_PROP_UINT32("vram-size", SM501SysBusState, vram_size, 0), > + DEFINE_PROP_UINT32("base", SM501SysBusState, base, 0), > + DEFINE_PROP_PTR("chr-state", SM501SysBusState, chr_state), > + DEFINE_PROP_END_OF_LIST(), > +}; > +static void sm501_sysbus_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + dc->realize = sm501_realize_sysbus; > + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); > + dc->desc = "SM501 Multimedia Companion"; > + dc->props = sm501_sysbus_properties; > +/* Note: pointer property "chr-state" may remain null, thus > + * no need for dc->cannot_instantiate_with_device_add_yet = true; > + */ > } You also need a VMState struct registered in dc->vmsd and a reset function registered in dc->reset. thanks -- PMM
On Fri, 24 Feb 2017, Peter Maydell wrote: > On 19 February 2017 at 16:35, BALATON Zoltan <balaton@eik.bme.hu> wrote: >> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> >> --- >> hw/display/sm501.c | 133 +++++++++++++++++++++++++++++++++++---------------- >> hw/sh4/r2d.c | 11 ++++- >> include/hw/devices.h | 5 -- >> 3 files changed, 101 insertions(+), 48 deletions(-) >> >> diff --git a/hw/display/sm501.c b/hw/display/sm501.c >> index 4eb085c..b592022 100644 >> --- a/hw/display/sm501.c >> +++ b/hw/display/sm501.c >> @@ -58,8 +58,8 @@ >> #define SM501_DPRINTF(fmt, ...) do {} while (0) >> #endif >> >> - >> #define MMIO_BASE_OFFSET 0x3e00000 >> +#define MMIO_SIZE 0x200000 >> >> /* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */ >> >> @@ -464,6 +464,7 @@ typedef struct SM501State { >> uint32_t local_mem_size_index; >> uint8_t *local_mem; >> MemoryRegion local_mem_region; >> + MemoryRegion mmio_region; >> uint32_t last_width; >> uint32_t last_height; >> >> @@ -1396,20 +1397,14 @@ static const GraphicHwOps sm501_ops = { >> .gfx_update = sm501_update_display, >> }; >> >> -void sm501_init(MemoryRegion *address_space_mem, uint32_t base, >> - uint32_t local_mem_bytes, qemu_irq irq, Chardev *chr) >> +static void sm501_init(SM501State *s, DeviceState *dev, uint32_t base, >> + uint32_t local_mem_bytes) >> { >> - SM501State *s; >> - DeviceState *dev; >> - MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1); >> - MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1); >> - MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1); >> - >> - /* allocate management data region */ >> - s = g_new0(SM501State, 1); >> + MemoryRegion *mr; >> + >> s->base = base; >> s->local_mem_size_index = get_local_mem_size_index(local_mem_bytes); >> - SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s), >> + SM501_DPRINTF("sm501 local mem size=%x. index=%d\n", get_local_mem_size(s), >> s->local_mem_size_index); >> s->system_control = 0x00100000; /* 2D engine FIFO empty */ >> s->misc_control = SM501_MISC_IRQ_INVERT; /* assumes SH, active=low */ >> @@ -1417,46 +1412,102 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, >> s->dc_crt_control = 0x00010000; >> >> /* allocate local memory */ >> - memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local", >> + memory_region_init_ram(&s->local_mem_region, OBJECT(dev), "sm501.local", >> local_mem_bytes, &error_fatal); >> vmstate_register_ram_global(&s->local_mem_region); >> memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA); >> s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region); >> - memory_region_add_subregion(address_space_mem, base, &s->local_mem_region); >> - >> - /* map mmio */ >> - memory_region_init_io(sm501_system_config, NULL, &sm501_system_config_ops, >> - s, "sm501-system-config", 0x6c); >> - memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET, >> - sm501_system_config); >> - memory_region_init_io(sm501_disp_ctrl, NULL, &sm501_disp_ctrl_ops, s, >> + >> + /* allocate mmio */ >> + memory_region_init(&s->mmio_region, OBJECT(dev), "sm501.mmio", MMIO_SIZE); >> + mr = g_new(MemoryRegion, 1); > > There's no need to dynamically allocate any of these memory regions; > just make them be MemoryRegion fields inside SM501State. > >> + memory_region_init_io(mr, OBJECT(dev), &sm501_system_config_ops, s, >> + "sm501-system-config", 0x6c); >> + memory_region_add_subregion(&s->mmio_region, SM501_SYS_CONFIG, mr); >> + mr = g_new(MemoryRegion, 1); >> + memory_region_init_io(mr, OBJECT(dev), &sm501_disp_ctrl_ops, s, >> "sm501-disp-ctrl", 0x1000); >> - memory_region_add_subregion(address_space_mem, >> - base + MMIO_BASE_OFFSET + SM501_DC, >> - sm501_disp_ctrl); >> - memory_region_init_io(sm501_2d_engine, NULL, &sm501_2d_engine_ops, s, >> + memory_region_add_subregion(&s->mmio_region, SM501_DC, mr); >> + mr = g_new(MemoryRegion, 1); >> + memory_region_init_io(mr, OBJECT(dev), &sm501_2d_engine_ops, s, >> "sm501-2d-engine", 0x54); >> - memory_region_add_subregion(address_space_mem, >> - base + MMIO_BASE_OFFSET + SM501_2D_ENGINE, >> - sm501_2d_engine); >> + memory_region_add_subregion(&s->mmio_region, SM501_2D_ENGINE, mr); >> + >> + /* create qemu graphic console */ >> + s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); >> +} >> + >> +#define TYPE_SYSBUS_SM501 "sysbus-sm501" >> +#define SYSBUS_SM501(obj) \ >> + OBJECT_CHECK(SM501SysBusState, (obj), TYPE_SYSBUS_SM501) >> + >> +typedef struct { >> + /*< private >*/ >> + SysBusDevice parent_obj; >> + /*< public >*/ >> + SM501State state; >> + uint32_t vram_size; >> + uint32_t base; >> + void *chr_state; >> +} SM501SysBusState; >> + >> +static void sm501_realize_sysbus(DeviceState *dev, Error **errp) >> +{ >> + SM501SysBusState *s = SYSBUS_SM501(dev); >> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); >> + DeviceState *usb_dev; >> + >> + sm501_init(&s->state, dev, s->base, s->vram_size); >> + sysbus_init_mmio(sbd, &s->state.local_mem_region); >> + sysbus_init_mmio(sbd, &s->state.mmio_region); >> >> /* bridge to usb host emulation module */ >> - dev = qdev_create(NULL, "sysbus-ohci"); >> - qdev_prop_set_uint32(dev, "num-ports", 2); >> - qdev_prop_set_uint64(dev, "dma-offset", base); >> - qdev_init_nofail(dev); >> - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, >> - base + MMIO_BASE_OFFSET + SM501_USB_HOST); >> - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); >> + usb_dev = qdev_create(NULL, "sysbus-ohci"); >> + qdev_prop_set_uint32(usb_dev, "num-ports", 2); >> + qdev_prop_set_uint64(usb_dev, "dma-offset", s->base); >> + qdev_init_nofail(usb_dev); > > Why is a display controller device creating a USB controller? > This looks like something that should be being done by the board. > >> + memory_region_add_subregion(&s->state.mmio_region, SM501_USB_HOST, >> + sysbus_mmio_get_region(SYS_BUS_DEVICE(usb_dev), 0)); >> + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev)); >> >> /* bridge to serial emulation module */ >> - if (chr) { >> - serial_mm_init(address_space_mem, >> - base + MMIO_BASE_OFFSET + SM501_UART0, 2, >> + if (s->chr_state) { >> + serial_mm_init(&s->state.mmio_region, SM501_UART0, 2, >> NULL, /* TODO : chain irq to IRL */ >> - 115200, chr, DEVICE_NATIVE_ENDIAN); >> + 115200, s->chr_state, DEVICE_NATIVE_ENDIAN); >> } >> +} > > Similarly, what's going on here with the serial? The SM501/SM502 is a multimedia chip that besides a display controller also contains some other functions (see http://cateee.net/lkddb/web-lkddb/MFD_SM501.html) and this is what is emulated here as these are part of the chip itself. > >> >> - /* create qemu graphic console */ >> - s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); >> +static Property sm501_sysbus_properties[] = { >> + DEFINE_PROP_UINT32("vram-size", SM501SysBusState, vram_size, 0), >> + DEFINE_PROP_UINT32("base", SM501SysBusState, base, 0), >> + DEFINE_PROP_PTR("chr-state", SM501SysBusState, chr_state), >> + DEFINE_PROP_END_OF_LIST(), >> +}; > >> +static void sm501_sysbus_class_init(ObjectClass *klass, void *data) >> +{ >> + DeviceClass *dc = DEVICE_CLASS(klass); >> + >> + dc->realize = sm501_realize_sysbus; >> + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); >> + dc->desc = "SM501 Multimedia Companion"; >> + dc->props = sm501_sysbus_properties; >> +/* Note: pointer property "chr-state" may remain null, thus >> + * no need for dc->cannot_instantiate_with_device_add_yet = true; >> + */ >> } > > You also need a VMState struct registered in dc->vmsd and a reset > function registered in dc->reset. Even if no migration is supported? Is there a simple example I could look at on what should go into these?
On 24 February 2017 at 20:23, BALATON Zoltan <balaton@eik.bme.hu> wrote: > On Fri, 24 Feb 2017, Peter Maydell wrote: >> >> On 19 February 2017 at 16:35, BALATON Zoltan <balaton@eik.bme.hu> wrote: >>> >>> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> >>> --- >>> hw/display/sm501.c | 133 >>> +++++++++++++++++++++++++++++++++++---------------- >>> hw/sh4/r2d.c | 11 ++++- >>> include/hw/devices.h | 5 -- >>> 3 files changed, 101 insertions(+), 48 deletions(-) >>> >>> diff --git a/hw/display/sm501.c b/hw/display/sm501.c >>> index 4eb085c..b592022 100644 >>> --- a/hw/display/sm501.c >>> +++ b/hw/display/sm501.c >>> @@ -58,8 +58,8 @@ >>> #define SM501_DPRINTF(fmt, ...) do {} while (0) >>> #endif >>> >>> - >>> #define MMIO_BASE_OFFSET 0x3e00000 >>> +#define MMIO_SIZE 0x200000 >>> >>> /* SM501 register definitions taken from >>> "linux/include/linux/sm501-regs.h" */ >>> >>> @@ -464,6 +464,7 @@ typedef struct SM501State { >>> uint32_t local_mem_size_index; >>> uint8_t *local_mem; >>> MemoryRegion local_mem_region; >>> + MemoryRegion mmio_region; >>> uint32_t last_width; >>> uint32_t last_height; >>> >>> @@ -1396,20 +1397,14 @@ static const GraphicHwOps sm501_ops = { >>> .gfx_update = sm501_update_display, >>> }; >>> >>> -void sm501_init(MemoryRegion *address_space_mem, uint32_t base, >>> - uint32_t local_mem_bytes, qemu_irq irq, Chardev *chr) >>> +static void sm501_init(SM501State *s, DeviceState *dev, uint32_t base, >>> + uint32_t local_mem_bytes) >>> { >>> - SM501State *s; >>> - DeviceState *dev; >>> - MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1); >>> - MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1); >>> - MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1); >>> - >>> - /* allocate management data region */ >>> - s = g_new0(SM501State, 1); >>> + MemoryRegion *mr; >>> + >>> s->base = base; >>> s->local_mem_size_index = get_local_mem_size_index(local_mem_bytes); >>> - SM501_DPRINTF("local mem size=%x. index=%d\n", >>> get_local_mem_size(s), >>> + SM501_DPRINTF("sm501 local mem size=%x. index=%d\n", >>> get_local_mem_size(s), >>> s->local_mem_size_index); >>> s->system_control = 0x00100000; /* 2D engine FIFO empty */ >>> s->misc_control = SM501_MISC_IRQ_INVERT; /* assumes SH, active=low >>> */ >>> @@ -1417,46 +1412,102 @@ void sm501_init(MemoryRegion *address_space_mem, >>> uint32_t base, >>> s->dc_crt_control = 0x00010000; >>> >>> /* allocate local memory */ >>> - memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local", >>> + memory_region_init_ram(&s->local_mem_region, OBJECT(dev), >>> "sm501.local", >>> local_mem_bytes, &error_fatal); >>> vmstate_register_ram_global(&s->local_mem_region); >>> memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA); >>> s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region); >>> - memory_region_add_subregion(address_space_mem, base, >>> &s->local_mem_region); >>> - >>> - /* map mmio */ >>> - memory_region_init_io(sm501_system_config, NULL, >>> &sm501_system_config_ops, >>> - s, "sm501-system-config", 0x6c); >>> - memory_region_add_subregion(address_space_mem, base + >>> MMIO_BASE_OFFSET, >>> - sm501_system_config); >>> - memory_region_init_io(sm501_disp_ctrl, NULL, &sm501_disp_ctrl_ops, >>> s, >>> + >>> + /* allocate mmio */ >>> + memory_region_init(&s->mmio_region, OBJECT(dev), "sm501.mmio", >>> MMIO_SIZE); >>> + mr = g_new(MemoryRegion, 1); >> >> >> There's no need to dynamically allocate any of these memory regions; >> just make them be MemoryRegion fields inside SM501State. >> >>> + memory_region_init_io(mr, OBJECT(dev), &sm501_system_config_ops, s, >>> + "sm501-system-config", 0x6c); >>> + memory_region_add_subregion(&s->mmio_region, SM501_SYS_CONFIG, mr); >>> + mr = g_new(MemoryRegion, 1); >>> + memory_region_init_io(mr, OBJECT(dev), &sm501_disp_ctrl_ops, s, >>> "sm501-disp-ctrl", 0x1000); >>> - memory_region_add_subregion(address_space_mem, >>> - base + MMIO_BASE_OFFSET + SM501_DC, >>> - sm501_disp_ctrl); >>> - memory_region_init_io(sm501_2d_engine, NULL, &sm501_2d_engine_ops, >>> s, >>> + memory_region_add_subregion(&s->mmio_region, SM501_DC, mr); >>> + mr = g_new(MemoryRegion, 1); >>> + memory_region_init_io(mr, OBJECT(dev), &sm501_2d_engine_ops, s, >>> "sm501-2d-engine", 0x54); >>> - memory_region_add_subregion(address_space_mem, >>> - base + MMIO_BASE_OFFSET + >>> SM501_2D_ENGINE, >>> - sm501_2d_engine); >>> + memory_region_add_subregion(&s->mmio_region, SM501_2D_ENGINE, mr); >>> + >>> + /* create qemu graphic console */ >>> + s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); >>> +} >>> + >>> +#define TYPE_SYSBUS_SM501 "sysbus-sm501" >>> +#define SYSBUS_SM501(obj) \ >>> + OBJECT_CHECK(SM501SysBusState, (obj), TYPE_SYSBUS_SM501) >>> + >>> +typedef struct { >>> + /*< private >*/ >>> + SysBusDevice parent_obj; >>> + /*< public >*/ >>> + SM501State state; >>> + uint32_t vram_size; >>> + uint32_t base; >>> + void *chr_state; >>> +} SM501SysBusState; >>> + >>> +static void sm501_realize_sysbus(DeviceState *dev, Error **errp) >>> +{ >>> + SM501SysBusState *s = SYSBUS_SM501(dev); >>> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); >>> + DeviceState *usb_dev; >>> + >>> + sm501_init(&s->state, dev, s->base, s->vram_size); >>> + sysbus_init_mmio(sbd, &s->state.local_mem_region); >>> + sysbus_init_mmio(sbd, &s->state.mmio_region); >>> >>> /* bridge to usb host emulation module */ >>> - dev = qdev_create(NULL, "sysbus-ohci"); >>> - qdev_prop_set_uint32(dev, "num-ports", 2); >>> - qdev_prop_set_uint64(dev, "dma-offset", base); >>> - qdev_init_nofail(dev); >>> - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, >>> - base + MMIO_BASE_OFFSET + SM501_USB_HOST); >>> - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); >>> + usb_dev = qdev_create(NULL, "sysbus-ohci"); >>> + qdev_prop_set_uint32(usb_dev, "num-ports", 2); >>> + qdev_prop_set_uint64(usb_dev, "dma-offset", s->base); >>> + qdev_init_nofail(usb_dev); >> >> >> Why is a display controller device creating a USB controller? >> This looks like something that should be being done by the board. >> >>> + memory_region_add_subregion(&s->state.mmio_region, SM501_USB_HOST, >>> + sysbus_mmio_get_region(SYS_BUS_DEVICE(usb_dev), >>> 0)); >>> + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev)); >>> >>> /* bridge to serial emulation module */ >>> - if (chr) { >>> - serial_mm_init(address_space_mem, >>> - base + MMIO_BASE_OFFSET + SM501_UART0, 2, >>> + if (s->chr_state) { >>> + serial_mm_init(&s->state.mmio_region, SM501_UART0, 2, >>> NULL, /* TODO : chain irq to IRL */ >>> - 115200, chr, DEVICE_NATIVE_ENDIAN); >>> + 115200, s->chr_state, DEVICE_NATIVE_ENDIAN); >>> } >>> +} >> >> >> Similarly, what's going on here with the serial? > > > The SM501/SM502 is a multimedia chip that besides a display controller also > contains some other functions (see > http://cateee.net/lkddb/web-lkddb/MFD_SM501.html) and this is what is > emulated here as these are part of the chip itself. Hmm; that's pretty ugly but I guess it's sort of like a container device that needs to contain various things inside it. >>> >>> - /* create qemu graphic console */ >>> - s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); >>> +static Property sm501_sysbus_properties[] = { >>> + DEFINE_PROP_UINT32("vram-size", SM501SysBusState, vram_size, 0), >>> + DEFINE_PROP_UINT32("base", SM501SysBusState, base, 0), >>> + DEFINE_PROP_PTR("chr-state", SM501SysBusState, chr_state), Pointer properties and properties which tell the device what address it's at are both signs that something's not quite modelled right. There may be no better way to do things right now, or then again there may be. >>> + DEFINE_PROP_END_OF_LIST(), >>> +}; >> >> >>> +static void sm501_sysbus_class_init(ObjectClass *klass, void *data) >>> +{ >>> + DeviceClass *dc = DEVICE_CLASS(klass); >>> + >>> + dc->realize = sm501_realize_sysbus; >>> + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); >>> + dc->desc = "SM501 Multimedia Companion"; >>> + dc->props = sm501_sysbus_properties; >>> +/* Note: pointer property "chr-state" may remain null, thus >>> + * no need for dc->cannot_instantiate_with_device_add_yet = true; >>> + */ >>> } >> >> >> You also need a VMState struct registered in dc->vmsd and a reset >> function registered in dc->reset. > > > Even if no migration is supported? Is there a simple example I could look at > on what should go into these? The idea is to support migration. There are examples of doing VMState structures all over the tree. You just need a structure that lists all the bits of your state data structure that contain guest-modifiable state. Reset is straightforward: it's just a function that resets the state of the device as if the system had been hard powercycled. thanks -- PMM
On Sat, 25 Feb 2017, Peter Maydell wrote: > On 24 February 2017 at 20:23, BALATON Zoltan <balaton@eik.bme.hu> wrote: >> The SM501/SM502 is a multimedia chip that besides a display controller also >> contains some other functions (see >> http://cateee.net/lkddb/web-lkddb/MFD_SM501.html) and this is what is >> emulated here as these are part of the chip itself. > > Hmm; that's pretty ugly but I guess it's sort of like a container > device that needs to contain various things inside it. > >>>> >>>> - /* create qemu graphic console */ >>>> - s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); >>>> +static Property sm501_sysbus_properties[] = { >>>> + DEFINE_PROP_UINT32("vram-size", SM501SysBusState, vram_size, 0), >>>> + DEFINE_PROP_UINT32("base", SM501SysBusState, base, 0), >>>> + DEFINE_PROP_PTR("chr-state", SM501SysBusState, chr_state), > > Pointer properties and properties which tell the device what > address it's at are both signs that something's not quite > modelled right. There may be no better way to do things right > now, or then again there may be. Maybe but I think that would not be part of this series but some other clean up separately. This series makes it a bit cleaner but does not aim to fix everything. >>>> + DEFINE_PROP_END_OF_LIST(), >>>> +}; >>> >>> >>>> +static void sm501_sysbus_class_init(ObjectClass *klass, void *data) >>>> +{ >>>> + DeviceClass *dc = DEVICE_CLASS(klass); >>>> + >>>> + dc->realize = sm501_realize_sysbus; >>>> + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); >>>> + dc->desc = "SM501 Multimedia Companion"; >>>> + dc->props = sm501_sysbus_properties; >>>> +/* Note: pointer property "chr-state" may remain null, thus >>>> + * no need for dc->cannot_instantiate_with_device_add_yet = true; >>>> + */ >>>> } >>> >>> >>> You also need a VMState struct registered in dc->vmsd and a reset >>> function registered in dc->reset. >> >> >> Even if no migration is supported? Is there a simple example I could look at >> on what should go into these? > > The idea is to support migration. There are examples of doing > VMState structures all over the tree. You just need a structure > that lists all the bits of your state data structure that > contain guest-modifiable state. > > Reset is straightforward: it's just a function that resets > the state of the device as if the system had been hard > powercycled. I've tried to add these but vmstate is only added to the PCI version because the OHCI device I've looked at also does the same, which is likely beacuse the sysbus version is only used on SH4 which does not support migration anyway. The PCI verison can be instantiated on machines that have migration support so it makes sense to do it there. I hope this is acceptable.
diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 4eb085c..b592022 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -58,8 +58,8 @@ #define SM501_DPRINTF(fmt, ...) do {} while (0) #endif - #define MMIO_BASE_OFFSET 0x3e00000 +#define MMIO_SIZE 0x200000 /* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */ @@ -464,6 +464,7 @@ typedef struct SM501State { uint32_t local_mem_size_index; uint8_t *local_mem; MemoryRegion local_mem_region; + MemoryRegion mmio_region; uint32_t last_width; uint32_t last_height; @@ -1396,20 +1397,14 @@ static const GraphicHwOps sm501_ops = { .gfx_update = sm501_update_display, }; -void sm501_init(MemoryRegion *address_space_mem, uint32_t base, - uint32_t local_mem_bytes, qemu_irq irq, Chardev *chr) +static void sm501_init(SM501State *s, DeviceState *dev, uint32_t base, + uint32_t local_mem_bytes) { - SM501State *s; - DeviceState *dev; - MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1); - MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1); - MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1); - - /* allocate management data region */ - s = g_new0(SM501State, 1); + MemoryRegion *mr; + s->base = base; s->local_mem_size_index = get_local_mem_size_index(local_mem_bytes); - SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s), + SM501_DPRINTF("sm501 local mem size=%x. index=%d\n", get_local_mem_size(s), s->local_mem_size_index); s->system_control = 0x00100000; /* 2D engine FIFO empty */ s->misc_control = SM501_MISC_IRQ_INVERT; /* assumes SH, active=low */ @@ -1417,46 +1412,102 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, s->dc_crt_control = 0x00010000; /* allocate local memory */ - memory_region_init_ram(&s->local_mem_region, NULL, "sm501.local", + memory_region_init_ram(&s->local_mem_region, OBJECT(dev), "sm501.local", local_mem_bytes, &error_fatal); vmstate_register_ram_global(&s->local_mem_region); memory_region_set_log(&s->local_mem_region, true, DIRTY_MEMORY_VGA); s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region); - memory_region_add_subregion(address_space_mem, base, &s->local_mem_region); - - /* map mmio */ - memory_region_init_io(sm501_system_config, NULL, &sm501_system_config_ops, - s, "sm501-system-config", 0x6c); - memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET, - sm501_system_config); - memory_region_init_io(sm501_disp_ctrl, NULL, &sm501_disp_ctrl_ops, s, + + /* allocate mmio */ + memory_region_init(&s->mmio_region, OBJECT(dev), "sm501.mmio", MMIO_SIZE); + mr = g_new(MemoryRegion, 1); + memory_region_init_io(mr, OBJECT(dev), &sm501_system_config_ops, s, + "sm501-system-config", 0x6c); + memory_region_add_subregion(&s->mmio_region, SM501_SYS_CONFIG, mr); + mr = g_new(MemoryRegion, 1); + memory_region_init_io(mr, OBJECT(dev), &sm501_disp_ctrl_ops, s, "sm501-disp-ctrl", 0x1000); - memory_region_add_subregion(address_space_mem, - base + MMIO_BASE_OFFSET + SM501_DC, - sm501_disp_ctrl); - memory_region_init_io(sm501_2d_engine, NULL, &sm501_2d_engine_ops, s, + memory_region_add_subregion(&s->mmio_region, SM501_DC, mr); + mr = g_new(MemoryRegion, 1); + memory_region_init_io(mr, OBJECT(dev), &sm501_2d_engine_ops, s, "sm501-2d-engine", 0x54); - memory_region_add_subregion(address_space_mem, - base + MMIO_BASE_OFFSET + SM501_2D_ENGINE, - sm501_2d_engine); + memory_region_add_subregion(&s->mmio_region, SM501_2D_ENGINE, mr); + + /* create qemu graphic console */ + s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); +} + +#define TYPE_SYSBUS_SM501 "sysbus-sm501" +#define SYSBUS_SM501(obj) \ + OBJECT_CHECK(SM501SysBusState, (obj), TYPE_SYSBUS_SM501) + +typedef struct { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + SM501State state; + uint32_t vram_size; + uint32_t base; + void *chr_state; +} SM501SysBusState; + +static void sm501_realize_sysbus(DeviceState *dev, Error **errp) +{ + SM501SysBusState *s = SYSBUS_SM501(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + DeviceState *usb_dev; + + sm501_init(&s->state, dev, s->base, s->vram_size); + sysbus_init_mmio(sbd, &s->state.local_mem_region); + sysbus_init_mmio(sbd, &s->state.mmio_region); /* bridge to usb host emulation module */ - dev = qdev_create(NULL, "sysbus-ohci"); - qdev_prop_set_uint32(dev, "num-ports", 2); - qdev_prop_set_uint64(dev, "dma-offset", base); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, - base + MMIO_BASE_OFFSET + SM501_USB_HOST); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); + usb_dev = qdev_create(NULL, "sysbus-ohci"); + qdev_prop_set_uint32(usb_dev, "num-ports", 2); + qdev_prop_set_uint64(usb_dev, "dma-offset", s->base); + qdev_init_nofail(usb_dev); + memory_region_add_subregion(&s->state.mmio_region, SM501_USB_HOST, + sysbus_mmio_get_region(SYS_BUS_DEVICE(usb_dev), 0)); + sysbus_pass_irq(sbd, SYS_BUS_DEVICE(usb_dev)); /* bridge to serial emulation module */ - if (chr) { - serial_mm_init(address_space_mem, - base + MMIO_BASE_OFFSET + SM501_UART0, 2, + if (s->chr_state) { + serial_mm_init(&s->state.mmio_region, SM501_UART0, 2, NULL, /* TODO : chain irq to IRL */ - 115200, chr, DEVICE_NATIVE_ENDIAN); + 115200, s->chr_state, DEVICE_NATIVE_ENDIAN); } +} - /* create qemu graphic console */ - s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); +static Property sm501_sysbus_properties[] = { + DEFINE_PROP_UINT32("vram-size", SM501SysBusState, vram_size, 0), + DEFINE_PROP_UINT32("base", SM501SysBusState, base, 0), + DEFINE_PROP_PTR("chr-state", SM501SysBusState, chr_state), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sm501_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sm501_realize_sysbus; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); + dc->desc = "SM501 Multimedia Companion"; + dc->props = sm501_sysbus_properties; +/* Note: pointer property "chr-state" may remain null, thus + * no need for dc->cannot_instantiate_with_device_add_yet = true; + */ } + +static const TypeInfo sm501_sysbus_info = { + .name = TYPE_SYSBUS_SM501, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SM501SysBusState), + .class_init = sm501_sysbus_class_init, +}; + +static void sm501_register_types(void) +{ + type_register_static(&sm501_sysbus_info); +} + +type_init(sm501_register_types) diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c index db373c7..adc41b6 100644 --- a/hw/sh4/r2d.c +++ b/hw/sh4/r2d.c @@ -277,8 +277,15 @@ static void r2d_init(MachineState *machine) sysbus_connect_irq(busdev, 2, irq[PCI_INTC]); sysbus_connect_irq(busdev, 3, irq[PCI_INTD]); - sm501_init(address_space_mem, 0x10000000, SM501_VRAM_SIZE, - irq[SM501], serial_hds[2]); + dev = qdev_create(NULL, "sysbus-sm501"); + busdev = SYS_BUS_DEVICE(dev); + qdev_prop_set_uint32(dev, "vram-size", SM501_VRAM_SIZE); + qdev_prop_set_uint32(dev, "base", 0x10000000); + qdev_prop_set_ptr(dev, "chr-state", serial_hds[2]); + qdev_init_nofail(dev); + sysbus_mmio_map(busdev, 0, 0x10000000); + sysbus_mmio_map(busdev, 1, 0x13e00000); + sysbus_connect_irq(busdev, 0, irq[SM501]); /* onboard CF (True IDE mode, Master only). */ dinfo = drive_get(IF_IDE, 0, 0); diff --git a/include/hw/devices.h b/include/hw/devices.h index 7475b71..861ddea 100644 --- a/include/hw/devices.h +++ b/include/hw/devices.h @@ -62,9 +62,4 @@ void tc6393xb_gpio_out_set(TC6393xbState *s, int line, qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s); qemu_irq tc6393xb_l3v_get(TC6393xbState *s); -/* sm501.c */ -void sm501_init(struct MemoryRegion *address_space_mem, uint32_t base, - uint32_t local_mem_bytes, qemu_irq irq, - Chardev *chr); - #endif
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> --- hw/display/sm501.c | 133 +++++++++++++++++++++++++++++++++++---------------- hw/sh4/r2d.c | 11 ++++- include/hw/devices.h | 5 -- 3 files changed, 101 insertions(+), 48 deletions(-)