target-arm queue:

* fsl-imx6: Fix incorrect Ethernet interrupt defines
  * dump: Update correct kdump phys_base field for AArch64
  * char: i.MX: Add support for "TX complete" interrupt
  * bcm2836/raspi: Fix various bugs resulting in panics trying
    to boot a Debian Linux kernel on raspi3
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJasAHJAAoJEDwlJe0UNgzew+AP+gK+v7Dmoql+8uOipAfZYPSA
 C6MjjvB+pJ8mj8GC9o8Kz8AOotw+GTC3sBW0Iktxx3GsGg7uCSN2fpUevzBkgUps
 ZMv74HDgPHc2Q5HO07+0ihNcEZvVmnq4XnozYmEm4BkiCCpyzFyMUhow9qF3xBLB
 QVFBdgz5lGljVw+b6o4szyxCePMST9K4Q1ZNHe70Yy2eKzEKgYXPJqt7M+Q4tEM8
 fBPlphqttANxFnSXxzZzleWwNHkUDsEtGUu6Qcamh+6AHkMcyzrpiOFEy5a+Lz3t
 YDhUE5uzkPpHqXgzYFwQrPafaZQNb/aID1buTr2dHepOcGdgu0J0IqxuPrSehsw5
 DlmIVMGN1rXvdHnQUpfR2apWJrKYA65mQVGKyAVGDBJrWAN4l7cDSvv7hdEs4Q7h
 a5zmxsWq5hoiVCI4gYnw1OWnzsBw1t8DDWAzdx8GdmtOyG47eMc6zG/NFz4IPu4I
 NPitFU6jxZ5/MEGtGaVYuvWLVokAbLBZH1Py7wdMkDiYDftzVzc6pU8FVh8BnpJi
 x271ZszalM+IhZNBRVnyrFHv+jXcAo/uoApdQBn4D8RHII0U+TJnf9EJHeDataJP
 QUuXTjsP8LeDvcrHpTANp36ljLu424wXWhMzE+zVNTauFJxpoyNnjv6rCSOShjv6
 n5zR7rzfpDJ2cMbs86cz
 =eWl1
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180319' into staging

target-arm queue:
 * fsl-imx6: Fix incorrect Ethernet interrupt defines
 * dump: Update correct kdump phys_base field for AArch64
 * char: i.MX: Add support for "TX complete" interrupt
 * bcm2836/raspi: Fix various bugs resulting in panics trying
   to boot a Debian Linux kernel on raspi3

# gpg: Signature made Mon 19 Mar 2018 18:30:33 GMT
# gpg:                using RSA key 3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20180319:
  hw/arm/raspi: Provide spin-loop code for AArch64 CPUs
  hw/arm/bcm2836: Hardcode correct CPU type
  hw/arm/bcm2836: Use correct affinity values for BCM2837
  hw/arm/bcm2836: Create proper bcm2837 device
  hw/arm/bcm2836: Rename bcm2836 type/struct to bcm283x
  hw/arm/bcm2386: Fix parent type of bcm2386
  hw/arm/boot: If booting a kernel in EL2, set SCR_EL3.HCE
  hw/arm/boot: assert that secure_boot and secure_board_setup are false for AArch64
  hw/arm/raspi: Don't do board-setup or secure-boot for raspi3
  char: i.MX: Add support for "TX complete" interrupt
  char: i.MX: Simplify imx_update()
  dump: Update correct kdump phys_base field for AArch64
  fsl-imx6: Swap Ethernet interrupt defines

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-03-19 19:20:45 +00:00
commit c26ef39204
9 changed files with 237 additions and 63 deletions

14
dump.c
View File

