static void pnv_lpc_realize(DeviceState *dev, Error **errp) { PnvLpcController *lpc = PNV_LPC(dev); Object *obj; Error *error = NULL; /* Reg inits */ lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B; /* Create address space and backing MR for the OPB bus */ memory_region_init(&lpc->opb_mr, OBJECT(dev), "lpc-opb", 0x100000000ull); address_space_init(&lpc->opb_as, &lpc->opb_mr, "lpc-opb"); /* Create ISA IO and Mem space regions which are the root of * the ISA bus (ie, ISA address spaces). We don't create a * separate one for FW which we alias to memory. */ memory_region_init(&lpc->isa_io, OBJECT(dev), "isa-io", ISA_IO_SIZE); memory_region_init(&lpc->isa_mem, OBJECT(dev), "isa-mem", ISA_MEM_SIZE); memory_region_init(&lpc->isa_fw, OBJECT(dev), "isa-fw", ISA_FW_SIZE); /* Create windows from the OPB space to the ISA space */ memory_region_init_alias(&lpc->opb_isa_io, OBJECT(dev), "lpc-isa-io", &lpc->isa_io, 0, LPC_IO_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_IO_OPB_ADDR, &lpc->opb_isa_io); memory_region_init_alias(&lpc->opb_isa_mem, OBJECT(dev), "lpc-isa-mem", &lpc->isa_mem, 0, LPC_MEM_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_MEM_OPB_ADDR, &lpc->opb_isa_mem); memory_region_init_alias(&lpc->opb_isa_fw, OBJECT(dev), "lpc-isa-fw", &lpc->isa_fw, 0, LPC_FW_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_FW_OPB_ADDR, &lpc->opb_isa_fw); /* Create MMIO regions for LPC HC and OPB registers */ memory_region_init_io(&lpc->opb_master_regs, OBJECT(dev), &opb_master_ops, lpc, "lpc-opb-master", LPC_OPB_REGS_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_OPB_REGS_OPB_ADDR, &lpc->opb_master_regs); memory_region_init_io(&lpc->lpc_hc_regs, OBJECT(dev), &lpc_hc_ops, lpc, "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_isa_irq_handler(void *opaque, int n, int level) { PnvLpcController *lpc = PNV_LPC(opaque); /* The Naples HW latches the 1 levels, clearing is done by SW */ if (level) { lpc->lpc_hc_irqstat |= LPC_HC_IRQ_SERIRQ0 >> n; pnv_lpc_eval_irqs(lpc); } }
/* If we don't use the built-in LPC interrupt deserializer, we need * to provide a set of qirqs for the ISA bus or things will go bad. * * Most machines using pre-Naples chips (without said deserializer) * have a CPLD that will collect the SerIRQ and shoot them as a * single level interrupt to the P8 chip. So let's setup a hook * for doing just that. */ static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level) { PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); uint32_t old_state = pnv->cpld_irqstate; PnvLpcController *lpc = PNV_LPC(opaque); if (level) { pnv->cpld_irqstate |= 1u << n; } else { pnv->cpld_irqstate &= ~(1u << n); } if (pnv->cpld_irqstate != old_state) { pnv_psi_irq_set(lpc->psi, PSIHB_IRQ_EXTERNAL, pnv->cpld_irqstate != 0); } }
static void pnv_lpc_realize(DeviceState *dev, Error **errp) { PnvLpcController *lpc = PNV_LPC(dev); /* Reg inits */ lpc->lpc_hc_fw_rd_acc_size = LPC_HC_FW_RD_4B; /* Create address space and backing MR for the OPB bus */ memory_region_init(&lpc->opb_mr, OBJECT(dev), "lpc-opb", 0x100000000ull); address_space_init(&lpc->opb_as, &lpc->opb_mr, "lpc-opb"); /* Create ISA IO and Mem space regions which are the root of * the ISA bus (ie, ISA address spaces). We don't create a * separate one for FW which we alias to memory. */ memory_region_init(&lpc->isa_io, OBJECT(dev), "isa-io", ISA_IO_SIZE); memory_region_init(&lpc->isa_mem, OBJECT(dev), "isa-mem", ISA_MEM_SIZE); /* Create windows from the OPB space to the ISA space */ memory_region_init_alias(&lpc->opb_isa_io, OBJECT(dev), "lpc-isa-io", &lpc->isa_io, 0, LPC_IO_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_IO_OPB_ADDR, &lpc->opb_isa_io); memory_region_init_alias(&lpc->opb_isa_mem, OBJECT(dev), "lpc-isa-mem", &lpc->isa_mem, 0, LPC_MEM_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_MEM_OPB_ADDR, &lpc->opb_isa_mem); memory_region_init_alias(&lpc->opb_isa_fw, OBJECT(dev), "lpc-isa-fw", &lpc->isa_mem, 0, LPC_FW_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_FW_OPB_ADDR, &lpc->opb_isa_fw); /* Create MMIO regions for LPC HC and OPB registers */ memory_region_init_io(&lpc->opb_master_regs, OBJECT(dev), &opb_master_ops, lpc, "lpc-opb-master", LPC_OPB_REGS_OPB_SIZE); memory_region_add_subregion(&lpc->opb_mr, LPC_OPB_REGS_OPB_ADDR, &lpc->opb_master_regs); memory_region_init_io(&lpc->lpc_hc_regs, OBJECT(dev), &lpc_hc_ops, lpc, "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); }
static void pnv_lpc_xscom_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { PnvLpcController *lpc = PNV_LPC(opaque); uint32_t offset = addr >> 3; switch (offset & 3) { case ECCB_CTL: pnv_lpc_do_eccb(lpc, val); break; case ECCB_RESET: /* XXXX */ break; case ECCB_STAT: break; case ECCB_DATA: lpc->eccb_data_reg = val >> 32; break; } }
static uint64_t pnv_lpc_xscom_read(void *opaque, hwaddr addr, unsigned size) { PnvLpcController *lpc = PNV_LPC(opaque); uint32_t offset = addr >> 3; uint64_t val = 0; switch (offset & 3) { case ECCB_CTL: case ECCB_RESET: val = 0; break; case ECCB_STAT: val = lpc->eccb_stat_reg; lpc->eccb_stat_reg = 0; break; case ECCB_DATA: val = ((uint64_t)lpc->eccb_data_reg) << 32; break; } return val; }