mirror of https://github.com/proxmox/mirror_qemu
ppc/pnv: add a LPC Controller class model
It will ease the introduction of the LPC Controller model for POWER9. Signed-off-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Message-Id: <20190307223548.20516-5-clg@kaod.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>master
parent
6f89f48e56
commit
82514be28b
|
@ -794,7 +794,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
|
||||||
OBJECT(qdev_get_machine()), &error_abort);
|
OBJECT(qdev_get_machine()), &error_abort);
|
||||||
|
|
||||||
object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc),
|
object_initialize_child(obj, "lpc", &chip8->lpc, sizeof(chip8->lpc),
|
||||||
TYPE_PNV_LPC, &error_abort, NULL);
|
TYPE_PNV8_LPC, &error_abort, NULL);
|
||||||
object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
|
object_property_add_const_link(OBJECT(&chip8->lpc), "psi",
|
||||||
OBJECT(&chip8->psi), &error_abort);
|
OBJECT(&chip8->psi), &error_abort);
|
||||||
|
|
||||||
|
|
|
@ -245,6 +245,7 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
|
||||||
static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
|
static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
|
||||||
{
|
{
|
||||||
bool lpc_to_opb_irq = false;
|
bool lpc_to_opb_irq = false;
|
||||||
|
PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc);
|
||||||
|
|
||||||
/* Update LPC controller to OPB line */
|
/* Update LPC controller to OPB line */
|
||||||
if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) {
|
if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) {
|
||||||
|
@ -267,7 +268,7 @@ static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
|
||||||
lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
|
lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
|
||||||
|
|
||||||
/* Reflect the interrupt */
|
/* Reflect the interrupt */
|
||||||
pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_LPC_I2C, lpc->opb_irq_stat != 0);
|
pnv_psi_irq_set(lpc->psi, plc->psi_irq, lpc->opb_irq_stat != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
|
static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
|
@ -419,11 +420,65 @@ static const MemoryRegionOps opb_master_ops = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
PnvLpcController *lpc = PNV_LPC(dev);
|
||||||
|
PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
|
||||||
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
plc->parent_realize(dev, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* P8 uses a XSCOM region for LPC registers */
|
||||||
|
pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(lpc),
|
||||||
|
&pnv_lpc_xscom_ops, lpc, "xscom-lpc",
|
||||||
|
PNV_XSCOM_LPC_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
|
||||||
|
PnvLpcClass *plc = PNV_LPC_CLASS(klass);
|
||||||
|
|
||||||
|
dc->desc = "PowerNV LPC Controller POWER8";
|
||||||
|
|
||||||
|
xdc->dt_xscom = pnv_lpc_dt_xscom;
|
||||||
|
|
||||||
|
plc->psi_irq = PSIHB_IRQ_LPC_I2C;
|
||||||
|
|
||||||
|
device_class_set_parent_realize(dc, pnv_lpc_power8_realize,
|
||||||
|
&plc->parent_realize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo pnv_lpc_power8_info = {
|
||||||
|
.name = TYPE_PNV8_LPC,
|
||||||
|
.parent = TYPE_PNV_LPC,
|
||||||
|
.instance_size = sizeof(PnvLpcController),
|
||||||
|
.class_init = pnv_lpc_power8_class_init,
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
|
{ TYPE_PNV_XSCOM_INTERFACE },
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void pnv_lpc_realize(DeviceState *dev, Error **errp)
|
static void pnv_lpc_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
PnvLpcController *lpc = PNV_LPC(dev);
|
PnvLpcController *lpc = PNV_LPC(dev);
|
||||||
Object *obj;
|
Object *obj;
|
||||||
Error *error = NULL;
|
Error *local_err = NULL;
|
||||||
|
|
||||||
|
obj = object_property_get_link(OBJECT(dev), "psi", &local_err);
|
||||||
|
if (!obj) {
|
||||||
|
error_propagate(errp, local_err);
|
||||||
|
error_prepend(errp, "required link 'psi' not found: ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* The LPC controller needs PSI to generate interrupts */
|
||||||
|
lpc->psi = PNV_PSI(obj);
|
||||||
|
|
||||||
/* Reg inits */
|
/* Reg inits */
|
||||||
lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B;
|
lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B;
|
||||||
|
@ -463,46 +518,28 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp)
|
||||||
"lpc-hc", LPC_HC_REGS_OPB_SIZE);
|
"lpc-hc", LPC_HC_REGS_OPB_SIZE);
|
||||||
memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR,
|
memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR,
|
||||||
&lpc->lpc_hc_regs);
|
&lpc->lpc_hc_regs);
|
||||||
|
|
||||||
/* XScom region for LPC registers */
|
|
||||||
pnv_xscom_region_init(&lpc->xscom_regs, OBJECT(dev),
|
|
||||||
&pnv_lpc_xscom_ops, lpc, "xscom-lpc",
|
|
||||||
PNV_XSCOM_LPC_SIZE);
|
|
||||||
|
|
||||||
/* get PSI object from chip */
|
|
||||||
obj = object_property_get_link(OBJECT(dev), "psi", &error);
|
|
||||||
if (!obj) {
|
|
||||||
error_setg(errp, "%s: required link 'psi' not found: %s",
|
|
||||||
__func__, error_get_pretty(error));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lpc->psi = PNV_PSI(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pnv_lpc_class_init(ObjectClass *klass, void *data)
|
static void pnv_lpc_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass);
|
|
||||||
|
|
||||||
xdc->dt_xscom = pnv_lpc_dt_xscom;
|
|
||||||
|
|
||||||
dc->realize = pnv_lpc_realize;
|
dc->realize = pnv_lpc_realize;
|
||||||
|
dc->desc = "PowerNV LPC Controller";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo pnv_lpc_info = {
|
static const TypeInfo pnv_lpc_info = {
|
||||||
.name = TYPE_PNV_LPC,
|
.name = TYPE_PNV_LPC,
|
||||||
.parent = TYPE_DEVICE,
|
.parent = TYPE_DEVICE,
|
||||||
.instance_size = sizeof(PnvLpcController),
|
|
||||||
.class_init = pnv_lpc_class_init,
|
.class_init = pnv_lpc_class_init,
|
||||||
.interfaces = (InterfaceInfo[]) {
|
.class_size = sizeof(PnvLpcClass),
|
||||||
{ TYPE_PNV_XSCOM_INTERFACE },
|
.abstract = true,
|
||||||
{ }
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pnv_lpc_register_types(void)
|
static void pnv_lpc_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&pnv_lpc_info);
|
type_register_static(&pnv_lpc_info);
|
||||||
|
type_register_static(&pnv_lpc_power8_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(pnv_lpc_register_types)
|
type_init(pnv_lpc_register_types)
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#define TYPE_PNV_LPC "pnv-lpc"
|
#define TYPE_PNV_LPC "pnv-lpc"
|
||||||
#define PNV_LPC(obj) \
|
#define PNV_LPC(obj) \
|
||||||
OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC)
|
OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV_LPC)
|
||||||
|
#define TYPE_PNV8_LPC TYPE_PNV_LPC "-POWER8"
|
||||||
|
#define PNV8_LPC(obj) OBJECT_CHECK(PnvLpcController, (obj), TYPE_PNV8_LPC)
|
||||||
|
|
||||||
typedef struct PnvLpcController {
|
typedef struct PnvLpcController {
|
||||||
DeviceState parent;
|
DeviceState parent;
|
||||||
|
@ -70,6 +72,19 @@ typedef struct PnvLpcController {
|
||||||
PnvPsi *psi;
|
PnvPsi *psi;
|
||||||
} PnvLpcController;
|
} PnvLpcController;
|
||||||
|
|
||||||
|
#define PNV_LPC_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(PnvLpcClass, (klass), TYPE_PNV_LPC)
|
||||||
|
#define PNV_LPC_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(PnvLpcClass, (obj), TYPE_PNV_LPC)
|
||||||
|
|
||||||
|
typedef struct PnvLpcClass {
|
||||||
|
DeviceClass parent_class;
|
||||||
|
|
||||||
|
int psi_irq;
|
||||||
|
|
||||||
|
DeviceRealize parent_realize;
|
||||||
|
} PnvLpcClass;
|
||||||
|
|
||||||
ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
|
ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
|
||||||
|
|
||||||
#endif /* _PPC_PNV_LPC_H */
|
#endif /* _PPC_PNV_LPC_H */
|
||||||
|
|
Loading…
Reference in New Issue