diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2015-06-15 10:00:14 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-06-19 15:12:57 +1000 |
commit | 35b433b79bb41f2cdb45e18ea1d20d326fefb344 (patch) | |
tree | b029d8bb3476d29bc2dcc3de7ce7f691eba61cf3 /include | |
parent | a921764eed0a38670cacc47fa3aa9d5e87e1ab6b (diff) | |
download | skiboot-35b433b79bb41f2cdb45e18ea1d20d326fefb344.zip skiboot-35b433b79bb41f2cdb45e18ea1d20d326fefb344.tar.gz skiboot-35b433b79bb41f2cdb45e18ea1d20d326fefb344.tar.bz2 |
Support for Naples LPC serial interrupts
This adds support for the HW SerIRQ deserializer of the P8 LPC
bridge which is properly wired up on Naples. It also adds support
for detecting and reporting LPC error interrupts on all P8s.
On most platforms (Rhesus is the exception here due to the way it
lets Linux handle the UART interrupts directly), we modify the
device-tree to properly represent the LPC controller as a cascaded
interrupt-controller and the "interrupts" property of LPC devices
to contain the actual LPC interrupt number for the device.
We add a mechanism for drivers to register specific LPC interrupts,
and a "workaround" for pre-Naples P8 which platforms can use to call
all of them for when the external FPGA based deserializer is used.
There's also a callback on LPC resets which isn't used yet, we need
a bit more work on the general LPC error handling, but it can be
done a separate patches.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'include')
-rw-r--r-- | include/bt.h | 1 | ||||
-rw-r--r-- | include/chip.h | 1 | ||||
-rw-r--r-- | include/lpc.h | 59 | ||||
-rw-r--r-- | include/skiboot.h | 1 |
4 files changed, 58 insertions, 4 deletions
diff --git a/include/bt.h b/include/bt.h index 43843d2..1763d9f 100644 --- a/include/bt.h +++ b/include/bt.h @@ -19,6 +19,5 @@ /* Initialise the BT interface */ void bt_init(void); -void bt_irq(void); #endif diff --git a/include/chip.h b/include/chip.h index 1b4f4c4..9cecace 100644 --- a/include/chip.h +++ b/include/chip.h @@ -136,6 +136,7 @@ struct proc_chip { struct lock lpc_lock; uint8_t lpc_fw_idsel; uint8_t lpc_fw_rdsz; + struct list_head lpc_clients; /* Used by hw/slw.c */ uint64_t slw_base; diff --git a/include/lpc.h b/include/lpc.h index a0990fd..a79d256 100644 --- a/include/lpc.h +++ b/include/lpc.h @@ -20,6 +20,42 @@ #include <opal.h> #include <ccan/endian/endian.h> +/* Note about LPC interrupts + * + * LPC interrupts come in two categories: + * + * - External device LPC interrupts + * - Error interrupts generated by the LPC controller + * + * The former is implemented differently depending on whether + * you are using Murano/Venice or Naples. + * + * The former two chips don't have a pin to deserialize the LPC + * SerIRQ protocol, so the only source of LPC device interrupts + * is an external interrupt pin, which is usually connected to a + * CPLD which deserializes SerIRQ. + * + * So in that case, we get external interrupts from the PSI which + * are in effect the "OR" of all the active LPC interrupts. + * + * The error interrupt generated by the LPC controllers however + * are internally routed normally to the PSI bridge and muxed with + * the I2C interrupts. + * + * On Naples, there is a pin to deserialize SerIRQ, so the individual + * LPC device interrupts (up to 19) are represented in the same status + * and mask register as the LPC error interrupts. They are still all + * then turned into a single XIVE interrupts in the PSI however, muxed + * with the I2C. + * + * In order to more/less transparently handle this, we let individual + * "drivers" register for specific LPC interrupts. On Naples, the handlers + * will be called individually based on what has been demuxed by the + * controller. On Venice/Murano, all the handlers will be called on + * every external interrupt. The platform is responsible of calling + * lpc_all_interrupts() from the platform external interrupt handler. + */ + /* Routines for accessing the LPC bus on Power8 */ extern void lpc_init(void); @@ -33,8 +69,27 @@ extern bool lpc_present(void); */ extern bool lpc_ok(void); -/* Handle the interrupt from LPC source */ -extern void __attrconst lpc_interrupt(uint32_t chip_id); +/* Handle the interrupt from the LPC controller */ +extern void lpc_interrupt(uint32_t chip_id); + +/* Call all external handlers */ +extern void lpc_all_interrupts(uint32_t chip_id); + +/* Register/deregister handler */ +struct lpc_client { + /* Callback on LPC reset */ + void (*reset)(uint32_t chip_id); + + /* Callback on LPC interrupt */ + void (*interrupt)(uint32_t chip_id, uint32_t irq_msk); + /* Bitmask of interrupts this client is interested in + * Note: beware of ordering, use LPC_IRQ() macro + */ + uint32_t interrupts; +#define LPC_IRQ(n) (0x80000000 >> (n)) +}; + +extern void lpc_register_client(uint32_t chip_id, const struct lpc_client *clt); /* Default bus accessors */ extern int64_t lpc_write(enum OpalLPCAddressType addr_type, uint32_t addr, diff --git a/include/skiboot.h b/include/skiboot.h index 790f3db..9f5fa31 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -232,7 +232,6 @@ extern void nvram_init(void); extern void nvram_read_complete(bool success); /* UART stuff */ -extern void uart_irq(void); extern void uart_setup_linux_passthrough(void); extern void uart_setup_opal_console(void); |