diff options
author | Lei YU <mine260309@gmail.com> | 2019-01-18 10:30:06 +0800 |
---|---|---|
committer | Stewart Smith <stewart@linux.ibm.com> | 2019-05-15 16:22:23 +1000 |
commit | df34cedd050a966b334973c933e5e7e90164b6ec (patch) | |
tree | 83d1f14c732c36c10954b7055ba5697c5765c967 | |
parent | 32d44e3555218a7df92b56a411c271617dad77c4 (diff) | |
download | skiboot-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>
-rw-r--r-- | core/init.c | 4 | ||||
-rw-r--r-- | hw/Makefile.inc | 2 | ||||
-rw-r--r-- | hw/dio-p9.c | 146 | ||||
-rw-r--r-- | hw/psi.c | 2 | ||||
-rw-r--r-- | include/chip.h | 4 | ||||
-rw-r--r-- | include/dio-p9.h | 50 | ||||
-rw-r--r-- | include/xscom-p9-regs.h | 5 |
7 files changed, 211 insertions, 2 deletions
diff --git a/core/init.c b/core/init.c index b2c2e29..6a920f5 100644 --- a/core/init.c +++ b/core/init.c @@ -51,6 +51,7 @@ #include <phys-map.h> #include <imc.h> #include <dts.h> +#include <dio-p9.h> #include <sbe-p9.h> #include <debug_descriptor.h> #include <occ.h> @@ -1142,6 +1143,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) */ chiptod_init(); + /* Initialize P9 DIO */ + p9_dio_init(); + /* * SBE uses TB value for scheduling timer. Hence init after * chiptod init 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)); + } + } +} @@ -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); diff --git a/include/chip.h b/include/chip.h index d6e7e35..5231d17 100644 --- a/include/chip.h +++ b/include/chip.h @@ -114,6 +114,7 @@ struct xive; struct lpcm; struct vas; struct p9_sbe; +struct p9_dio; /* Chip type */ enum proc_chip_type { @@ -224,6 +225,9 @@ struct proc_chip { /* Used by hw/sbe-p9.c */ struct p9_sbe *sbe; + + /* Used by hw/dio-p9.c */ + struct p9_dio *dio; }; extern uint32_t pir_to_chip_id(uint32_t pir); diff --git a/include/dio-p9.h b/include/dio-p9.h new file mode 100644 index 0000000..65aed2d --- /dev/null +++ b/include/dio-p9.h @@ -0,0 +1,50 @@ + +/* 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. + */ + +#ifndef __DIO_H +#define __DIO_H + +struct proc_chip; + +/* Initialize the P9 DIO */ +extern void p9_dio_init(void); + +/* The function typedef for dio interrupt callback */ +typedef void (*dio_interrupt_callback)(struct proc_chip *chip); + +/* Register dio interrupt on GPIO port. + * This effectively enables the DIO interrupt on the GPIO port, + * and callback will be called when the interrupt is triggered */ +extern int dio_interrupt_register(struct proc_chip *chip, + int port, dio_interrupt_callback c); + +/* Deregister dio interrupt on GPIO port. + * This effectively disables the DIO interrupt on the GPIO port. */ +extern int dio_interrupt_deregister(struct proc_chip *chip, + int port, dio_interrupt_callback c); + +/* The function to be called when DIO interrupt is triggered */ +extern void dio_interrupt_handler(uint32_t chip_id); + + +#define NUM_OF_P9_DIO_PORTS 3 /* P9 has GPIO port 0~2 for interrupts */ + +struct p9_dio { + dio_interrupt_callback callbacks[NUM_OF_P9_DIO_PORTS]; +}; + +#endif /* __DIO_H */ diff --git a/include/xscom-p9-regs.h b/include/xscom-p9-regs.h index 2c9dc6b..5137d91 100644 --- a/include/xscom-p9-regs.h +++ b/include/xscom-p9-regs.h @@ -58,8 +58,11 @@ #define P9X_EX_NCU_DARN_BAR 0x11011 #define P9X_EX_NCU_DARN_BAR_EN PPC_BIT(0) -#define P9_GPIO_DATA_OUT_ENABLE 0x00000000000B0054ull #define P9_GPIO_DATA_OUT 0x00000000000B0051ull +#define P9_GPIO_DATA_OUT_ENABLE 0x00000000000B0054ull +#define P9_GPIO_INTERRUPT_STATUS 0x00000000000B0057ull +#define P9_GPIO_INTERRUPT_ENABLE 0x00000000000B005Dull +#define P9_GPIO_INTERRUPT_CONDITION 0x00000000000B005Eull /* xscom address for SCOM Control and data Register */ /* bits 54:60 of SCOM SPRC register is used for core specific SPR selection. */ |