aboutsummaryrefslogtreecommitdiff
path: root/include/lpc.h
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-06-15 10:00:14 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-06-19 15:12:57 +1000
commit35b433b79bb41f2cdb45e18ea1d20d326fefb344 (patch)
treeb029d8bb3476d29bc2dcc3de7ce7f691eba61cf3 /include/lpc.h
parenta921764eed0a38670cacc47fa3aa9d5e87e1ab6b (diff)
downloadskiboot-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/lpc.h')
-rw-r--r--include/lpc.h59
1 files changed, 57 insertions, 2 deletions
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,