diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/814-qe-0001-irqchip-qeic-move-qeic-driver-from-drivers-soc-fsl-q.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/814-qe-0001-irqchip-qeic-move-qeic-driver-from-drivers-soc-fsl-q.patch | 1243 |
1 files changed, 0 insertions, 1243 deletions
diff --git a/target/linux/layerscape/patches-5.4/814-qe-0001-irqchip-qeic-move-qeic-driver-from-drivers-soc-fsl-q.patch b/target/linux/layerscape/patches-5.4/814-qe-0001-irqchip-qeic-move-qeic-driver-from-drivers-soc-fsl-q.patch deleted file mode 100644 index bedc902cee..0000000000 --- a/target/linux/layerscape/patches-5.4/814-qe-0001-irqchip-qeic-move-qeic-driver-from-drivers-soc-fsl-q.patch +++ /dev/null @@ -1,1243 +0,0 @@ -From 0172b31512827b9fd735df47751c7aa88b6aa5f6 Mon Sep 17 00:00:00 2001 -From: Zhao Qiang <qiang.zhao@nxp.com> -Date: Thu, 27 Apr 2017 09:52:54 +0800 -Subject: [PATCH] irqchip/qeic: move qeic driver from drivers/soc/fsl/qe - -move the driver from drivers/soc/fsl/qe to drivers/irqchip, -merge qe_ic.h and qe_ic.c into irq-qeic.c. - -Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com> ---- - drivers/irqchip/irq-qeic.c | 597 ++++++++++++++++++++++++++++++++++++++++++++ - drivers/soc/fsl/qe/Makefile | 2 +- - drivers/soc/fsl/qe/qe_ic.c | 508 ------------------------------------- - drivers/soc/fsl/qe/qe_ic.h | 99 -------- - 4 files changed, 598 insertions(+), 608 deletions(-) - create mode 100644 drivers/irqchip/irq-qeic.c - delete mode 100644 drivers/soc/fsl/qe/qe_ic.c - delete mode 100644 drivers/soc/fsl/qe/qe_ic.h - ---- /dev/null -+++ b/drivers/irqchip/irq-qeic.c -@@ -0,0 +1,597 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * drivers/irqchip/irq-qeic.c -+ * -+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All rights reserved. -+ * -+ * Author: Li Yang <leoli@freescale.com> -+ * Based on code from Shlomi Gridish <gridish@freescale.com> -+ * -+ * QUICC ENGINE Interrupt Controller -+ */ -+ -+#include <linux/of_irq.h> -+#include <linux/of_address.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/errno.h> -+#include <linux/reboot.h> -+#include <linux/slab.h> -+#include <linux/stddef.h> -+#include <linux/sched.h> -+#include <linux/signal.h> -+#include <linux/device.h> -+#include <linux/spinlock.h> -+#include <asm/irq.h> -+#include <asm/io.h> -+#include <soc/fsl/qe/qe_ic.h> -+ -+#define NR_QE_IC_INTS 64 -+ -+/* QE IC registers offset */ -+#define QEIC_CICR 0x00 -+#define QEIC_CIVEC 0x04 -+#define QEIC_CRIPNR 0x08 -+#define QEIC_CIPNR 0x0c -+#define QEIC_CIPXCC 0x10 -+#define QEIC_CIPYCC 0x14 -+#define QEIC_CIPWCC 0x18 -+#define QEIC_CIPZCC 0x1c -+#define QEIC_CIMR 0x20 -+#define QEIC_CRIMR 0x24 -+#define QEIC_CICNR 0x28 -+#define QEIC_CIPRTA 0x30 -+#define QEIC_CIPRTB 0x34 -+#define QEIC_CRICR 0x3c -+#define QEIC_CHIVEC 0x60 -+ -+/* Interrupt priority registers */ -+#define CIPCC_SHIFT_PRI0 29 -+#define CIPCC_SHIFT_PRI1 26 -+#define CIPCC_SHIFT_PRI2 23 -+#define CIPCC_SHIFT_PRI3 20 -+#define CIPCC_SHIFT_PRI4 13 -+#define CIPCC_SHIFT_PRI5 10 -+#define CIPCC_SHIFT_PRI6 7 -+#define CIPCC_SHIFT_PRI7 4 -+ -+/* CICR priority modes */ -+#define CICR_GWCC 0x00040000 -+#define CICR_GXCC 0x00020000 -+#define CICR_GYCC 0x00010000 -+#define CICR_GZCC 0x00080000 -+#define CICR_GRTA 0x00200000 -+#define CICR_GRTB 0x00400000 -+#define CICR_HPIT_SHIFT 8 -+#define CICR_HPIT_MASK 0x00000300 -+#define CICR_HP_SHIFT 24 -+#define CICR_HP_MASK 0x3f000000 -+ -+/* CICNR */ -+#define CICNR_WCC1T_SHIFT 20 -+#define CICNR_ZCC1T_SHIFT 28 -+#define CICNR_YCC1T_SHIFT 12 -+#define CICNR_XCC1T_SHIFT 4 -+ -+/* CRICR */ -+#define CRICR_RTA1T_SHIFT 20 -+#define CRICR_RTB1T_SHIFT 28 -+ -+/* Signal indicator */ -+#define SIGNAL_MASK 3 -+#define SIGNAL_HIGH 2 -+#define SIGNAL_LOW 0 -+ -+struct qe_ic { -+ /* Control registers offset */ -+ u32 __iomem *regs; -+ -+ /* The remapper for this QEIC */ -+ struct irq_domain *irqhost; -+ -+ /* The "linux" controller struct */ -+ struct irq_chip hc_irq; -+ -+ /* VIRQ numbers of QE high/low irqs */ -+ unsigned int virq_high; -+ unsigned int virq_low; -+}; -+ -+/* -+ * QE interrupt controller internal structure -+ */ -+struct qe_ic_info { -+ /* location of this source at the QIMR register. */ -+ u32 mask; -+ -+ /* Mask register offset */ -+ u32 mask_reg; -+ -+ /* -+ * for grouped interrupts sources - the interrupt -+ * code as appears at the group priority register -+ */ -+ u8 pri_code; -+ -+ /* Group priority register offset */ -+ u32 pri_reg; -+}; -+ -+static DEFINE_RAW_SPINLOCK(qe_ic_lock); -+ -+static struct qe_ic_info qe_ic_info[] = { -+ [1] = { -+ .mask = 0x00008000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 0, -+ .pri_reg = QEIC_CIPWCC, -+ }, -+ [2] = { -+ .mask = 0x00004000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 1, -+ .pri_reg = QEIC_CIPWCC, -+ }, -+ [3] = { -+ .mask = 0x00002000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 2, -+ .pri_reg = QEIC_CIPWCC, -+ }, -+ [10] = { -+ .mask = 0x00000040, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 1, -+ .pri_reg = QEIC_CIPZCC, -+ }, -+ [11] = { -+ .mask = 0x00000020, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 2, -+ .pri_reg = QEIC_CIPZCC, -+ }, -+ [12] = { -+ .mask = 0x00000010, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 3, -+ .pri_reg = QEIC_CIPZCC, -+ }, -+ [13] = { -+ .mask = 0x00000008, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 4, -+ .pri_reg = QEIC_CIPZCC, -+ }, -+ [14] = { -+ .mask = 0x00000004, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 5, -+ .pri_reg = QEIC_CIPZCC, -+ }, -+ [15] = { -+ .mask = 0x00000002, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 6, -+ .pri_reg = QEIC_CIPZCC, -+ }, -+ [20] = { -+ .mask = 0x10000000, -+ .mask_reg = QEIC_CRIMR, -+ .pri_code = 3, -+ .pri_reg = QEIC_CIPRTA, -+ }, -+ [25] = { -+ .mask = 0x00800000, -+ .mask_reg = QEIC_CRIMR, -+ .pri_code = 0, -+ .pri_reg = QEIC_CIPRTB, -+ }, -+ [26] = { -+ .mask = 0x00400000, -+ .mask_reg = QEIC_CRIMR, -+ .pri_code = 1, -+ .pri_reg = QEIC_CIPRTB, -+ }, -+ [27] = { -+ .mask = 0x00200000, -+ .mask_reg = QEIC_CRIMR, -+ .pri_code = 2, -+ .pri_reg = QEIC_CIPRTB, -+ }, -+ [28] = { -+ .mask = 0x00100000, -+ .mask_reg = QEIC_CRIMR, -+ .pri_code = 3, -+ .pri_reg = QEIC_CIPRTB, -+ }, -+ [32] = { -+ .mask = 0x80000000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 0, -+ .pri_reg = QEIC_CIPXCC, -+ }, -+ [33] = { -+ .mask = 0x40000000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 1, -+ .pri_reg = QEIC_CIPXCC, -+ }, -+ [34] = { -+ .mask = 0x20000000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 2, -+ .pri_reg = QEIC_CIPXCC, -+ }, -+ [35] = { -+ .mask = 0x10000000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 3, -+ .pri_reg = QEIC_CIPXCC, -+ }, -+ [36] = { -+ .mask = 0x08000000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 4, -+ .pri_reg = QEIC_CIPXCC, -+ }, -+ [40] = { -+ .mask = 0x00800000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 0, -+ .pri_reg = QEIC_CIPYCC, -+ }, -+ [41] = { -+ .mask = 0x00400000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 1, -+ .pri_reg = QEIC_CIPYCC, -+ }, -+ [42] = { -+ .mask = 0x00200000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 2, -+ .pri_reg = QEIC_CIPYCC, -+ }, -+ [43] = { -+ .mask = 0x00100000, -+ .mask_reg = QEIC_CIMR, -+ .pri_code = 3, -+ .pri_reg = QEIC_CIPYCC, -+ }, -+}; -+ -+static inline u32 qe_ic_read(volatile __be32 __iomem * base, unsigned int reg) -+{ -+ return in_be32(base + (reg >> 2)); -+} -+ -+static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg, -+ u32 value) -+{ -+ out_be32(base + (reg >> 2), value); -+} -+ -+static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) -+{ -+ return irq_get_chip_data(virq); -+} -+ -+static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d) -+{ -+ return irq_data_get_irq_chip_data(d); -+} -+ -+static void qe_ic_unmask_irq(struct irq_data *d) -+{ -+ struct qe_ic *qe_ic = qe_ic_from_irq_data(d); -+ unsigned int src = irqd_to_hwirq(d); -+ unsigned long flags; -+ u32 temp; -+ -+ raw_spin_lock_irqsave(&qe_ic_lock, flags); -+ -+ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); -+ qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, -+ temp | qe_ic_info[src].mask); -+ -+ raw_spin_unlock_irqrestore(&qe_ic_lock, flags); -+} -+ -+static void qe_ic_mask_irq(struct irq_data *d) -+{ -+ struct qe_ic *qe_ic = qe_ic_from_irq_data(d); -+ unsigned int src = irqd_to_hwirq(d); -+ unsigned long flags; -+ u32 temp; -+ -+ raw_spin_lock_irqsave(&qe_ic_lock, flags); -+ -+ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); -+ qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, -+ temp & ~qe_ic_info[src].mask); -+ -+ /* Flush the above write before enabling interrupts; otherwise, -+ * spurious interrupts will sometimes happen. To be 100% sure -+ * that the write has reached the device before interrupts are -+ * enabled, the mask register would have to be read back; however, -+ * this is not required for correctness, only to avoid wasting -+ * time on a large number of spurious interrupts. In testing, -+ * a sync reduced the observed spurious interrupts to zero. -+ */ -+ mb(); -+ -+ raw_spin_unlock_irqrestore(&qe_ic_lock, flags); -+} -+ -+static struct irq_chip qe_ic_irq_chip = { -+ .name = "QEIC", -+ .irq_unmask = qe_ic_unmask_irq, -+ .irq_mask = qe_ic_mask_irq, -+ .irq_mask_ack = qe_ic_mask_irq, -+}; -+ -+static int qe_ic_host_match(struct irq_domain *h, struct device_node *node, -+ enum irq_domain_bus_token bus_token) -+{ -+ /* Exact match, unless qe_ic node is NULL */ -+ struct device_node *of_node = irq_domain_get_of_node(h); -+ return of_node == NULL || of_node == node; -+} -+ -+static int qe_ic_host_map(struct irq_domain *h, unsigned int virq, -+ irq_hw_number_t hw) -+{ -+ struct qe_ic *qe_ic = h->host_data; -+ struct irq_chip *chip; -+ -+ if (hw >= ARRAY_SIZE(qe_ic_info)) { -+ pr_err("%s: Invalid hw irq number for QEIC\n", __func__); -+ return -EINVAL; -+ } -+ -+ if (qe_ic_info[hw].mask == 0) { -+ printk(KERN_ERR "Can't map reserved IRQ\n"); -+ return -EINVAL; -+ } -+ /* Default chip */ -+ chip = &qe_ic->hc_irq; -+ -+ irq_set_chip_data(virq, qe_ic); -+ irq_set_status_flags(virq, IRQ_LEVEL); -+ -+ irq_set_chip_and_handler(virq, chip, handle_level_irq); -+ -+ return 0; -+} -+ -+static const struct irq_domain_ops qe_ic_host_ops = { -+ .match = qe_ic_host_match, -+ .map = qe_ic_host_map, -+ .xlate = irq_domain_xlate_onetwocell, -+}; -+ -+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ -+unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic) -+{ -+ int irq; -+ -+ BUG_ON(qe_ic == NULL); -+ -+ /* get the interrupt source vector. */ -+ irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26; -+ -+ if (irq == 0) -+ return NO_IRQ; -+ -+ return irq_linear_revmap(qe_ic->irqhost, irq); -+} -+ -+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ -+unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic) -+{ -+ int irq; -+ -+ BUG_ON(qe_ic == NULL); -+ -+ /* get the interrupt source vector. */ -+ irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26; -+ -+ if (irq == 0) -+ return NO_IRQ; -+ -+ return irq_linear_revmap(qe_ic->irqhost, irq); -+} -+ -+void __init qe_ic_init(struct device_node *node, unsigned int flags, -+ void (*low_handler)(struct irq_desc *desc), -+ void (*high_handler)(struct irq_desc *desc)) -+{ -+ struct qe_ic *qe_ic; -+ struct resource res; -+ u32 temp = 0, ret, high_active = 0; -+ -+ ret = of_address_to_resource(node, 0, &res); -+ if (ret) -+ return; -+ -+ qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL); -+ if (qe_ic == NULL) -+ return; -+ -+ qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS, -+ &qe_ic_host_ops, qe_ic); -+ if (qe_ic->irqhost == NULL) { -+ kfree(qe_ic); -+ return; -+ } -+ -+ qe_ic->regs = ioremap(res.start, resource_size(&res)); -+ -+ qe_ic->hc_irq = qe_ic_irq_chip; -+ -+ qe_ic->virq_high = irq_of_parse_and_map(node, 0); -+ qe_ic->virq_low = irq_of_parse_and_map(node, 1); -+ -+ if (qe_ic->virq_low == NO_IRQ) { -+ printk(KERN_ERR "Failed to map QE_IC low IRQ\n"); -+ kfree(qe_ic); -+ return; -+ } -+ -+ /* default priority scheme is grouped. If spread mode is */ -+ /* required, configure cicr accordingly. */ -+ if (flags & QE_IC_SPREADMODE_GRP_W) -+ temp |= CICR_GWCC; -+ if (flags & QE_IC_SPREADMODE_GRP_X) -+ temp |= CICR_GXCC; -+ if (flags & QE_IC_SPREADMODE_GRP_Y) -+ temp |= CICR_GYCC; -+ if (flags & QE_IC_SPREADMODE_GRP_Z) -+ temp |= CICR_GZCC; -+ if (flags & QE_IC_SPREADMODE_GRP_RISCA) -+ temp |= CICR_GRTA; -+ if (flags & QE_IC_SPREADMODE_GRP_RISCB) -+ temp |= CICR_GRTB; -+ -+ /* choose destination signal for highest priority interrupt */ -+ if (flags & QE_IC_HIGH_SIGNAL) { -+ temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT); -+ high_active = 1; -+ } -+ -+ qe_ic_write(qe_ic->regs, QEIC_CICR, temp); -+ -+ irq_set_handler_data(qe_ic->virq_low, qe_ic); -+ irq_set_chained_handler(qe_ic->virq_low, low_handler); -+ -+ if (qe_ic->virq_high != NO_IRQ && -+ qe_ic->virq_high != qe_ic->virq_low) { -+ irq_set_handler_data(qe_ic->virq_high, qe_ic); -+ irq_set_chained_handler(qe_ic->virq_high, high_handler); -+ } -+} -+ -+void qe_ic_set_highest_priority(unsigned int virq, int high) -+{ -+ struct qe_ic *qe_ic = qe_ic_from_irq(virq); -+ unsigned int src = virq_to_hw(virq); -+ u32 temp = 0; -+ -+ temp = qe_ic_read(qe_ic->regs, QEIC_CICR); -+ -+ temp &= ~CICR_HP_MASK; -+ temp |= src << CICR_HP_SHIFT; -+ -+ temp &= ~CICR_HPIT_MASK; -+ temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT; -+ -+ qe_ic_write(qe_ic->regs, QEIC_CICR, temp); -+} -+ -+/* Set Priority level within its group, from 1 to 8 */ -+int qe_ic_set_priority(unsigned int virq, unsigned int priority) -+{ -+ struct qe_ic *qe_ic = qe_ic_from_irq(virq); -+ unsigned int src = virq_to_hw(virq); -+ u32 temp; -+ -+ if (priority > 8 || priority == 0) -+ return -EINVAL; -+ if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info), -+ "%s: Invalid hw irq number for QEIC\n", __func__)) -+ return -EINVAL; -+ if (qe_ic_info[src].pri_reg == 0) -+ return -EINVAL; -+ -+ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg); -+ -+ if (priority < 4) { -+ temp &= ~(0x7 << (32 - priority * 3)); -+ temp |= qe_ic_info[src].pri_code << (32 - priority * 3); -+ } else { -+ temp &= ~(0x7 << (24 - priority * 3)); -+ temp |= qe_ic_info[src].pri_code << (24 - priority * 3); -+ } -+ -+ qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp); -+ -+ return 0; -+} -+ -+/* Set a QE priority to use high irq, only priority 1~2 can use high irq */ -+int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high) -+{ -+ struct qe_ic *qe_ic = qe_ic_from_irq(virq); -+ unsigned int src = virq_to_hw(virq); -+ u32 temp, control_reg = QEIC_CICNR, shift = 0; -+ -+ if (priority > 2 || priority == 0) -+ return -EINVAL; -+ if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info), -+ "%s: Invalid hw irq number for QEIC\n", __func__)) -+ return -EINVAL; -+ -+ switch (qe_ic_info[src].pri_reg) { -+ case QEIC_CIPZCC: -+ shift = CICNR_ZCC1T_SHIFT; -+ break; -+ case QEIC_CIPWCC: -+ shift = CICNR_WCC1T_SHIFT; -+ break; -+ case QEIC_CIPYCC: -+ shift = CICNR_YCC1T_SHIFT; -+ break; -+ case QEIC_CIPXCC: -+ shift = CICNR_XCC1T_SHIFT; -+ break; -+ case QEIC_CIPRTA: -+ shift = CRICR_RTA1T_SHIFT; -+ control_reg = QEIC_CRICR; -+ break; -+ case QEIC_CIPRTB: -+ shift = CRICR_RTB1T_SHIFT; -+ control_reg = QEIC_CRICR; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ shift += (2 - priority) * 2; -+ temp = qe_ic_read(qe_ic->regs, control_reg); -+ temp &= ~(SIGNAL_MASK << shift); -+ temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift; -+ qe_ic_write(qe_ic->regs, control_reg, temp); -+ -+ return 0; -+} -+ -+static struct bus_type qe_ic_subsys = { -+ .name = "qe_ic", -+ .dev_name = "qe_ic", -+}; -+ -+static struct device device_qe_ic = { -+ .id = 0, -+ .bus = &qe_ic_subsys, -+}; -+ -+static int __init init_qe_ic_sysfs(void) -+{ -+ int rc; -+ -+ printk(KERN_DEBUG "Registering qe_ic with sysfs...\n"); -+ -+ rc = subsys_system_register(&qe_ic_subsys, NULL); -+ if (rc) { -+ printk(KERN_ERR "Failed registering qe_ic sys class\n"); -+ return -ENODEV; -+ } -+ rc = device_register(&device_qe_ic); -+ if (rc) { -+ printk(KERN_ERR "Failed registering qe_ic sys device\n"); -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+subsys_initcall(init_qe_ic_sysfs); ---- a/drivers/soc/fsl/qe/Makefile -+++ b/drivers/soc/fsl/qe/Makefile -@@ -2,7 +2,7 @@ - # - # Makefile for the linux ppc-specific parts of QE - # --obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o -+obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_io.o - obj-$(CONFIG_CPM) += qe_common.o - obj-$(CONFIG_UCC) += ucc.o - obj-$(CONFIG_UCC_SLOW) += ucc_slow.o ---- a/drivers/soc/fsl/qe/qe_ic.c -+++ /dev/null -@@ -1,508 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-or-later --/* -- * arch/powerpc/sysdev/qe_lib/qe_ic.c -- * -- * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. -- * -- * Author: Li Yang <leoli@freescale.com> -- * Based on code from Shlomi Gridish <gridish@freescale.com> -- * -- * QUICC ENGINE Interrupt Controller -- */ -- --#include <linux/of_irq.h> --#include <linux/of_address.h> --#include <linux/kernel.h> --#include <linux/init.h> --#include <linux/errno.h> --#include <linux/reboot.h> --#include <linux/slab.h> --#include <linux/stddef.h> --#include <linux/sched.h> --#include <linux/signal.h> --#include <linux/device.h> --#include <linux/spinlock.h> --#include <asm/irq.h> --#include <asm/io.h> --#include <soc/fsl/qe/qe_ic.h> -- --#include "qe_ic.h" -- --static DEFINE_RAW_SPINLOCK(qe_ic_lock); -- --static struct qe_ic_info qe_ic_info[] = { -- [1] = { -- .mask = 0x00008000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 0, -- .pri_reg = QEIC_CIPWCC, -- }, -- [2] = { -- .mask = 0x00004000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 1, -- .pri_reg = QEIC_CIPWCC, -- }, -- [3] = { -- .mask = 0x00002000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 2, -- .pri_reg = QEIC_CIPWCC, -- }, -- [10] = { -- .mask = 0x00000040, -- .mask_reg = QEIC_CIMR, -- .pri_code = 1, -- .pri_reg = QEIC_CIPZCC, -- }, -- [11] = { -- .mask = 0x00000020, -- .mask_reg = QEIC_CIMR, -- .pri_code = 2, -- .pri_reg = QEIC_CIPZCC, -- }, -- [12] = { -- .mask = 0x00000010, -- .mask_reg = QEIC_CIMR, -- .pri_code = 3, -- .pri_reg = QEIC_CIPZCC, -- }, -- [13] = { -- .mask = 0x00000008, -- .mask_reg = QEIC_CIMR, -- .pri_code = 4, -- .pri_reg = QEIC_CIPZCC, -- }, -- [14] = { -- .mask = 0x00000004, -- .mask_reg = QEIC_CIMR, -- .pri_code = 5, -- .pri_reg = QEIC_CIPZCC, -- }, -- [15] = { -- .mask = 0x00000002, -- .mask_reg = QEIC_CIMR, -- .pri_code = 6, -- .pri_reg = QEIC_CIPZCC, -- }, -- [20] = { -- .mask = 0x10000000, -- .mask_reg = QEIC_CRIMR, -- .pri_code = 3, -- .pri_reg = QEIC_CIPRTA, -- }, -- [25] = { -- .mask = 0x00800000, -- .mask_reg = QEIC_CRIMR, -- .pri_code = 0, -- .pri_reg = QEIC_CIPRTB, -- }, -- [26] = { -- .mask = 0x00400000, -- .mask_reg = QEIC_CRIMR, -- .pri_code = 1, -- .pri_reg = QEIC_CIPRTB, -- }, -- [27] = { -- .mask = 0x00200000, -- .mask_reg = QEIC_CRIMR, -- .pri_code = 2, -- .pri_reg = QEIC_CIPRTB, -- }, -- [28] = { -- .mask = 0x00100000, -- .mask_reg = QEIC_CRIMR, -- .pri_code = 3, -- .pri_reg = QEIC_CIPRTB, -- }, -- [32] = { -- .mask = 0x80000000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 0, -- .pri_reg = QEIC_CIPXCC, -- }, -- [33] = { -- .mask = 0x40000000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 1, -- .pri_reg = QEIC_CIPXCC, -- }, -- [34] = { -- .mask = 0x20000000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 2, -- .pri_reg = QEIC_CIPXCC, -- }, -- [35] = { -- .mask = 0x10000000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 3, -- .pri_reg = QEIC_CIPXCC, -- }, -- [36] = { -- .mask = 0x08000000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 4, -- .pri_reg = QEIC_CIPXCC, -- }, -- [40] = { -- .mask = 0x00800000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 0, -- .pri_reg = QEIC_CIPYCC, -- }, -- [41] = { -- .mask = 0x00400000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 1, -- .pri_reg = QEIC_CIPYCC, -- }, -- [42] = { -- .mask = 0x00200000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 2, -- .pri_reg = QEIC_CIPYCC, -- }, -- [43] = { -- .mask = 0x00100000, -- .mask_reg = QEIC_CIMR, -- .pri_code = 3, -- .pri_reg = QEIC_CIPYCC, -- }, --}; -- --static inline u32 qe_ic_read(volatile __be32 __iomem * base, unsigned int reg) --{ -- return in_be32(base + (reg >> 2)); --} -- --static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg, -- u32 value) --{ -- out_be32(base + (reg >> 2), value); --} -- --static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) --{ -- return irq_get_chip_data(virq); --} -- --static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d) --{ -- return irq_data_get_irq_chip_data(d); --} -- --static void qe_ic_unmask_irq(struct irq_data *d) --{ -- struct qe_ic *qe_ic = qe_ic_from_irq_data(d); -- unsigned int src = irqd_to_hwirq(d); -- unsigned long flags; -- u32 temp; -- -- raw_spin_lock_irqsave(&qe_ic_lock, flags); -- -- temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); -- qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, -- temp | qe_ic_info[src].mask); -- -- raw_spin_unlock_irqrestore(&qe_ic_lock, flags); --} -- --static void qe_ic_mask_irq(struct irq_data *d) --{ -- struct qe_ic *qe_ic = qe_ic_from_irq_data(d); -- unsigned int src = irqd_to_hwirq(d); -- unsigned long flags; -- u32 temp; -- -- raw_spin_lock_irqsave(&qe_ic_lock, flags); -- -- temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); -- qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, -- temp & ~qe_ic_info[src].mask); -- -- /* Flush the above write before enabling interrupts; otherwise, -- * spurious interrupts will sometimes happen. To be 100% sure -- * that the write has reached the device before interrupts are -- * enabled, the mask register would have to be read back; however, -- * this is not required for correctness, only to avoid wasting -- * time on a large number of spurious interrupts. In testing, -- * a sync reduced the observed spurious interrupts to zero. -- */ -- mb(); -- -- raw_spin_unlock_irqrestore(&qe_ic_lock, flags); --} -- --static struct irq_chip qe_ic_irq_chip = { -- .name = "QEIC", -- .irq_unmask = qe_ic_unmask_irq, -- .irq_mask = qe_ic_mask_irq, -- .irq_mask_ack = qe_ic_mask_irq, --}; -- --static int qe_ic_host_match(struct irq_domain *h, struct device_node *node, -- enum irq_domain_bus_token bus_token) --{ -- /* Exact match, unless qe_ic node is NULL */ -- struct device_node *of_node = irq_domain_get_of_node(h); -- return of_node == NULL || of_node == node; --} -- --static int qe_ic_host_map(struct irq_domain *h, unsigned int virq, -- irq_hw_number_t hw) --{ -- struct qe_ic *qe_ic = h->host_data; -- struct irq_chip *chip; -- -- if (hw >= ARRAY_SIZE(qe_ic_info)) { -- pr_err("%s: Invalid hw irq number for QEIC\n", __func__); -- return -EINVAL; -- } -- -- if (qe_ic_info[hw].mask == 0) { -- printk(KERN_ERR "Can't map reserved IRQ\n"); -- return -EINVAL; -- } -- /* Default chip */ -- chip = &qe_ic->hc_irq; -- -- irq_set_chip_data(virq, qe_ic); -- irq_set_status_flags(virq, IRQ_LEVEL); -- -- irq_set_chip_and_handler(virq, chip, handle_level_irq); -- -- return 0; --} -- --static const struct irq_domain_ops qe_ic_host_ops = { -- .match = qe_ic_host_match, -- .map = qe_ic_host_map, -- .xlate = irq_domain_xlate_onetwocell, --}; -- --/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ --unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic) --{ -- int irq; -- -- BUG_ON(qe_ic == NULL); -- -- /* get the interrupt source vector. */ -- irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26; -- -- if (irq == 0) -- return NO_IRQ; -- -- return irq_linear_revmap(qe_ic->irqhost, irq); --} -- --/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ --unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic) --{ -- int irq; -- -- BUG_ON(qe_ic == NULL); -- -- /* get the interrupt source vector. */ -- irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26; -- -- if (irq == 0) -- return NO_IRQ; -- -- return irq_linear_revmap(qe_ic->irqhost, irq); --} -- --void __init qe_ic_init(struct device_node *node, unsigned int flags, -- void (*low_handler)(struct irq_desc *desc), -- void (*high_handler)(struct irq_desc *desc)) --{ -- struct qe_ic *qe_ic; -- struct resource res; -- u32 temp = 0, ret, high_active = 0; -- -- ret = of_address_to_resource(node, 0, &res); -- if (ret) -- return; -- -- qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL); -- if (qe_ic == NULL) -- return; -- -- qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS, -- &qe_ic_host_ops, qe_ic); -- if (qe_ic->irqhost == NULL) { -- kfree(qe_ic); -- return; -- } -- -- qe_ic->regs = ioremap(res.start, resource_size(&res)); -- -- qe_ic->hc_irq = qe_ic_irq_chip; -- -- qe_ic->virq_high = irq_of_parse_and_map(node, 0); -- qe_ic->virq_low = irq_of_parse_and_map(node, 1); -- -- if (qe_ic->virq_low == NO_IRQ) { -- printk(KERN_ERR "Failed to map QE_IC low IRQ\n"); -- kfree(qe_ic); -- return; -- } -- -- /* default priority scheme is grouped. If spread mode is */ -- /* required, configure cicr accordingly. */ -- if (flags & QE_IC_SPREADMODE_GRP_W) -- temp |= CICR_GWCC; -- if (flags & QE_IC_SPREADMODE_GRP_X) -- temp |= CICR_GXCC; -- if (flags & QE_IC_SPREADMODE_GRP_Y) -- temp |= CICR_GYCC; -- if (flags & QE_IC_SPREADMODE_GRP_Z) -- temp |= CICR_GZCC; -- if (flags & QE_IC_SPREADMODE_GRP_RISCA) -- temp |= CICR_GRTA; -- if (flags & QE_IC_SPREADMODE_GRP_RISCB) -- temp |= CICR_GRTB; -- -- /* choose destination signal for highest priority interrupt */ -- if (flags & QE_IC_HIGH_SIGNAL) { -- temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT); -- high_active = 1; -- } -- -- qe_ic_write(qe_ic->regs, QEIC_CICR, temp); -- -- irq_set_handler_data(qe_ic->virq_low, qe_ic); -- irq_set_chained_handler(qe_ic->virq_low, low_handler); -- -- if (qe_ic->virq_high != NO_IRQ && -- qe_ic->virq_high != qe_ic->virq_low) { -- irq_set_handler_data(qe_ic->virq_high, qe_ic); -- irq_set_chained_handler(qe_ic->virq_high, high_handler); -- } --} -- --void qe_ic_set_highest_priority(unsigned int virq, int high) --{ -- struct qe_ic *qe_ic = qe_ic_from_irq(virq); -- unsigned int src = virq_to_hw(virq); -- u32 temp = 0; -- -- temp = qe_ic_read(qe_ic->regs, QEIC_CICR); -- -- temp &= ~CICR_HP_MASK; -- temp |= src << CICR_HP_SHIFT; -- -- temp &= ~CICR_HPIT_MASK; -- temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT; -- -- qe_ic_write(qe_ic->regs, QEIC_CICR, temp); --} -- --/* Set Priority level within its group, from 1 to 8 */ --int qe_ic_set_priority(unsigned int virq, unsigned int priority) --{ -- struct qe_ic *qe_ic = qe_ic_from_irq(virq); -- unsigned int src = virq_to_hw(virq); -- u32 temp; -- -- if (priority > 8 || priority == 0) -- return -EINVAL; -- if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info), -- "%s: Invalid hw irq number for QEIC\n", __func__)) -- return -EINVAL; -- if (qe_ic_info[src].pri_reg == 0) -- return -EINVAL; -- -- temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg); -- -- if (priority < 4) { -- temp &= ~(0x7 << (32 - priority * 3)); -- temp |= qe_ic_info[src].pri_code << (32 - priority * 3); -- } else { -- temp &= ~(0x7 << (24 - priority * 3)); -- temp |= qe_ic_info[src].pri_code << (24 - priority * 3); -- } -- -- qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp); -- -- return 0; --} -- --/* Set a QE priority to use high irq, only priority 1~2 can use high irq */ --int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high) --{ -- struct qe_ic *qe_ic = qe_ic_from_irq(virq); -- unsigned int src = virq_to_hw(virq); -- u32 temp, control_reg = QEIC_CICNR, shift = 0; -- -- if (priority > 2 || priority == 0) -- return -EINVAL; -- if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info), -- "%s: Invalid hw irq number for QEIC\n", __func__)) -- return -EINVAL; -- -- switch (qe_ic_info[src].pri_reg) { -- case QEIC_CIPZCC: -- shift = CICNR_ZCC1T_SHIFT; -- break; -- case QEIC_CIPWCC: -- shift = CICNR_WCC1T_SHIFT; -- break; -- case QEIC_CIPYCC: -- shift = CICNR_YCC1T_SHIFT; -- break; -- case QEIC_CIPXCC: -- shift = CICNR_XCC1T_SHIFT; -- break; -- case QEIC_CIPRTA: -- shift = CRICR_RTA1T_SHIFT; -- control_reg = QEIC_CRICR; -- break; -- case QEIC_CIPRTB: -- shift = CRICR_RTB1T_SHIFT; -- control_reg = QEIC_CRICR; -- break; -- default: -- return -EINVAL; -- } -- -- shift += (2 - priority) * 2; -- temp = qe_ic_read(qe_ic->regs, control_reg); -- temp &= ~(SIGNAL_MASK << shift); -- temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift; -- qe_ic_write(qe_ic->regs, control_reg, temp); -- -- return 0; --} -- --static struct bus_type qe_ic_subsys = { -- .name = "qe_ic", -- .dev_name = "qe_ic", --}; -- --static struct device device_qe_ic = { -- .id = 0, -- .bus = &qe_ic_subsys, --}; -- --static int __init init_qe_ic_sysfs(void) --{ -- int rc; -- -- printk(KERN_DEBUG "Registering qe_ic with sysfs...\n"); -- -- rc = subsys_system_register(&qe_ic_subsys, NULL); -- if (rc) { -- printk(KERN_ERR "Failed registering qe_ic sys class\n"); -- return -ENODEV; -- } -- rc = device_register(&device_qe_ic); -- if (rc) { -- printk(KERN_ERR "Failed registering qe_ic sys device\n"); -- return -ENODEV; -- } -- return 0; --} -- --subsys_initcall(init_qe_ic_sysfs); ---- a/drivers/soc/fsl/qe/qe_ic.h -+++ /dev/null -@@ -1,99 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-or-later */ --/* -- * drivers/soc/fsl/qe/qe_ic.h -- * -- * QUICC ENGINE Interrupt Controller Header -- * -- * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. -- * -- * Author: Li Yang <leoli@freescale.com> -- * Based on code from Shlomi Gridish <gridish@freescale.com> -- */ --#ifndef _POWERPC_SYSDEV_QE_IC_H --#define _POWERPC_SYSDEV_QE_IC_H -- --#include <soc/fsl/qe/qe_ic.h> -- --#define NR_QE_IC_INTS 64 -- --/* QE IC registers offset */ --#define QEIC_CICR 0x00 --#define QEIC_CIVEC 0x04 --#define QEIC_CRIPNR 0x08 --#define QEIC_CIPNR 0x0c --#define QEIC_CIPXCC 0x10 --#define QEIC_CIPYCC 0x14 --#define QEIC_CIPWCC 0x18 --#define QEIC_CIPZCC 0x1c --#define QEIC_CIMR 0x20 --#define QEIC_CRIMR 0x24 --#define QEIC_CICNR 0x28 --#define QEIC_CIPRTA 0x30 --#define QEIC_CIPRTB 0x34 --#define QEIC_CRICR 0x3c --#define QEIC_CHIVEC 0x60 -- --/* Interrupt priority registers */ --#define CIPCC_SHIFT_PRI0 29 --#define CIPCC_SHIFT_PRI1 26 --#define CIPCC_SHIFT_PRI2 23 --#define CIPCC_SHIFT_PRI3 20 --#define CIPCC_SHIFT_PRI4 13 --#define CIPCC_SHIFT_PRI5 10 --#define CIPCC_SHIFT_PRI6 7 --#define CIPCC_SHIFT_PRI7 4 -- --/* CICR priority modes */ --#define CICR_GWCC 0x00040000 --#define CICR_GXCC 0x00020000 --#define CICR_GYCC 0x00010000 --#define CICR_GZCC 0x00080000 --#define CICR_GRTA 0x00200000 --#define CICR_GRTB 0x00400000 --#define CICR_HPIT_SHIFT 8 --#define CICR_HPIT_MASK 0x00000300 --#define CICR_HP_SHIFT 24 --#define CICR_HP_MASK 0x3f000000 -- --/* CICNR */ --#define CICNR_WCC1T_SHIFT 20 --#define CICNR_ZCC1T_SHIFT 28 --#define CICNR_YCC1T_SHIFT 12 --#define CICNR_XCC1T_SHIFT 4 -- --/* CRICR */ --#define CRICR_RTA1T_SHIFT 20 --#define CRICR_RTB1T_SHIFT 28 -- --/* Signal indicator */ --#define SIGNAL_MASK 3 --#define SIGNAL_HIGH 2 --#define SIGNAL_LOW 0 -- --struct qe_ic { -- /* Control registers offset */ -- volatile u32 __iomem *regs; -- -- /* The remapper for this QEIC */ -- struct irq_domain *irqhost; -- -- /* The "linux" controller struct */ -- struct irq_chip hc_irq; -- -- /* VIRQ numbers of QE high/low irqs */ -- unsigned int virq_high; -- unsigned int virq_low; --}; -- --/* -- * QE interrupt controller internal structure -- */ --struct qe_ic_info { -- u32 mask; /* location of this source at the QIMR register. */ -- u32 mask_reg; /* Mask register offset */ -- u8 pri_code; /* for grouped interrupts sources - the interrupt -- code as appears at the group priority register */ -- u32 pri_reg; /* Group priority register offset */ --}; -- --#endif /* _POWERPC_SYSDEV_QE_IC_H */ |