aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/hw/capp.c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/skiboot/hw/capp.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/hw/capp.c')
-rw-r--r--roms/skiboot/hw/capp.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/roms/skiboot/hw/capp.c b/roms/skiboot/hw/capp.c
new file mode 100644
index 000000000..a1aa1caa9
--- /dev/null
+++ b/roms/skiboot/hw/capp.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/*
+ * CAPP unit (i.e. CAPI)
+ *
+ * Copyright 2013-2019 IBM Corp.
+ */
+
+#include <skiboot.h>
+#include <io.h>
+#include <opal.h>
+#include <chip.h>
+#include <xscom.h>
+#include <capp.h>
+
+#define PHBERR(opal_id, chip_id, index, fmt, a...) \
+ prlog(PR_ERR, "PHB#%04x[%d:%d]: " fmt, \
+ opal_id, chip_id, \
+ index, ## a)
+
+static struct {
+ uint32_t ec_level;
+ struct capp_lid_hdr *lid;
+ size_t size;
+ int load_result;
+} capp_ucode_info = { 0, NULL, 0, false };
+
+#define CAPP_UCODE_MAX_SIZE 0x20000
+
+struct lock capi_lock = LOCK_UNLOCKED;
+struct capp_ops capi_ops = { NULL };
+
+bool capp_ucode_loaded(struct proc_chip *chip, unsigned int index)
+{
+ return (chip->capp_ucode_loaded & (1 << index));
+}
+
+int preload_capp_ucode(void)
+{
+ struct dt_node *p;
+ struct proc_chip *chip;
+ uint32_t index;
+ uint64_t rc;
+ int ret;
+
+ /* CAPI is supported on P8 and P9 only */
+ p = dt_find_compatible_node(dt_root, NULL, "ibm,power8-pbcq");
+ if (!p)
+ p = dt_find_compatible_node(dt_root, NULL, "ibm,power9-pbcq");
+ if (!p)
+ return OPAL_SUCCESS;
+
+ chip = get_chip(dt_get_chip_id(p));
+
+ rc = xscom_read_cfam_chipid(chip->id, &index);
+ if (rc) {
+ prerror("CAPP: Error reading cfam chip-id\n");
+ ret = OPAL_HARDWARE;
+ return ret;
+ }
+ /* Keep ChipID and Major/Minor EC. Mask out the Location Code. */
+ index = index & 0xf0fff;
+
+ /* Assert that we're preloading */
+ assert(capp_ucode_info.lid == NULL);
+ capp_ucode_info.load_result = OPAL_EMPTY;
+
+ capp_ucode_info.ec_level = index;
+
+ /* Is the ucode preloaded like for BML? */
+ if (dt_has_node_property(p, "ibm,capp-ucode", NULL)) {
+ capp_ucode_info.lid = (struct capp_lid_hdr *)(u64)
+ dt_prop_get_u32(p, "ibm,capp-ucode");
+ capp_ucode_info.load_result = OPAL_SUCCESS;
+ ret = OPAL_SUCCESS;
+ goto end;
+ }
+ /* If we successfully download the ucode, we leave it around forever */
+ capp_ucode_info.size = CAPP_UCODE_MAX_SIZE;
+ capp_ucode_info.lid = malloc(CAPP_UCODE_MAX_SIZE);
+ if (!capp_ucode_info.lid) {
+ prerror("CAPP: Can't allocate space for ucode lid\n");
+ ret = OPAL_NO_MEM;
+ goto end;
+ }
+
+ prlog(PR_INFO, "CAPI: Preloading ucode %x\n", capp_ucode_info.ec_level);
+
+ ret = start_preload_resource(RESOURCE_ID_CAPP, index,
+ capp_ucode_info.lid,
+ &capp_ucode_info.size);
+
+ if (ret != OPAL_SUCCESS) {
+ prerror("CAPI: Failed to preload resource %d\n", ret);
+ capp_ucode_info.load_result = ret;
+ }
+
+end:
+ return ret;
+}
+
+static int64_t capp_lid_download(void)
+{
+ int64_t ret;
+
+ if (capp_ucode_info.load_result != OPAL_EMPTY)
+ return capp_ucode_info.load_result;
+
+ capp_ucode_info.load_result = wait_for_resource_loaded(
+ RESOURCE_ID_CAPP,
+ capp_ucode_info.ec_level);
+
+ if (capp_ucode_info.load_result != OPAL_SUCCESS) {
+ prerror("CAPP: Error loading ucode lid. index=%x\n",
+ capp_ucode_info.ec_level);
+ ret = OPAL_RESOURCE;
+ free(capp_ucode_info.lid);
+ capp_ucode_info.lid = NULL;
+ goto end;
+ }
+
+ ret = OPAL_SUCCESS;
+end:
+ return ret;
+}
+
+int64_t capp_load_ucode(unsigned int chip_id, uint32_t opal_id,
+ unsigned int index, u64 lid_eyecatcher,
+ uint32_t reg_offset,
+ uint64_t apc_master_addr, uint64_t apc_master_write,
+ uint64_t snp_array_addr, uint64_t snp_array_write)
+{
+ struct proc_chip *chip = get_chip(chip_id);
+ struct capp_ucode_lid *ucode;
+ struct capp_ucode_data *data;
+ struct capp_lid_hdr *lid;
+ uint64_t rc, val, addr;
+ uint32_t chunk_count, offset;
+ int i;
+
+ if (capp_ucode_loaded(chip, index))
+ return OPAL_SUCCESS;
+
+ rc = capp_lid_download();
+ if (rc)
+ return rc;
+
+ prlog(PR_INFO, "CHIP%i: CAPP ucode lid loaded at %p\n",
+ chip_id, capp_ucode_info.lid);
+
+ lid = capp_ucode_info.lid;
+ /*
+ * If lid header is present (on FSP machines), it'll tell us where to
+ * find the ucode. Otherwise this is the ucode.
+ */
+ ucode = (struct capp_ucode_lid *)lid;
+ if (be64_to_cpu(lid->eyecatcher) == lid_eyecatcher) {
+ if (be64_to_cpu(lid->version) != 0x1) {
+ PHBERR(opal_id, chip_id, index,
+ "capi ucode lid header invalid\n");
+ return OPAL_HARDWARE;
+ }
+ ucode = (struct capp_ucode_lid *)
+ ((char *)ucode + be64_to_cpu(lid->ucode_offset));
+ }
+
+ /* 'CAPPULID' in ASCII */
+ if ((be64_to_cpu(ucode->eyecatcher) != 0x43415050554C4944UL) ||
+ (be64_to_cpu(ucode->version) != 1)) {
+ PHBERR(opal_id, chip_id, index,
+ "CAPP: ucode header invalid\n");
+ return OPAL_HARDWARE;
+ }
+
+ offset = 0;
+ while (offset < be64_to_cpu(ucode->data_size)) {
+ data = (struct capp_ucode_data *)
+ ((char *)&ucode->data + offset);
+ chunk_count = be32_to_cpu(data->hdr.chunk_count);
+ offset += sizeof(struct capp_ucode_data_hdr) + chunk_count * 8;
+
+ /* 'CAPPUCOD' in ASCII */
+ if (be64_to_cpu(data->hdr.eyecatcher) != 0x4341505055434F44UL) {
+ PHBERR(opal_id, chip_id, index,
+ "CAPP: ucode data header invalid:%i\n",
+ offset);
+ return OPAL_HARDWARE;
+ }
+
+ switch (data->hdr.reg) {
+ case apc_master_cresp:
+ xscom_write(chip_id, apc_master_addr + reg_offset,
+ 0);
+ addr = apc_master_write;
+ break;
+ case apc_master_uop_table:
+ xscom_write(chip_id, apc_master_addr + reg_offset,
+ 0x180ULL << 52);
+ addr = apc_master_write;
+ break;
+ case snp_ttype:
+ xscom_write(chip_id, snp_array_addr + reg_offset,
+ 0x5000ULL << 48);
+ addr = snp_array_write;
+ break;
+ case snp_uop_table:
+ xscom_write(chip_id, snp_array_addr + reg_offset,
+ 0x4000ULL << 48);
+ addr = snp_array_write;
+ break;
+ default:
+ continue;
+ }
+
+ for (i = 0; i < chunk_count; i++) {
+ val = be64_to_cpu(data->data[i]);
+ xscom_write(chip_id, addr + reg_offset, val);
+ }
+ }
+
+ chip->capp_ucode_loaded |= (1 << index);
+
+ return OPAL_SUCCESS;
+}
+
+int64_t capp_get_info(int chip_id, struct phb *phb, struct capp_info *info)
+{
+ if (capi_ops.get_capp_info)
+ return capi_ops.get_capp_info(chip_id, phb, info);
+
+ return OPAL_PARAMETER;
+}
+
+int64_t capp_xscom_read(struct capp *capp, int64_t off, uint64_t *val)
+{
+ return capp == NULL ? OPAL_PARAMETER :
+ xscom_read(capp->chip_id, off + capp->capp_xscom_offset, val);
+}
+
+int64_t capp_xscom_write(struct capp *capp, int64_t off, uint64_t val)
+{
+ return capp == NULL ? OPAL_PARAMETER :
+ xscom_write(capp->chip_id, off + capp->capp_xscom_offset, val);
+}