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>
This commit is contained in:
Cédric Le Goater 2019-03-07 23:35:37 +01:00 committed by David Gibson
parent 6f89f48e56
commit 82514be28b
3 changed files with 77 additions and 25 deletions

View File

@ -794,7 +794,7 @@ static void pnv_chip_power8_instance_init(Object *obj)
OBJECT(qdev_get_machine()), &error_abort);
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(&chip8->psi), &error_abort);

View File

@ -245,6 +245,7 @@ static const MemoryRegionOps pnv_lpc_xscom_ops = {
static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
{
bool lpc_to_opb_irq = false;
PnvLpcClass *plc = PNV_LPC_GET_CLASS(lpc);
/* Update LPC controller to OPB line */
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;
/* 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)
@ -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)
{
PnvLpcController *lpc = PNV_LPC(dev);
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 */
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);
memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR,
&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)
{
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->desc = "PowerNV LPC Controller";
}
static const TypeInfo pnv_lpc_info = {
.name = TYPE_PNV_LPC,
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvLpcController),
.class_init = pnv_lpc_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_PNV_XSCOM_INTERFACE },
{ }
}
.class_size = sizeof(PnvLpcClass),
.abstract = true,
};
static void pnv_lpc_register_types(void)
{
type_register_static(&pnv_lpc_info);
type_register_static(&pnv_lpc_power8_info);
}
type_init(pnv_lpc_register_types)

View File

@ -24,6 +24,8 @@
#define TYPE_PNV_LPC "pnv-lpc"
#define PNV_LPC(obj) \
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 {
DeviceState parent;
@ -70,6 +72,19 @@ typedef struct PnvLpcController {
PnvPsi *psi;
} 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);
#endif /* _PPC_PNV_LPC_H */