Browse Source
Add minimal code needed to allow upstream Linux guest to boot. Cc: Peter Maydell <peter.maydell@linaro.org> Cc: Jason Wang <jasowang@redhat.com> Cc: Philippe Mathieu-Daudé <f4bug@amsat.org> Cc: Marcel Apfelbaum <marcel.apfelbaum@zoho.com> Cc: Michael S. Tsirkin <mst@redhat.com> Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>pull/66/head
committed by
Peter Maydell
3 changed files with 148 additions and 1 deletions
@ -0,0 +1,125 @@ |
|||
/*
|
|||
* Copyright (c) 2018, Impinj, Inc. |
|||
* |
|||
* i.MX7 GPCv2 block emulation code |
|||
* |
|||
* Author: Andrey Smirnov <andrew.smirnov@gmail.com> |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "hw/intc/imx_gpcv2.h" |
|||
#include "qemu/log.h" |
|||
|
|||
#define GPC_PU_PGC_SW_PUP_REQ 0x0f8 |
|||
#define GPC_PU_PGC_SW_PDN_REQ 0x104 |
|||
|
|||
#define USB_HSIC_PHY_SW_Pxx_REQ BIT(4) |
|||
#define USB_OTG2_PHY_SW_Pxx_REQ BIT(3) |
|||
#define USB_OTG1_PHY_SW_Pxx_REQ BIT(2) |
|||
#define PCIE_PHY_SW_Pxx_REQ BIT(1) |
|||
#define MIPI_PHY_SW_Pxx_REQ BIT(0) |
|||
|
|||
|
|||
static void imx_gpcv2_reset(DeviceState *dev) |
|||
{ |
|||
IMXGPCv2State *s = IMX_GPCV2(dev); |
|||
|
|||
memset(s->regs, 0, sizeof(s->regs)); |
|||
} |
|||
|
|||
static uint64_t imx_gpcv2_read(void *opaque, hwaddr offset, |
|||
unsigned size) |
|||
{ |
|||
IMXGPCv2State *s = opaque; |
|||
|
|||
return s->regs[offset / sizeof(uint32_t)]; |
|||
} |
|||
|
|||
static void imx_gpcv2_write(void *opaque, hwaddr offset, |
|||
uint64_t value, unsigned size) |
|||
{ |
|||
IMXGPCv2State *s = opaque; |
|||
const size_t idx = offset / sizeof(uint32_t); |
|||
|
|||
s->regs[idx] = value; |
|||
|
|||
/*
|
|||
* Real HW will clear those bits once as a way to indicate that |
|||
* power up request is complete |
|||
*/ |
|||
if (offset == GPC_PU_PGC_SW_PUP_REQ || |
|||
offset == GPC_PU_PGC_SW_PDN_REQ) { |
|||
s->regs[idx] &= ~(USB_HSIC_PHY_SW_Pxx_REQ | |
|||
USB_OTG2_PHY_SW_Pxx_REQ | |
|||
USB_OTG1_PHY_SW_Pxx_REQ | |
|||
PCIE_PHY_SW_Pxx_REQ | |
|||
MIPI_PHY_SW_Pxx_REQ); |
|||
} |
|||
} |
|||
|
|||
static const struct MemoryRegionOps imx_gpcv2_ops = { |
|||
.read = imx_gpcv2_read, |
|||
.write = imx_gpcv2_write, |
|||
.endianness = DEVICE_NATIVE_ENDIAN, |
|||
.impl = { |
|||
/*
|
|||
* Our device would not work correctly if the guest was doing |
|||
* unaligned access. This might not be a limitation on the real |
|||
* device but in practice there is no reason for a guest to access |
|||
* this device unaligned. |
|||
*/ |
|||
.min_access_size = 4, |
|||
.max_access_size = 4, |
|||
.unaligned = false, |
|||
}, |
|||
}; |
|||
|
|||
static void imx_gpcv2_init(Object *obj) |
|||
{ |
|||
SysBusDevice *sd = SYS_BUS_DEVICE(obj); |
|||
IMXGPCv2State *s = IMX_GPCV2(obj); |
|||
|
|||
memory_region_init_io(&s->iomem, |
|||
obj, |
|||
&imx_gpcv2_ops, |
|||
s, |
|||
TYPE_IMX_GPCV2 ".iomem", |
|||
sizeof(s->regs)); |
|||
sysbus_init_mmio(sd, &s->iomem); |
|||
} |
|||
|
|||
static const VMStateDescription vmstate_imx_gpcv2 = { |
|||
.name = TYPE_IMX_GPCV2, |
|||
.version_id = 1, |
|||
.minimum_version_id = 1, |
|||
.fields = (VMStateField[]) { |
|||
VMSTATE_UINT32_ARRAY(regs, IMXGPCv2State, GPC_NUM), |
|||
VMSTATE_END_OF_LIST() |
|||
}, |
|||
}; |
|||
|
|||
static void imx_gpcv2_class_init(ObjectClass *klass, void *data) |
|||
{ |
|||
DeviceClass *dc = DEVICE_CLASS(klass); |
|||
|
|||
dc->reset = imx_gpcv2_reset; |
|||
dc->vmsd = &vmstate_imx_gpcv2; |
|||
dc->desc = "i.MX GPCv2 Module"; |
|||
} |
|||
|
|||
static const TypeInfo imx_gpcv2_info = { |
|||
.name = TYPE_IMX_GPCV2, |
|||
.parent = TYPE_SYS_BUS_DEVICE, |
|||
.instance_size = sizeof(IMXGPCv2State), |
|||
.instance_init = imx_gpcv2_init, |
|||
.class_init = imx_gpcv2_class_init, |
|||
}; |
|||
|
|||
static void imx_gpcv2_register_type(void) |
|||
{ |
|||
type_register_static(&imx_gpcv2_info); |
|||
} |
|||
type_init(imx_gpcv2_register_type) |
|||
@ -0,0 +1,22 @@ |
|||
#ifndef IMX_GPCV2_H |
|||
#define IMX_GPCV2_H |
|||
|
|||
#include "hw/sysbus.h" |
|||
|
|||
enum IMXGPCv2Registers { |
|||
GPC_NUM = 0xE00 / sizeof(uint32_t), |
|||
}; |
|||
|
|||
typedef struct IMXGPCv2State { |
|||
/*< private >*/ |
|||
SysBusDevice parent_obj; |
|||
|
|||
/*< public >*/ |
|||
MemoryRegion iomem; |
|||
uint32_t regs[GPC_NUM]; |
|||
} IMXGPCv2State; |
|||
|
|||
#define TYPE_IMX_GPCV2 "imx-gpcv2" |
|||
#define IMX_GPCV2(obj) OBJECT_CHECK(IMXGPCv2State, (obj), TYPE_IMX_GPCV2) |
|||
|
|||
#endif /* IMX_GPCV2_H */ |
|||
Loading…
Reference in new issue