diff mbox series

[4/4] hw/ocmb: Add OCMB SCOM support

Message ID 20200402111356.1413-4-oohall@gmail.com
State Accepted
Headers show
Series [1/4] hw/xscom: Add scom infrastructure | expand

Checks

Context Check Description
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (ec7be0894c652bfda961418d79dd19838678abfc)

Commit Message

Oliver O'Halloran April 2, 2020, 11:13 a.m. UTC
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>
---
 core/init.c     |   4 ++
 hw/Makefile.inc |   1 +
 hw/ocmb.c       | 167 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/ocmb.h  |  13 ++++
 4 files changed, 185 insertions(+)
 create mode 100644 hw/ocmb.c
 create mode 100644 include/ocmb.h
diff mbox series

Patch

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 <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 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 <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 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