hw/fsi: Introduce IBM's FSI master
This is a part of patchset where IBM's Flexible Service Interface is introduced. This commit models the FSI master. CFAM is hanging out of FSI master which is a bus controller. The FSI master: A controller in the platform service processor (e.g. BMC) driving CFAM engine accesses into the POWER chip. At the hardware level FSI is a bit-based protocol supporting synchronous and DMA-driven accesses of engines in a CFAM. Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Signed-off-by: Ninad Palsule <ninad@linux.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> [ clg: - move FSICFAMState object under FSIMasterState - introduced fsi_master_init() - reworked fsi_master_realize() - dropped FSIBus definition ] Signed-off-by: Cédric Le Goater <clg@kaod.org>
This commit is contained in:
parent
f32f8e4d20
commit
ca03310737
170
hw/fsi/fsi-master.c
Normal file
170
hw/fsi/fsi-master.c
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright (C) 2024 IBM Corp.
|
||||
*
|
||||
* IBM Flexible Service Interface master
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include "hw/fsi/fsi-master.h"
|
||||
|
||||
#define TYPE_OP_BUS "opb"
|
||||
|
||||
#define TO_REG(x) ((x) >> 2)
|
||||
|
||||
#define FSI_MENP0 TO_REG(0x010)
|
||||
#define FSI_MENP32 TO_REG(0x014)
|
||||
#define FSI_MSENP0 TO_REG(0x018)
|
||||
#define FSI_MLEVP0 TO_REG(0x018)
|
||||
#define FSI_MSENP32 TO_REG(0x01c)
|
||||
#define FSI_MLEVP32 TO_REG(0x01c)
|
||||
#define FSI_MCENP0 TO_REG(0x020)
|
||||
#define FSI_MREFP0 TO_REG(0x020)
|
||||
#define FSI_MCENP32 TO_REG(0x024)
|
||||
#define FSI_MREFP32 TO_REG(0x024)
|
||||
|
||||
#define FSI_MVER TO_REG(0x074)
|
||||
#define FSI_MRESP0 TO_REG(0x0d0)
|
||||
|
||||
#define FSI_MRESB0 TO_REG(0x1d0)
|
||||
#define FSI_MRESB0_RESET_GENERAL BIT(31)
|
||||
#define FSI_MRESB0_RESET_ERROR BIT(30)
|
||||
|
||||
static uint64_t fsi_master_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
FSIMasterState *s = FSI_MASTER(opaque);
|
||||
int reg = TO_REG(addr);
|
||||
|
||||
trace_fsi_master_read(addr, size);
|
||||
|
||||
if (reg >= FSI_MASTER_NR_REGS) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Out of bounds read: 0x%"HWADDR_PRIx" for %u\n",
|
||||
__func__, addr, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return s->regs[reg];
|
||||
}
|
||||
|
||||
static void fsi_master_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
unsigned size)
|
||||
{
|
||||
FSIMasterState *s = FSI_MASTER(opaque);
|
||||
int reg = TO_REG(addr);
|
||||
|
||||
trace_fsi_master_write(addr, size, data);
|
||||
|
||||
if (reg >= FSI_MASTER_NR_REGS) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Out of bounds write: %"HWADDR_PRIx" for %u\n",
|
||||
__func__, addr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (reg) {
|
||||
case FSI_MENP0:
|
||||
s->regs[FSI_MENP0] = data;
|
||||
break;
|
||||
case FSI_MENP32:
|
||||
s->regs[FSI_MENP32] = data;
|
||||
break;
|
||||
case FSI_MSENP0:
|
||||
s->regs[FSI_MENP0] |= data;
|
||||
break;
|
||||
case FSI_MSENP32:
|
||||
s->regs[FSI_MENP32] |= data;
|
||||
break;
|
||||
case FSI_MCENP0:
|
||||
s->regs[FSI_MENP0] &= ~data;
|
||||
break;
|
||||
case FSI_MCENP32:
|
||||
s->regs[FSI_MENP32] &= ~data;
|
||||
break;
|
||||
case FSI_MRESP0:
|
||||
/* Perform necessary resets leave register 0 to indicate no errors */
|
||||
break;
|
||||
case FSI_MRESB0:
|
||||
if (data & FSI_MRESB0_RESET_GENERAL) {
|
||||
device_cold_reset(DEVICE(opaque));
|
||||
}
|
||||
if (data & FSI_MRESB0_RESET_ERROR) {
|
||||
/* FIXME: this seems dubious */
|
||||
device_cold_reset(DEVICE(opaque));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
s->regs[reg] = data;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct MemoryRegionOps fsi_master_ops = {
|
||||
.read = fsi_master_read,
|
||||
.write = fsi_master_write,
|
||||
.endianness = DEVICE_BIG_ENDIAN,
|
||||
};
|
||||
|
||||
static void fsi_master_init(Object *o)
|
||||
{
|
||||
FSIMasterState *s = FSI_MASTER(o);
|
||||
|
||||
object_initialize_child(o, "cfam", &s->cfam, TYPE_FSI_CFAM);
|
||||
|
||||
qbus_init(&s->bus, sizeof(s->bus), TYPE_FSI_BUS, DEVICE(s), NULL);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &fsi_master_ops, s,
|
||||
TYPE_FSI_MASTER, 0x10000000);
|
||||
memory_region_init(&s->opb2fsi, OBJECT(s), "fsi.opb2fsi", 0x10000000);
|
||||
}
|
||||
|
||||
static void fsi_master_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
FSIMasterState *s = FSI_MASTER(dev);
|
||||
|
||||
if (!qdev_realize(DEVICE(&s->cfam), BUS(&s->bus), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* address ? */
|
||||
memory_region_add_subregion(&s->opb2fsi, 0, &s->cfam.mr);
|
||||
}
|
||||
|
||||
static void fsi_master_reset(DeviceState *dev)
|
||||
{
|
||||
FSIMasterState *s = FSI_MASTER(dev);
|
||||
|
||||
/* Initialize registers */
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
|
||||
/* ASPEED default */
|
||||
s->regs[FSI_MVER] = 0xe0050101;
|
||||
}
|
||||
|
||||
static void fsi_master_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->bus_type = TYPE_OP_BUS;
|
||||
dc->desc = "FSI Master";
|
||||
dc->realize = fsi_master_realize;
|
||||
dc->reset = fsi_master_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo fsi_master_info = {
|
||||
.name = TYPE_FSI_MASTER,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_init = fsi_master_init,
|
||||
.instance_size = sizeof(FSIMasterState),
|
||||
.class_init = fsi_master_class_init,
|
||||
};
|
||||
|
||||
static void fsi_register_types(void)
|
||||
{
|
||||
type_register_static(&fsi_master_info);
|
||||
}
|
||||
|
||||
type_init(fsi_register_types);
|
@ -1 +1 @@
|
||||
system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c','fsi.c','cfam.c'))
|
||||
system_ss.add(when: 'CONFIG_FSI', if_true: files('lbus.c','fsi.c','cfam.c','fsi-master.c'))
|
||||
|
@ -7,3 +7,5 @@ fsi_cfam_config_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64
|
||||
fsi_cfam_unimplemented_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d"
|
||||
fsi_cfam_unimplemented_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64
|
||||
fsi_cfam_config_write_noaddr(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64
|
||||
fsi_master_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d"
|
||||
fsi_master_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64
|
||||
|
32
include/hw/fsi/fsi-master.h
Normal file
32
include/hw/fsi/fsi-master.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright (C) 2024 IBM Corp.
|
||||
*
|
||||
* IBM Flexible Service Interface Master
|
||||
*/
|
||||
#ifndef FSI_FSI_MASTER_H
|
||||
#define FSI_FSI_MASTER_H
|
||||
|
||||
#include "exec/memory.h"
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/fsi/fsi.h"
|
||||
#include "hw/fsi/cfam.h"
|
||||
|
||||
#define TYPE_FSI_MASTER "fsi.master"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(FSIMasterState, FSI_MASTER)
|
||||
|
||||
#define FSI_MASTER_NR_REGS ((0x2e0 >> 2) + 1)
|
||||
|
||||
typedef struct FSIMasterState {
|
||||
DeviceState parent;
|
||||
MemoryRegion iomem;
|
||||
MemoryRegion opb2fsi;
|
||||
|
||||
FSIBus bus;
|
||||
|
||||
uint32_t regs[FSI_MASTER_NR_REGS];
|
||||
FSICFAMState cfam;
|
||||
} FSIMasterState;
|
||||
|
||||
|
||||
#endif /* FSI_FSI_H */
|
Loading…
x
Reference in New Issue
Block a user