aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorLei YU <mine260309@gmail.com>2019-01-18 10:30:06 +0800
committerStewart Smith <stewart@linux.ibm.com>2019-05-15 16:22:23 +1000
commitdf34cedd050a966b334973c933e5e7e90164b6ec (patch)
tree83d1f14c732c36c10954b7055ba5697c5765c967 /hw
parent32d44e3555218a7df92b56a411c271617dad77c4 (diff)
downloadskiboot-df34cedd050a966b334973c933e5e7e90164b6ec.zip
skiboot-df34cedd050a966b334973c933e5e7e90164b6ec.tar.gz
skiboot-df34cedd050a966b334973c933e5e7e90164b6ec.tar.bz2
Add P9 DIO interrupt support
On P9 there are GPIO port 0, 1, 2 for GPIO interrupt, and DIO interrupt is used to handle the interrupts. Add support to the DIO interrupts: 1. Add dio_interrupt_register(chip, port, callback) to register the interrupt; 2. Add dio_interrupt_deregister(chip, port, callback) to deregister; 3. When interrupt on the port occurs, callback is invoked, and the interrupt status is cleared. Signed-off-by: Lei YU <mine260309@gmail.com> [oliver: Fixed Makefile.inc merge conflict] Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/Makefile.inc2
-rw-r--r--hw/dio-p9.c146
-rw-r--r--hw/psi.c2
3 files changed, 149 insertions, 1 deletions
diff --git a/hw/Makefile.inc b/hw/Makefile.inc
index fbafd82..2885b50 100644
--- a/hw/Makefile.inc
+++ b/hw/Makefile.inc
@@ -9,7 +9,7 @@ HW_OBJS += dts.o lpc-rtc.o npu.o npu-hw-procedures.o xive.o phb4.o
HW_OBJS += fake-nvram.o lpc-mbox.o npu2.o npu2-hw-procedures.o
HW_OBJS += npu2-common.o phys-map.o sbe-p9.o capp.o occ-sensor.o vas.o
HW_OBJS += npu2-opencapi.o phys-map.o sbe-p9.o capp.o occ-sensor.o
-HW_OBJS += vas.o sbe-p8.o
+HW_OBJS += vas.o sbe-p8.o dio-p9.o
HW_OBJS += lpc-port80h.o
HW=hw/built-in.a
diff --git a/hw/dio-p9.c b/hw/dio-p9.c
new file mode 100644
index 0000000..e2d40ac
--- /dev/null
+++ b/hw/dio-p9.c
@@ -0,0 +1,146 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#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));
+ }
+ }
+}
diff --git a/hw/psi.c b/hw/psi.c
index 2f7ab5f..ff6b0a9 100644
--- a/hw/psi.c
+++ b/hw/psi.c
@@ -24,6 +24,7 @@
#include <gx.h>
#include <interrupts.h>
#include <cpu.h>
+#include <dio-p9.h>
#include <trace.h>
#include <xscom.h>
#include <chip.h>
@@ -604,6 +605,7 @@ static void psihb_p9_interrupt(struct irq_source *is, uint32_t isn)
break;
case P9_PSI_IRQ_DIO:
printf("PSI: DIO irq received\n");
+ dio_interrupt_handler(psi->chip_id);
break;
case P9_PSI_IRQ_PSU:
p9_sbe_interrupt(psi->chip_id);