xref: /openbmc/qemu/hw/char/serial-mm.c (revision b5ab62b3c0050612c7f9b0b4baeb44ebab42775a)
1*7e6b5497SBernhard Beschow /*
2*7e6b5497SBernhard Beschow  * QEMU 16550A UART emulation
3*7e6b5497SBernhard Beschow  *
4*7e6b5497SBernhard Beschow  * Copyright (c) 2003-2004 Fabrice Bellard
5*7e6b5497SBernhard Beschow  * Copyright (c) 2008 Citrix Systems, Inc.
6*7e6b5497SBernhard Beschow  *
7*7e6b5497SBernhard Beschow  * Permission is hereby granted, free of charge, to any person obtaining a copy
8*7e6b5497SBernhard Beschow  * of this software and associated documentation files (the "Software"), to deal
9*7e6b5497SBernhard Beschow  * in the Software without restriction, including without limitation the rights
10*7e6b5497SBernhard Beschow  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11*7e6b5497SBernhard Beschow  * copies of the Software, and to permit persons to whom the Software is
12*7e6b5497SBernhard Beschow  * furnished to do so, subject to the following conditions:
13*7e6b5497SBernhard Beschow  *
14*7e6b5497SBernhard Beschow  * The above copyright notice and this permission notice shall be included in
15*7e6b5497SBernhard Beschow  * all copies or substantial portions of the Software.
16*7e6b5497SBernhard Beschow  *
17*7e6b5497SBernhard Beschow  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18*7e6b5497SBernhard Beschow  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19*7e6b5497SBernhard Beschow  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20*7e6b5497SBernhard Beschow  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21*7e6b5497SBernhard Beschow  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22*7e6b5497SBernhard Beschow  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23*7e6b5497SBernhard Beschow  * THE SOFTWARE.
24*7e6b5497SBernhard Beschow  */
25*7e6b5497SBernhard Beschow 
26*7e6b5497SBernhard Beschow #include "qemu/osdep.h"
27*7e6b5497SBernhard Beschow #include "hw/char/serial-mm.h"
28*7e6b5497SBernhard Beschow #include "exec/cpu-common.h"
29*7e6b5497SBernhard Beschow #include "migration/vmstate.h"
30*7e6b5497SBernhard Beschow #include "qapi/error.h"
31*7e6b5497SBernhard Beschow #include "hw/qdev-properties.h"
32*7e6b5497SBernhard Beschow 
serial_mm_read(void * opaque,hwaddr addr,unsigned size)33*7e6b5497SBernhard Beschow static uint64_t serial_mm_read(void *opaque, hwaddr addr, unsigned size)
34*7e6b5497SBernhard Beschow {
35*7e6b5497SBernhard Beschow     SerialMM *s = SERIAL_MM(opaque);
36*7e6b5497SBernhard Beschow     return serial_io_ops.read(&s->serial, addr >> s->regshift, 1);
37*7e6b5497SBernhard Beschow }
38*7e6b5497SBernhard Beschow 
serial_mm_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)39*7e6b5497SBernhard Beschow static void serial_mm_write(void *opaque, hwaddr addr,
40*7e6b5497SBernhard Beschow                             uint64_t value, unsigned size)
41*7e6b5497SBernhard Beschow {
42*7e6b5497SBernhard Beschow     SerialMM *s = SERIAL_MM(opaque);
43*7e6b5497SBernhard Beschow     value &= 255;
44*7e6b5497SBernhard Beschow     serial_io_ops.write(&s->serial, addr >> s->regshift, value, 1);
45*7e6b5497SBernhard Beschow }
46*7e6b5497SBernhard Beschow 
47*7e6b5497SBernhard Beschow static const MemoryRegionOps serial_mm_ops[3] = {
48*7e6b5497SBernhard Beschow     [DEVICE_NATIVE_ENDIAN] = {
49*7e6b5497SBernhard Beschow         .read = serial_mm_read,
50*7e6b5497SBernhard Beschow         .write = serial_mm_write,
51*7e6b5497SBernhard Beschow         .endianness = DEVICE_NATIVE_ENDIAN,
52*7e6b5497SBernhard Beschow         .valid.max_access_size = 8,
53*7e6b5497SBernhard Beschow         .impl.max_access_size = 8,
54*7e6b5497SBernhard Beschow     },
55*7e6b5497SBernhard Beschow     [DEVICE_LITTLE_ENDIAN] = {
56*7e6b5497SBernhard Beschow         .read = serial_mm_read,
57*7e6b5497SBernhard Beschow         .write = serial_mm_write,
58*7e6b5497SBernhard Beschow         .endianness = DEVICE_LITTLE_ENDIAN,
59*7e6b5497SBernhard Beschow         .valid.max_access_size = 8,
60*7e6b5497SBernhard Beschow         .impl.max_access_size = 8,
61*7e6b5497SBernhard Beschow     },
62*7e6b5497SBernhard Beschow     [DEVICE_BIG_ENDIAN] = {
63*7e6b5497SBernhard Beschow         .read = serial_mm_read,
64*7e6b5497SBernhard Beschow         .write = serial_mm_write,
65*7e6b5497SBernhard Beschow         .endianness = DEVICE_BIG_ENDIAN,
66*7e6b5497SBernhard Beschow         .valid.max_access_size = 8,
67*7e6b5497SBernhard Beschow         .impl.max_access_size = 8,
68*7e6b5497SBernhard Beschow     },
69*7e6b5497SBernhard Beschow };
70*7e6b5497SBernhard Beschow 
serial_mm_realize(DeviceState * dev,Error ** errp)71*7e6b5497SBernhard Beschow static void serial_mm_realize(DeviceState *dev, Error **errp)
72*7e6b5497SBernhard Beschow {
73*7e6b5497SBernhard Beschow     SerialMM *smm = SERIAL_MM(dev);
74*7e6b5497SBernhard Beschow     SerialState *s = &smm->serial;
75*7e6b5497SBernhard Beschow 
76*7e6b5497SBernhard Beschow     if (!qdev_realize(DEVICE(s), NULL, errp)) {
77*7e6b5497SBernhard Beschow         return;
78*7e6b5497SBernhard Beschow     }
79*7e6b5497SBernhard Beschow 
80*7e6b5497SBernhard Beschow     memory_region_init_io(&s->io, OBJECT(dev),
81*7e6b5497SBernhard Beschow                           &serial_mm_ops[smm->endianness], smm, "serial",
82*7e6b5497SBernhard Beschow                           8 << smm->regshift);
83*7e6b5497SBernhard Beschow     sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
84*7e6b5497SBernhard Beschow     sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
85*7e6b5497SBernhard Beschow }
86*7e6b5497SBernhard Beschow 
87*7e6b5497SBernhard Beschow static const VMStateDescription vmstate_serial_mm = {
88*7e6b5497SBernhard Beschow     .name = "serial",
89*7e6b5497SBernhard Beschow     .version_id = 3,
90*7e6b5497SBernhard Beschow     .minimum_version_id = 2,
91*7e6b5497SBernhard Beschow     .fields = (const VMStateField[]) {
92*7e6b5497SBernhard Beschow         VMSTATE_STRUCT(serial, SerialMM, 0, vmstate_serial, SerialState),
93*7e6b5497SBernhard Beschow         VMSTATE_END_OF_LIST()
94*7e6b5497SBernhard Beschow     }
95*7e6b5497SBernhard Beschow };
96*7e6b5497SBernhard Beschow 
serial_mm_init(MemoryRegion * address_space,hwaddr base,int regshift,qemu_irq irq,int baudbase,Chardev * chr,enum device_endian end)97*7e6b5497SBernhard Beschow SerialMM *serial_mm_init(MemoryRegion *address_space,
98*7e6b5497SBernhard Beschow                          hwaddr base, int regshift,
99*7e6b5497SBernhard Beschow                          qemu_irq irq, int baudbase,
100*7e6b5497SBernhard Beschow                          Chardev *chr, enum device_endian end)
101*7e6b5497SBernhard Beschow {
102*7e6b5497SBernhard Beschow     SerialMM *smm = SERIAL_MM(qdev_new(TYPE_SERIAL_MM));
103*7e6b5497SBernhard Beschow     MemoryRegion *mr;
104*7e6b5497SBernhard Beschow 
105*7e6b5497SBernhard Beschow     qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift);
106*7e6b5497SBernhard Beschow     qdev_prop_set_uint32(DEVICE(smm), "baudbase", baudbase);
107*7e6b5497SBernhard Beschow     qdev_prop_set_chr(DEVICE(smm), "chardev", chr);
108*7e6b5497SBernhard Beschow     qdev_set_legacy_instance_id(DEVICE(smm), base, 2);
109*7e6b5497SBernhard Beschow     qdev_prop_set_uint8(DEVICE(smm), "endianness", end);
110*7e6b5497SBernhard Beschow     sysbus_realize_and_unref(SYS_BUS_DEVICE(smm), &error_fatal);
111*7e6b5497SBernhard Beschow 
112*7e6b5497SBernhard Beschow     sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq);
113*7e6b5497SBernhard Beschow     mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0);
114*7e6b5497SBernhard Beschow     memory_region_add_subregion(address_space, base, mr);
115*7e6b5497SBernhard Beschow 
116*7e6b5497SBernhard Beschow     return smm;
117*7e6b5497SBernhard Beschow }
118*7e6b5497SBernhard Beschow 
serial_mm_instance_init(Object * o)119*7e6b5497SBernhard Beschow static void serial_mm_instance_init(Object *o)
120*7e6b5497SBernhard Beschow {
121*7e6b5497SBernhard Beschow     SerialMM *smm = SERIAL_MM(o);
122*7e6b5497SBernhard Beschow 
123*7e6b5497SBernhard Beschow     object_initialize_child(o, "serial", &smm->serial, TYPE_SERIAL);
124*7e6b5497SBernhard Beschow 
125*7e6b5497SBernhard Beschow     qdev_alias_all_properties(DEVICE(&smm->serial), o);
126*7e6b5497SBernhard Beschow }
127*7e6b5497SBernhard Beschow 
128*7e6b5497SBernhard Beschow static Property serial_mm_properties[] = {
129*7e6b5497SBernhard Beschow     /*
130*7e6b5497SBernhard Beschow      * Set the spacing between adjacent memory-mapped UART registers.
131*7e6b5497SBernhard Beschow      * Each register will be at (1 << regshift) bytes after the previous one.
132*7e6b5497SBernhard Beschow      */
133*7e6b5497SBernhard Beschow     DEFINE_PROP_UINT8("regshift", SerialMM, regshift, 0),
134*7e6b5497SBernhard Beschow     DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN),
135*7e6b5497SBernhard Beschow     DEFINE_PROP_END_OF_LIST(),
136*7e6b5497SBernhard Beschow };
137*7e6b5497SBernhard Beschow 
serial_mm_class_init(ObjectClass * oc,void * data)138*7e6b5497SBernhard Beschow static void serial_mm_class_init(ObjectClass *oc, void *data)
139*7e6b5497SBernhard Beschow {
140*7e6b5497SBernhard Beschow     DeviceClass *dc = DEVICE_CLASS(oc);
141*7e6b5497SBernhard Beschow 
142*7e6b5497SBernhard Beschow     device_class_set_props(dc, serial_mm_properties);
143*7e6b5497SBernhard Beschow     dc->realize = serial_mm_realize;
144*7e6b5497SBernhard Beschow     dc->vmsd = &vmstate_serial_mm;
145*7e6b5497SBernhard Beschow }
146*7e6b5497SBernhard Beschow 
147*7e6b5497SBernhard Beschow static const TypeInfo types[] = {
148*7e6b5497SBernhard Beschow     {
149*7e6b5497SBernhard Beschow         .name = TYPE_SERIAL_MM,
150*7e6b5497SBernhard Beschow         .parent = TYPE_SYS_BUS_DEVICE,
151*7e6b5497SBernhard Beschow         .class_init = serial_mm_class_init,
152*7e6b5497SBernhard Beschow         .instance_init = serial_mm_instance_init,
153*7e6b5497SBernhard Beschow         .instance_size = sizeof(SerialMM),
154*7e6b5497SBernhard Beschow     },
155*7e6b5497SBernhard Beschow };
156*7e6b5497SBernhard Beschow 
157*7e6b5497SBernhard Beschow DEFINE_TYPES(types)
158