Skip to content

Commit

Permalink
Add P9 DIO interrupt support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mine260309 authored and stewartsmith committed May 15, 2019
1 parent 32d44e3 commit df34ced
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 2 deletions.
4 changes: 4 additions & 0 deletions core/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion hw/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
146 changes: 146 additions & 0 deletions hw/dio-p9.c
Original file line number Diff line number Diff line change
@@ -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));
}
}
}
2 changes: 2 additions & 0 deletions hw/psi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions include/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ struct xive;
struct lpcm;
struct vas;
struct p9_sbe;
struct p9_dio;

/* Chip type */
enum proc_chip_type {
Expand Down Expand Up @@ -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);
Expand Down
50 changes: 50 additions & 0 deletions include/dio-p9.h
Original file line number Diff line number Diff line change
@@ -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 */
5 changes: 4 additions & 1 deletion include/xscom-p9-regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down

0 comments on commit df34ced

Please sign in to comment.