@ -1609,10 +1609,18 @@ static void vmcoreinfo_update_phys_base(DumpState *s)
lines = g_strsplit((char *)vmci, "\n", -1);
for (i = 0; lines[i]; i++) {
if (g_str_has_prefix(lines[i], "NUMBER(phys_base)=")) {
if (qemu_strtou64(lines[i] + 18, NULL, 16,
const char *prefix = NULL;
if (s->dump_info.d_machine == EM_X86_64) {
prefix = "NUMBER(phys_base)=";
} else if (s->dump_info.d_machine == EM_AARCH64) {
prefix = "NUMBER(PHYS_OFFSET)=";
}
if (prefix && g_str_has_prefix(lines[i], prefix)) {
if (qemu_strtou64(lines[i] + strlen(prefix), NULL, 16,
&phys_base) < 0) {
warn_report("Failed to read NUMBER(phys_base)=");
warn_report("Failed to read %s", prefix);
} else {
s->dump_info.phys_base = phys_base;
}

View File

@ -23,9 +23,40 @@
/* "QA7" (Pi2) interrupt controller and mailboxes etc. */
#define BCM2836_CONTROL_BASE 0x40000000
struct BCM283XInfo {
const char *name;
const char *cpu_type;
int clusterid;
};
static const BCM283XInfo bcm283x_socs[] = {
{
.name = TYPE_BCM2836,
.cpu_type = ARM_CPU_TYPE_NAME("cortex-a15"),
.clusterid = 0xf,
},
#ifdef TARGET_AARCH64
{
.name = TYPE_BCM2837,
.cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
.clusterid = 0x0,
},
#endif
};
static void bcm2836_init(Object *obj)
{
BCM2836State *s = BCM2836(obj);
BCM283XState *s = BCM283X(obj);
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
const BCM283XInfo *info = bc->info;
int n;
for (n = 0; n < BCM283X_NCPUS; n++) {
object_initialize(&s->cpus[n], sizeof(s->cpus[n]),
info->cpu_type);
object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]),
&error_abort);
}
object_initialize(&s->control, sizeof(s->control), TYPE_BCM2836_CONTROL);
object_property_add_child(obj, "control", OBJECT(&s->control), NULL);
@ -44,21 +75,15 @@ static void bcm2836_init(Object *obj)
static void bcm2836_realize(DeviceState *dev, Error **errp)
{
BCM2836State *s = BCM2836(dev);
BCM283XState *s = BCM283X(dev);
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
const BCM283XInfo *info = bc->info;
Object *obj;
Error *err = NULL;
int n;
/* common peripherals from bcm2835 */
obj = OBJECT(dev);
for (n = 0; n < BCM2836_NCPUS; n++) {
object_initialize(&s->cpus[n], sizeof(s->cpus[n]),
s->cpu_type);
object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpus[n]),
&error_abort);
}
obj = object_property_get_link(OBJECT(dev), "ram", &err);
if (obj == NULL) {
error_setg(errp, "%s: required ram link not found: %s",
@ -102,11 +127,9 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-fiq", 0));
for (n = 0; n < BCM2836_NCPUS; n++) {
/* Mirror bcm2836, which has clusterid set to 0xf
* TODO: this should be converted to a property of ARM_CPU
*/
s->cpus[n].mp_affinity = 0xF00 | n;
for (n = 0; n < BCM283X_NCPUS; n++) {
/* TODO: this should be converted to a property of ARM_CPU */
s->cpus[n].mp_affinity = (info->clusterid << 8) | n;
/* set periphbase/CBAR value for CPU-local registers */
object_property_set_int(OBJECT(&s->cpus[n]),
@ -150,30 +173,44 @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
}
static Property bcm2836_props[] = {
DEFINE_PROP_STRING("cpu-type", BCM2836State, cpu_type),
DEFINE_PROP_UINT32("enabled-cpus", BCM2836State, enabled_cpus, BCM2836_NCPUS),
DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
BCM283X_NCPUS),
DEFINE_PROP_END_OF_LIST()
};
static void bcm2836_class_init(ObjectClass *oc, void *data)
static void bcm283x_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
BCM283XClass *bc = BCM283X_CLASS(oc);
dc->props = bcm2836_props;
bc->info = data;
dc->realize = bcm2836_realize;
dc->props = bcm2836_props;
}
static const TypeInfo bcm2836_type_info = {
.name = TYPE_BCM2836,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(BCM2836State),
static const TypeInfo bcm283x_type_info = {
.name = TYPE_BCM283X,
.parent = TYPE_DEVICE,
.instance_size = sizeof(BCM283XState),
.instance_init = bcm2836_init,
.class_init = bcm2836_class_init,
.class_size = sizeof(BCM283XClass),
.abstract = true,
};
static void bcm2836_register_types(void)
{
type_register_static(&bcm2836_type_info);
int i;
type_register_static(&bcm283x_type_info);
for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) {
TypeInfo ti = {
.name = bcm283x_socs[i].name,
.parent = TYPE_BCM283X,
.class_init = bcm283x_class_init,
.class_data = (void *) &bcm283x_socs[i],
};
type_register(&ti);
}
}
type_init(bcm2836_register_types)

View File

@ -720,6 +720,18 @@ static void do_cpu_reset(void *opaque)
} else {
env->pstate = PSTATE_MODE_EL1h;
}
/* AArch64 kernels never boot in secure mode */
assert(!info->secure_boot);
/* This hook is only supported for AArch32 currently:
* bootloader_aarch64[] will not call the hook, and
* the code above has already dropped us into EL2 or EL1.
*/
assert(!info->secure_board_setup);
}
if (arm_feature(env, ARM_FEATURE_EL2)) {
/* If we have EL2 then Linux expects the HVC insn to work */
env->cp15.scr_el3 |= SCR_HCE;
}
/* Set to non-secure if not a secure boot */

View File

@ -27,12 +27,13 @@
#define BOARDSETUP_ADDR (MVBAR_ADDR + 0x20) /* board setup code */
#define FIRMWARE_ADDR_2 0x8000 /* Pi 2 loads kernel.img here by default */
#define FIRMWARE_ADDR_3 0x80000 /* Pi 3 loads kernel.img here by default */
#define SPINTABLE_ADDR 0xd8 /* Pi 3 bootloader spintable */
/* Table of Linux board IDs for different Pi versions */
static const int raspi_boardid[] = {[1] = 0xc42, [2] = 0xc43, [3] = 0xc44};
typedef struct RasPiState {
BCM2836State soc;
BCM283XState soc;
MemoryRegion ram;
} RasPiState;
@ -63,6 +64,40 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
info->smp_loader_start);
}
static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
{
/* Unlike the AArch32 version we don't need to call the board setup hook.
* The mechanism for doing the spin-table is also entirely different.
* We must have four 64-bit fields at absolute addresses
* 0xd8, 0xe0, 0xe8, 0xf0 in RAM, which are the flag variables for
* our CPUs, and which we must ensure are zero initialized before
* the primary CPU goes into the kernel. We put these variables inside
* a rom blob, so that the reset for ROM contents zeroes them for us.
*/
static const uint32_t smpboot[] = {
0xd2801b05, /* mov x5, 0xd8 */
0xd53800a6, /* mrs x6, mpidr_el1 */
0x924004c6, /* and x6, x6, #0x3 */
0xd503205f, /* spin: wfe */
0xf86678a4, /* ldr x4, [x5,x6,lsl #3] */
0xb4ffffc4, /* cbz x4, spin */
0xd2800000, /* mov x0, #0x0 */
0xd2800001, /* mov x1, #0x0 */
0xd2800002, /* mov x2, #0x0 */
0xd2800003, /* mov x3, #0x0 */
0xd61f0080, /* br x4 */
};
static const uint64_t spintables[] = {
0, 0, 0, 0
};
rom_add_blob_fixed("raspi_smpboot", smpboot, sizeof(smpboot),
info->smp_loader_start);
rom_add_blob_fixed("raspi_spintables", spintables, sizeof(spintables),
SPINTABLE_ADDR);
}
static void write_board_setup(ARMCPU *cpu, const struct arm_boot_info *info)
{
arm_write_secure_board_setup_dummy_smc(cpu, info, MVBAR_ADDR);
@ -82,15 +117,28 @@ static void setup_boot(MachineState *machine, int version, size_t ram_size)
binfo.board_id = raspi_boardid[version];
binfo.ram_size = ram_size;
binfo.nb_cpus = smp_cpus;
binfo.board_setup_addr = BOARDSETUP_ADDR;
binfo.write_board_setup = write_board_setup;
binfo.secure_board_setup = true;
binfo.secure_boot = true;
if (version <= 2) {
/* The rpi1 and 2 require some custom setup code to run in Secure
* mode before booting a kernel (to set up the SMC vectors so
* that we get a no-op SMC; this is used by Linux to call the
* firmware for some cache maintenance operations.
* The rpi3 doesn't need this.
*/
binfo.board_setup_addr = BOARDSETUP_ADDR;
binfo.write_board_setup = write_board_setup;
binfo.secure_board_setup = true;
binfo.secure_boot = true;
}
/* Pi2 and Pi3 requires SMP setup */
if (version >= 2) {
binfo.smp_loader_start = SMPBOOT_ADDR;
binfo.write_secondary_boot = write_smpboot;
if (version == 2) {
binfo.write_secondary_boot = write_smpboot;
} else {
binfo.write_secondary_boot = write_smpboot64;
}
binfo.secondary_cpu_reset_hook = reset_secondary;
}
@ -127,7 +175,8 @@ static void raspi_init(MachineState *machine, int version)
BusState *bus;
DeviceState *carddev;
object_initialize(&s->soc, sizeof(s->soc), TYPE_BCM2836);
object_initialize(&s->soc, sizeof(s->soc),
version == 3 ? TYPE_BCM2837 : TYPE_BCM2836);
object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc),
&error_abort);
@ -140,8 +189,6 @@ static void raspi_init(MachineState *machine, int version)
/* Setup the SOC */
object_property_add_const_link(OBJECT(&s->soc), "ram", OBJECT(&s->ram),
&error_abort);
object_property_set_str(OBJECT(&s->soc), machine->cpu_type, "cpu-type",
&error_abort);
object_property_set_int(OBJECT(&s->soc), smp_cpus, "enabled-cpus",
&error_abort);
int board_rev = version == 3 ? 0xa02082 : 0xa21041;
@ -180,9 +227,9 @@ static void raspi2_machine_init(MachineClass *mc)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
mc->max_cpus = BCM2836_NCPUS;
mc->min_cpus = BCM2836_NCPUS;
mc->default_cpus = BCM2836_NCPUS;
mc->max_cpus = BCM283X_NCPUS;
mc->min_cpus = BCM283X_NCPUS;
mc->default_cpus = BCM283X_NCPUS;
mc->default_ram_size = 1024 * 1024 * 1024;
mc->ignore_memory_transaction_failures = true;
};
@ -203,9 +250,9 @@ static void raspi3_machine_init(MachineClass *mc)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
mc->max_cpus = BCM2836_NCPUS;
mc->min_cpus = BCM2836_NCPUS;
mc->default_cpus = BCM2836_NCPUS;
mc->max_cpus = BCM283X_NCPUS;
mc->min_cpus = BCM283X_NCPUS;
mc->default_cpus = BCM283X_NCPUS;
mc->default_ram_size = 1024 * 1024 * 1024;
}
DEFINE_MACHINE("raspi3", raspi3_machine_init)

