aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/hw/dio-p9.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/dio-p9.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/hw/dio-p9.c')
-rw-r--r--roms/skiboot/hw/dio-p9.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/roms/skiboot/hw/dio-p9.c b/roms/skiboot/hw/dio-p9.c
new file mode 100644
index 000000000..5153f6eeb
--- /dev/null
+++ b/roms/skiboot/hw/dio-p9.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2019 IBM Corp. */
+
+#define pr_fmt(fmt) "DIO: " fmt
+
+#include <chip.h>
+#include <dio-p9.h>
+#include <opal.h>
+#include <xscom.h>
+#include <xscom-p9-regs.h>
+
+void p9_dio_init(void)
+{
+ struct dt_node *xn;
+ struct proc_chip *chip;
+ struct p9_dio *dio;
+
+ if (proc_gen < proc_gen_p9)
+ return;
+
+ dt_for_each_compatible(dt_root, xn, "ibm,xscom") {
+ dio = zalloc(sizeof(struct p9_dio));
+ assert(dio);
+ chip = get_chip(dt_get_chip_id(xn));
+ assert(chip);
+ chip->dio = dio;
+ }
+}
+
+int dio_interrupt_register(struct proc_chip *chip,
+ int port, dio_interrupt_callback callback)
+{
+ u64 val;
+ int rc;
+
+ assert(chip);
+ assert(chip->dio);
+
+ if (port < 0 || port >= NUM_OF_P9_DIO_PORTS)
+ return OPAL_PARAMETER;
+
+ if (chip->dio->callbacks[port]) /* This port already has a callback */
+ return OPAL_PARAMETER;
+
+ rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_ENABLE, &val);
+ if (rc != OPAL_SUCCESS) {
+ prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
+ rc, P9_GPIO_INTERRUPT_ENABLE);
+ return OPAL_HARDWARE;
+ }
+
+ val |= PPC_BIT(port);
+ rc = xscom_write(chip->id, P9_GPIO_INTERRUPT_ENABLE, val);
+ if (rc != OPAL_SUCCESS) {
+ prlog(PR_ERR, "XSCOM error %d writing reg 0x%llx\n",
+ rc, P9_GPIO_INTERRUPT_ENABLE);
+ return OPAL_HARDWARE;
+ }
+
+ chip->dio->callbacks[port] = callback;
+
+ return OPAL_SUCCESS;
+}
+
+int dio_interrupt_deregister(struct proc_chip* chip,
+ int port, dio_interrupt_callback callback)
+{
+ u64 val;
+ int rc;
+
+ assert(chip);
+ assert(chip->dio);
+
+ if (port < 0 || port >= NUM_OF_P9_DIO_PORTS)
+ return OPAL_PARAMETER;
+
+ if (chip->dio->callbacks[port] != callback)
+ return OPAL_PARAMETER;
+
+ rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_ENABLE, &val);
+ if (rc != OPAL_SUCCESS) {
+ prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
+ rc, P9_GPIO_INTERRUPT_ENABLE);
+ return OPAL_HARDWARE;
+ }
+
+ val &= ~PPC_BIT(port);
+ rc = xscom_write(chip->id, P9_GPIO_INTERRUPT_ENABLE, val);
+ if (rc != OPAL_SUCCESS) {
+ prlog(PR_ERR, "XSCOM error %d writing reg 0x%llx\n",
+ rc, P9_GPIO_INTERRUPT_ENABLE);
+ return OPAL_HARDWARE;
+ }
+
+ chip->dio->callbacks[port] = NULL;
+
+ return OPAL_SUCCESS;
+}
+
+void dio_interrupt_handler(uint32_t chip_id)
+{
+ struct proc_chip *chip;
+ u64 val;
+ int rc;
+ int i;
+
+ chip = get_chip(chip_id);
+ if (chip == NULL || chip->dio == NULL)
+ return;
+
+ rc = xscom_read(chip->id, P9_GPIO_INTERRUPT_STATUS, &val);
+ if (rc != OPAL_SUCCESS) {
+ prlog(PR_ERR, "XSCOM error %d reading reg 0x%llx\n",
+ rc, P9_GPIO_INTERRUPT_STATUS);
+ return;
+ }
+
+ for (i = 0; i < NUM_OF_P9_DIO_PORTS; ++i) {
+ if (val & PPC_BIT(i)) {
+ if (chip->dio->callbacks[i])
+ chip->dio->callbacks[i](chip);
+ else
+ prlog(PR_ERR,
+ "DIO interrupt triggerd on chip 0x%x"
+ " port %d but no handler\n",
+ chip->id, i);
+ /* Write 1 to clear the interrupt status */
+ xscom_write(chip->id, P9_GPIO_INTERRUPT_CONDITION,
+ val & PPC_BIT(i));
+ }
+ }
+}