aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2020-04-02 22:13:56 +1100
committerOliver O'Halloran <oohall@gmail.com>2020-04-08 14:38:33 +1000
commite991415a88dbfd6c1690c5c2d8840288f45ec925 (patch)
treec3e814c5f255def7f8bb410e5ba34ad832bdaa1e
parent38b5c3179d59489320e116b810ab21eec8205657 (diff)
downloadskiboot-e991415a88dbfd6c1690c5c2d8840288f45ec925.zip
skiboot-e991415a88dbfd6c1690c5c2d8840288f45ec925.tar.gz
skiboot-e991415a88dbfd6c1690c5c2d8840288f45ec925.tar.bz2
hw/ocmb: Add OCMB SCOM support
Add a driver for the SCOM ranges of the OCMB. Unlike most chips the OCMB has two different (three if you count OpenCAPI config space) register spaces and we need to ensure that the right access size is used on each. Additionally the SCOM interface is a bit non-standard in that a full physical address is passed as the SCOM address rather than a register number so we don't need to perform any address transformations, we just need to verify that the address falls into one of the nominated address ranges. Cc: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
-rw-r--r--core/init.c4
-rw-r--r--hw/Makefile.inc1
-rw-r--r--hw/ocmb.c167
-rw-r--r--include/ocmb.h13
4 files changed, 185 insertions, 0 deletions
diff --git a/core/init.c b/core/init.c
index bff4e96..595d087 100644
--- a/core/init.c
+++ b/core/init.c
@@ -29,6 +29,7 @@
#include <console.h>
#include <fsi-master.h>
#include <centaur.h>
+#include <ocmb.h>
#include <libfdt/libfdt.h>
#include <timer.h>
#include <ipmi.h>
@@ -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 b708bdf..a7f450c 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 0000000..19b15dd
--- /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 <skiboot.h>
+#include <xscom.h>
+#include <device.h>
+#include <ocmb.h>
+#include <io.h>
+#include <inttypes.h>
+
+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 0000000..e753188
--- /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