View File

@ -37,8 +37,8 @@
static const VMStateDescription vmstate_imx_serial = {
.name = TYPE_IMX_SERIAL,
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_INT32(readbuff, IMXSerialState),
VMSTATE_UINT32(usr1, IMXSerialState),
@ -50,22 +50,36 @@ static const VMStateDescription vmstate_imx_serial = {
VMSTATE_UINT32(ubmr, IMXSerialState),
VMSTATE_UINT32(ubrc, IMXSerialState),
VMSTATE_UINT32(ucr3, IMXSerialState),
VMSTATE_UINT32(ucr4, IMXSerialState),
VMSTATE_END_OF_LIST()
},
};
static void imx_update(IMXSerialState *s)
{
uint32_t flags;
uint32_t usr1;
uint32_t usr2;
uint32_t mask;
flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY);
if (s->ucr1 & UCR1_TXMPTYEN) {
flags |= (s->uts1 & UTS1_TXEMPTY);
} else {
flags &= ~USR1_TRDY;
}
/*
* Lucky for us TRDY and RRDY has the same offset in both USR1 and
* UCR1, so we can get away with something as simple as the
* following:
*/
usr1 = s->usr1 & s->ucr1 & (USR1_TRDY | USR1_RRDY);
/*
* Bits that we want in USR2 are not as conveniently laid out,
* unfortunately.
*/
mask = (s->ucr1 & UCR1_TXMPTYEN) ? USR2_TXFE : 0;
/*
* TCEN and TXDC are both bit 3
*/
mask |= s->ucr4 & UCR4_TCEN;
qemu_set_irq(s->irq, !!flags);
usr2 = s->usr2 & mask;
qemu_set_irq(s->irq, usr1 || usr2);
}
static void imx_serial_reset(IMXSerialState *s)
@ -155,6 +169,8 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset,
return s->ucr3;
case 0x23: /* UCR4 */
return s->ucr4;
case 0x29: /* BRM Incremental */
return 0x0; /* TODO */
@ -183,8 +199,10 @@ static void imx_serial_write(void *opaque, hwaddr offset,
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &ch, 1);
s->usr1 &= ~USR1_TRDY;
s->usr2 &= ~USR2_TXDC;
imx_update(s);
s->usr1 |= USR1_TRDY;
s->usr2 |= USR2_TXDC;
imx_update(s);
}
break;
@ -257,8 +275,12 @@ static void imx_serial_write(void *opaque, hwaddr offset,
s->ucr3 = value & 0xffff;
break;
case 0x2d: /* UTS1 */
case 0x23: /* UCR4 */
s->ucr4 = value & 0xffff;
imx_update(s);
break;
case 0x2d: /* UTS1 */
qemu_log_mask(LOG_UNIMP, "[%s]%s: Unimplemented reg 0x%"
HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
/* TODO */

View File

@ -417,7 +417,33 @@ static void imx_enet_write_bd(IMXENETBufDesc *bd, dma_addr_t addr)
static void imx_eth_update(IMXFECState *s)
{
if (s->regs[ENET_EIR] & s->regs[ENET_EIMR] & ENET_INT_TS_TIMER) {
/*
* Previous versions of qemu had the ENET_INT_MAC and ENET_INT_TS_TIMER
* interrupts swapped. This worked with older versions of Linux (4.14
* and older) since Linux associated both interrupt lines with Ethernet
* MAC interrupts. Specifically,
* - Linux 4.15 and later have separate interrupt handlers for the MAC and
* timer interrupts. Those versions of Linux fail with versions of QEMU
* with swapped interrupt assignments.
* - In linux 4.14, both interrupt lines were registered with the Ethernet
* MAC interrupt handler. As a result, all versions of qemu happen to
* work, though that is accidental.
* - In Linux 4.9 and older, the timer interrupt was registered directly
* with the Ethernet MAC interrupt handler. The MAC interrupt was
* redirected to a GPIO interrupt to work around erratum ERR006687.
* This was implemented using the SOC's IOMUX block. In qemu, this GPIO
* interrupt never fired since IOMUX is currently not supported in qemu.
* Linux instead received MAC interrupts on the timer interrupt.
* As a result, qemu versions with the swapped interrupt assignment work,
* albeit accidentally, but qemu versions with the correct interrupt
* assignment fail.
*
* To ensure that all versions of Linux work, generate ENET_INT_MAC
* interrrupts on both interrupt lines. This should be changed if and when
* qemu supports IOMUX.
*/
if (s->regs[ENET_EIR] & s->regs[ENET_EIMR] &
(ENET_INT_MAC | ENET_INT_TS_TIMER)) {
qemu_set_irq(s->irq[1], 1);
} else {
qemu_set_irq(s->irq[1], 0);

View File

@ -15,12 +15,19 @@
#include "hw/arm/bcm2835_peripherals.h"
#include "hw/intc/bcm2836_control.h"
#define TYPE_BCM283X "bcm283x"
#define BCM283X(obj) OBJECT_CHECK(BCM283XState, (obj), TYPE_BCM283X)
#define BCM283X_NCPUS 4
/* These type names are for specific SoCs; other than instantiating
* them, code using these devices should always handle them via the
* BCM283x base class, so they have no BCM2836(obj) etc macros.
*/
#define TYPE_BCM2836 "bcm2836"
#define BCM2836(obj) OBJECT_CHECK(BCM2836State, (obj), TYPE_BCM2836)
#define TYPE_BCM2837 "bcm2837"
#define BCM2836_NCPUS 4
typedef struct BCM2836State {
typedef struct BCM283XState {
/*< private >*/
DeviceState parent_obj;
/*< public >*/
@ -28,9 +35,21 @@ typedef struct BCM2836State {
char *cpu_type;
uint32_t enabled_cpus;
ARMCPU cpus[BCM2836_NCPUS];
ARMCPU cpus[BCM283X_NCPUS];
BCM2836ControlState control;
BCM2835PeripheralState peripherals;
} BCM2836State;
} BCM283XState;
typedef struct BCM283XInfo BCM283XInfo;
typedef struct BCM283XClass {
DeviceClass parent_class;
const BCM283XInfo *info;
} BCM283XClass;
#define BCM283X_CLASS(klass) \
OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
#define BCM283X_GET_CLASS(obj) \
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
#endif /* BCM2836_H */

View File

@ -438,8 +438,8 @@ typedef struct FslIMX6State {
#define FSL_IMX6_HDMI_MASTER_IRQ 115
#define FSL_IMX6_HDMI_CEC_IRQ 116
#define FSL_IMX6_MLB150_LOW_IRQ 117
#define FSL_IMX6_ENET_MAC_1588_IRQ 118
#define FSL_IMX6_ENET_MAC_IRQ 119
#define FSL_IMX6_ENET_MAC_IRQ 118
#define FSL_IMX6_ENET_MAC_1588_IRQ 119
#define FSL_IMX6_PCIE1_IRQ 120
#define FSL_IMX6_PCIE2_IRQ 121
#define FSL_IMX6_PCIE3_IRQ 122

View File

@ -67,6 +67,8 @@
#define UCR2_RXEN (1<<1) /* Receiver enable */
#define UCR2_SRST (1<<0) /* Reset complete */
#define UCR4_TCEN BIT(3) /* TX complete interrupt enable */
#define UTS1_TXEMPTY (1<<6)
#define UTS1_RXEMPTY (1<<5)
#define UTS1_TXFULL (1<<4)
@ -95,6 +97,7 @@ typedef struct IMXSerialState {
uint32_t ubmr;
uint32_t ubrc;
uint32_t ucr3;
uint32_t ucr4;
qemu_irq irq;
CharBackend chr;