diff --git a/core/init.c b/core/init.c index bff4e968aae5..595d087fa4f3 100644 --- a/core/init.c +++ b/core/init.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1190,6 +1191,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) /* Grab centaurs from device-tree if present (only on FSP-less) */ centaur_init(); + /* initialize ocmb scom-controller */ + ocmb_init(); + /* Initialize PSI (depends on probe_platform being called) */ psi_init(); diff --git a/hw/Makefile.inc b/hw/Makefile.inc index b708bdfe7630..a7f450cf7246 100644 --- a/hw/Makefile.inc +++ b/hw/Makefile.inc @@ -9,6 +9,7 @@ HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o HW_OBJS += npu2-common.o npu2-opencapi.o phys-map.o sbe-p9.o capp.o HW_OBJS += occ-sensor.o vas.o sbe-p8.o dio-p9.o lpc-port80h.o cache-p9.o HW_OBJS += npu-opal.o npu3.o npu3-nvlink.o npu3-hw-procedures.o +HW_OBJS += ocmb.o HW=hw/built-in.a include $(SRC)/hw/fsp/Makefile.inc diff --git a/hw/ocmb.c b/hw/ocmb.c new file mode 100644 index 000000000000..19b15dd68095 --- /dev/null +++ b/hw/ocmb.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * Open Capi Memory Buffer chip + * + * Copyright 2020 IBM Corp. + */ + + +#define pr_fmt(fmt) "OCMB: " fmt + +#include +#include +#include +#include +#include +#include + +struct ocmb_range { + uint64_t start; + uint64_t end; + uint64_t flags; + + /* flags come from hdat */ +#define ACCESS_8B PPC_BIT(0) +#define ACCESS_4B PPC_BIT(1) +#define ACCESS_SIZE_MASK (ACCESS_8B | ACCESS_4B) +}; + +struct ocmb { + struct scom_controller scom; + int range_count; + struct ocmb_range ranges[]; +}; + +static const struct ocmb_range *find_range(const struct ocmb *o, uint64_t offset) +{ + int i; + + for (i = 0; i < o->range_count; i++) { + uint64_t start = o->ranges[i].start; + uint64_t end = o->ranges[i].end; + + if (offset >= start && offset <= end) + return &o->ranges[i]; + } + + return NULL; +} + +static int64_t ocmb_fake_scom_write(struct scom_controller *f, + uint32_t __unused chip_id, + uint64_t offset, uint64_t val) +{ + const struct ocmb *o = f->private; + const struct ocmb_range *r; + + r = find_range(o, offset); + if (!r) { + prerror("no matching address range!\n"); + return OPAL_XSCOM_ADDR_ERROR; + } + + switch (r->flags & ACCESS_SIZE_MASK) { + case ACCESS_8B: + if (offset & 0x7) + return OPAL_XSCOM_ADDR_ERROR; + out_be64((void *) offset, val); + break; + + case ACCESS_4B: + if (offset & 0x3) + return OPAL_XSCOM_ADDR_ERROR; + out_be32((void *) offset, val); + break; + default: + prerror("bad flags? %llx\n", r->flags); + return OPAL_XSCOM_ADDR_ERROR; + } + + return OPAL_SUCCESS; +} + +static int64_t ocmb_fake_scom_read(struct scom_controller *f, + uint32_t chip_id __unused, + uint64_t offset, uint64_t *val) +{ + const struct ocmb *o = f->private; + const struct ocmb_range *r = NULL; + + r = find_range(o, offset); + if (!r) { + prerror("no matching address range!\n"); + return OPAL_XSCOM_ADDR_ERROR; + } + + + switch (r->flags & ACCESS_SIZE_MASK) { + case ACCESS_8B: + if (offset & 0x7) + return OPAL_XSCOM_ADDR_ERROR; + *val = in_be64((void *) offset); + break; + + case ACCESS_4B: + if (offset & 0x3) + return OPAL_XSCOM_ADDR_ERROR; + *val = in_be32((void *) offset); + break; + default: + prerror("bad flags? %llx\n", r->flags); + return OPAL_XSCOM_ADDR_ERROR; + } + + return OPAL_SUCCESS; +} + +static bool ocmb_probe_one(struct dt_node *ocmb_node) +{ + uint64_t chip_id = dt_prop_get_u32(ocmb_node, "ibm,chip-id"); + const struct dt_property *flags; + int i = 0, num = 0; + struct ocmb *ocmb; + + num = dt_count_addresses(ocmb_node); + + ocmb = zalloc(sizeof(*ocmb) + sizeof(*ocmb->ranges) * num); + if (!ocmb) + return false; + + ocmb->scom.private = ocmb; + ocmb->scom.part_id = chip_id; + ocmb->scom.write = ocmb_fake_scom_write; + ocmb->scom.read = ocmb_fake_scom_read; + ocmb->range_count = num; + + flags = dt_require_property(ocmb_node, "flags", sizeof(u64) * num); + + for (i = 0; i < num; i++) { + uint64_t start, size; + + start = dt_get_address(ocmb_node, i, &size); + + ocmb->ranges[i].start = start; + ocmb->ranges[i].end = start + size - 1; + ocmb->ranges[i].flags = dt_property_get_u64(flags, i); + + prlog(PR_DEBUG, "Added range: %" PRIx64 " - [%llx - %llx]\n", + chip_id, start, start + size - 1); + } + + if (scom_register(&ocmb->scom)) + prerror("error registienr fake socm\n"); + + dt_add_property(ocmb_node, "scom-controller", NULL, 0); + + prerror("XXX: Added scom controller for %s\n", ocmb_node->name); + + return true; +} + +void ocmb_init(void) +{ + struct dt_node *dn; + + dt_for_each_compatible(dt_root, dn, "ibm,explorer") + ocmb_probe_one(dn); +} diff --git a/include/ocmb.h b/include/ocmb.h new file mode 100644 index 000000000000..e7531885d2a3 --- /dev/null +++ b/include/ocmb.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* + * Open Capi Memory Buffer chip + * + * Copyright 2020 IBM Corp. + */ + +#ifndef __OCMB_H +#define __OCMB_H + +extern void ocmb_init(void); + +#endif /* __OCMB_H */ \ No newline at end of file