From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753322AbbIRJT6 (ORCPT ); Fri, 18 Sep 2015 05:19:58 -0400 Received: from mout.gmx.net ([212.227.15.15]:56608 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753158AbbIRJTx (ORCPT ); Fri, 18 Sep 2015 05:19:53 -0400 From: Oleksij Rempel To: linux-kernel@vger.kernel.org, marc.zyngier@arm.com, jason@lakedaemon.net, tglx@linutronix.de Cc: Oleksij Rempel Subject: [PATCH v2 2/2] ARM: irqchip: mxs: add Alpascale ASM9260 support Date: Fri, 18 Sep 2015 11:18:42 +0200 Message-Id: <1442567922-14538-3-git-send-email-linux@rempel-privat.de> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1442567922-14538-1-git-send-email-linux@rempel-privat.de> References: <1442567922-14538-1-git-send-email-linux@rempel-privat.de> X-Provags-ID: V03:K0:VmoxYmZaFJ2P6JvkhcXcPdipqoyKoKqGzlhjnosNCPHaQxfXJ6n 9hzS4TCbUcGjhfaVAR6ud4/yzFyEpz9uM79383R0+VW9GddKwnnOEhAVcqSq8ER3nB3Dhqp iK71Yu5Ek+Lby+x9YmFCuNRvqTiHMtNUPP5XqhkkHvjOKWaMu+24+AlwkiQI79sjbZRD7Kh nAaxC/qY7I5D0osQOpL2A== X-UI-Out-Filterresults: notjunk:1;V01:K0:wtN2rv7tO1g=:0aLWHB7056+NWneyDO1e7O dw7chXw2W5kf6ZcOrqQ+SDyvqlJv2oR72iirRB1b7o31XpjBguu2DK5gBz7e7jo+2CojgTQIb UXxr8g0+cLJO+e0JP2jSkJMR3GS4kd32UJGUlz1usuF+KEBVtIcr2sPiC3P2OE0AZZQfaqrqM +TohdzUl1dN61LXyhCEcRVv8MSFZr46anXNyESYP44Kq+PM+KdBmPrKdjyUliKTWOHvwqDVgE yg11GbO64Y0mxqoQXv1bZfZRdWOLtDDJs6jcnTJ2dxkpJeVEXu7LtJ7iaHbCQkwWpleHnpo3L xlZNMpa51stBs4ueirSWpULU6RDN4ann7IEZ9NxqaEc2INDXnVpQIETI9Ip4GC1I7Fwqtrzsm 4glYULV2eVGION8oQA2Le8zxJLfGuUvZ2BrjljKykSeNeVFtdbXbqbuQMoUmMyitZICgHKEvK PnH8ZnBQFWR4D/fH8NCg9YNJJxjwxYl7x5oLgzzSS9+x/6RmrpDStbyeT4lpQ58p1Eg3AD1Kk KaSUGvwUvGrpb3l/ZqDk46y3TpamHuB/9XzfThIZEalFkf+tqjgJfxTXwwN48ATwNl6h8A4oB 4hNHazN18II81XxqE/nMo0DF+qz6785SryeU/fnhDB04vk6JaQXXdvswTILcugIR5dNi4k4XL Wi5yoYvqGJWI5LyqnosRpuzLjUAea24YI0V4xfNM+7yZEqJlRn2obzY3PcIancjZ5kuzLQ7Me xlnLzUIiQR2fLiUx Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Oleksij Rempel Freescale iMX23/iMX28 and Alphascale ASM9260 have similar interrupt collectors. It makes easy to reuse irq-mxs code for ASM9260. Differences between this devices are fallowing: - different register offsets - different count of intterupt lines per register - ASM9260 don't provide reset bit - ASM9260 don't support FIQ. Signed-off-by: Oleksij Rempel --- drivers/irqchip/Kconfig | 5 ++ drivers/irqchip/Makefile | 2 +- drivers/irqchip/alphascale_asm9260-icoll.h | 109 +++++++++++++++++++++++++++++ drivers/irqchip/irq-mxs.c | 106 +++++++++++++++++++++++++++- 4 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 drivers/irqchip/alphascale_asm9260-icoll.h diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 27b52c8..0dfd840 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -187,3 +187,8 @@ config IMX_GPCV2 select IRQ_DOMAIN help Enables the wakeup IRQs for IMX platforms with GPCv2 block + +config IRQ_MXS + def_bool y if MACH_ASM9260 || ARCH_MXS + select IRQ_DOMAIN + select STMP_DEVICE diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index bb3048f..177f78f 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o obj-$(CONFIG_ARCH_MMP) += irq-mmp.o obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o -obj-$(CONFIG_ARCH_MXS) += irq-mxs.o +obj-$(CONFIG_IRQ_MXS) += irq-mxs.o obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o diff --git a/drivers/irqchip/alphascale_asm9260-icoll.h b/drivers/irqchip/alphascale_asm9260-icoll.h new file mode 100644 index 0000000..5cec108 --- /dev/null +++ b/drivers/irqchip/alphascale_asm9260-icoll.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 Oleksij Rempel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _ALPHASCALE_ASM9260_ICOLL_H +#define _ALPHASCALE_ASM9260_ICOLL_H + +#define ASM9260_NUM_IRQS 64 +/* + * this device provide 4 offsets for each register: + * 0x0 - plain read write mode + * 0x4 - set mode, OR logic. + * 0x8 - clr mode, XOR logic. + * 0xc - togle mode. + */ + +#define ASM9260_HW_ICOLL_VECTOR 0x0000 +/* + * bits 31:2 + * This register presents the vector address for the interrupt currently + * active on the CPU IRQ input. Writing to this register notifies the + * interrupt collector that the interrupt service routine for the current + * interrupt has been entered. + * The exception trap should have a LDPC instruction from this address: + * LDPC ASM9260_HW_ICOLL_VECTOR_ADDR; IRQ exception at 0xffff0018 + */ + +/* + * The Interrupt Collector Level Acknowledge Register is used by software to + * indicate the completion of an interrupt on a specific level. + * This register is written at the very end of an interrupt service routine. If + * nesting is used then the CPU irq must be turned on before writing to this + * register to avoid a race condition in the CPU interrupt hardware. + */ +#define ASM9260_HW_ICOLL_LEVELACK 0x0010 +#define ASM9260_BM_LEVELn(nr) BIT(nr) + +#define ASM9260_HW_ICOLL_CTRL 0x0020 +/* + * ASM9260_BM_CTRL_SFTRST and ASM9260_BM_CTRL_CLKGATE are not available on + * asm9260. + */ +#define ASM9260_BM_CTRL_SFTRST BIT(31) +#define ASM9260_BM_CTRL_CLKGATE BIT(30) +/* disable interrupt level nesting */ +#define ASM9260_BM_CTRL_NO_NESTING BIT(19) +/* + * Set this bit to one enable the RISC32-style read side effect associated with + * the vector address register. In this mode, interrupt in-service is signaled + * by the read of the ASM9260_HW_ICOLL_VECTOR register to acquire the interrupt + * vector address. Set this bit to zero for normal operation, in which the ISR + * signals in-service explicitly by means of a write to the + * ASM9260_HW_ICOLL_VECTOR register. + * 0 - Must Write to Vector register to go in-service. + * 1 - Go in-service as a read side effect + */ +#define ASM9260_BM_CTRL_ARM_RSE_MODE BIT(18) +#define ASM9260_BM_CTRL_IRQ_ENABLE BIT(16) + +#define ASM9260_HW_ICOLL_STAT_OFFSET 0x0030 +/* + * bits 5:0 + * Vector number of current interrupt. Multiply by 4 and add to vector base + * address to obtain the value in ASM9260_HW_ICOLL_VECTOR. + */ + +/* + * RAW0 and RAW1 provides a read-only view of the raw interrupt request lines + * coming from various parts of the chip. Its purpose is to improve diagnostic + * observability. + */ +#define ASM9260_HW_ICOLL_RAW0 0x0040 +#define ASM9260_HW_ICOLL_RAW1 0x0050 + +#define ASM9260_HW_ICOLL_INTERRUPT0 0x0060 +#define ASM9260_HW_ICOLL_INTERRUPTn(n) (0x0060 + ((n) >> 2) * 0x10) +/* + * WARNING: Modifying the priority of an enabled interrupt may result in + * undefined behavior. + */ +#define ASM9260_BM_INT_PRIORITY_MASK 0x3 +#define ASM9260_BM_INT_ENABLE BIT(2) +#define ASM9260_BM_INT_SOFTIRQ BIT(3) + +#define ASM9260_BM_ICOLL_INTERRUPTn_SHIFT(n) (((n) & 0x3) << 3) +#define ASM9260_BM_ICOLL_INTERRUPTn_ENABLE(n) (1 << (2 + \ + ASM9260_BM_ICOLL_INTERRUPTn_SHIFT(n))) + +#define ASM9260_HW_ICOLL_VBASE 0x0160 +/* + * bits 31:2 + * This bitfield holds the upper 30 bits of the base address of the vector + * table. + */ + +#define ASM9260_HW_ICOLL_CLEAR0 0x01d0 +#define ASM9260_HW_ICOLL_CLEAR1 0x01e0 +#define ASM9260_HW_ICOLL_CLEARn(n) (((n >> 5) * 0x10) \ + + SET_REG) +#define ASM9260_BM_CLEAR_BIT(n) BIT(n & 0x1f) + +/* Scratchpad */ +#define ASM9260_HW_ICOLL_UNDEF_VECTOR 0x01f0 +#endif diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index 14374de..1470087 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -1,5 +1,7 @@ /* * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2014 Oleksij Rempel + * Add Alphascale ASM9260 support. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +30,8 @@ #include #include +#include "alphascale_asm9260-icoll.h" + /* * this device provide 4 offsets for each register: * 0x0 - plain read write mode @@ -49,6 +53,11 @@ #define ICOLL_NUM_IRQS 128 +enum icoll_type { + ICOLL, + ASM9260_ICOLL, +}; + struct icoll_priv { void __iomem *vector; void __iomem *levelack; @@ -58,10 +67,38 @@ struct icoll_priv { /* number of interrupts per register */ int intr_per_reg; void __iomem *clear; + enum icoll_type type; }; static struct icoll_priv icoll_priv; static struct irq_domain *icoll_domain; +static DEFINE_RAW_SPINLOCK(icoll_lock); + +/* calculate bit offset depending on number of intterupt per register */ +static u32 icoll_intr_bitshift(struct irq_data *d, u32 bit) +{ + /* + * We expect intr_per_reg to be 4 or 1, it means + * "n" will be 3 or 0. + */ + int n = icoll_priv.intr_per_reg - 1; + + /* + * If n = 0, "bit" is never shifted. + * If n = 3, mask lower part of hwirq to convert it + * in 0, 1, 2 or 3 and then multiply it by 8 (or shift by 3) + */ + return bit << ((d->hwirq & n) << n); +} + +/* calculate mem offset depending on number of intterupt per register */ +static void __iomem *icoll_intr_reg(struct irq_data *d) +{ + int n = icoll_priv.intr_per_reg >> 1; + + /* offset = hwirq / intr_per_reg * 0x10 */ + return icoll_priv.intr + ((d->hwirq >> n) * 0x10); +} static void icoll_ack_irq(struct irq_data *d) { @@ -86,12 +123,38 @@ static void icoll_unmask_irq(struct irq_data *d) icoll_priv.intr + SET_REG + HW_ICOLL_INTERRUPTn(d->hwirq)); } +static void asm9260_mask_irq(struct irq_data *d) +{ + raw_spin_lock(&icoll_lock); + __raw_writel(icoll_intr_bitshift(d, BM_ICOLL_INTR_ENABLE), + icoll_intr_reg(d) + CLR_REG); + raw_spin_unlock(&icoll_lock); +} + +static void asm9260_unmask_irq(struct irq_data *d) +{ + raw_spin_lock(&icoll_lock); + __raw_writel(ASM9260_BM_CLEAR_BIT(d->hwirq), + icoll_priv.clear + + ASM9260_HW_ICOLL_CLEARn(d->hwirq)); + + __raw_writel(icoll_intr_bitshift(d, BM_ICOLL_INTR_ENABLE), + icoll_intr_reg(d) + SET_REG); + raw_spin_unlock(&icoll_lock); +} + static struct irq_chip mxs_icoll_chip = { .irq_ack = icoll_ack_irq, .irq_mask = icoll_mask_irq, .irq_unmask = icoll_unmask_irq, }; +static struct irq_chip asm9260_icoll_chip = { + .irq_ack = icoll_ack_irq, + .irq_mask = asm9260_mask_irq, + .irq_unmask = asm9260_unmask_irq, +}; + asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs) { u32 irqnr; @@ -104,7 +167,14 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs) static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, &mxs_icoll_chip, handle_level_irq); + struct irq_chip *chip; + + if (icoll_priv.type == ICOLL) + chip = &mxs_icoll_chip; + else + chip = &asm9260_icoll_chip; + + irq_set_chip_and_handler(virq, chip, handle_level_irq); set_irq_flags(virq, IRQF_VALID); return 0; @@ -142,6 +212,8 @@ static int __init icoll_of_init(struct device_node *np, { void __iomem *icoll_base; + icoll_priv.type = ICOLL; + icoll_base = icoll_init_iobase(np); icoll_priv.vector = icoll_base + HW_ICOLL_VECTOR; icoll_priv.levelack = icoll_base + HW_ICOLL_LEVELACK; @@ -162,3 +234,35 @@ static int __init icoll_of_init(struct device_node *np, return icoll_domain ? 0 : -ENODEV; } IRQCHIP_DECLARE(mxs, "fsl,icoll", icoll_of_init); + +static int __init asm9260_of_init(struct device_node *np, + struct device_node *interrupt_parent) +{ + void __iomem *icoll_base; + int i; + + icoll_priv.type = ASM9260_ICOLL; + + icoll_base = icoll_init_iobase(np); + icoll_priv.vector = icoll_base + ASM9260_HW_ICOLL_VECTOR; + icoll_priv.levelack = icoll_base + ASM9260_HW_ICOLL_LEVELACK; + icoll_priv.ctrl = icoll_base + ASM9260_HW_ICOLL_CTRL; + icoll_priv.stat = icoll_base + ASM9260_HW_ICOLL_STAT_OFFSET; + icoll_priv.intr = icoll_base + ASM9260_HW_ICOLL_INTERRUPT0; + icoll_priv.intr_per_reg = 4; + icoll_priv.clear = icoll_base + ASM9260_HW_ICOLL_CLEAR0; + + writel_relaxed(ASM9260_BM_CTRL_IRQ_ENABLE, + icoll_priv.ctrl); + /* + * ASM9260 don't provide reset bit. So, we need to set level 0 + * manually. + */ + for (i = 0; i < 16 * 0x10; i += 0x10) + writel(0, icoll_priv.intr + i); + + icoll_add_domain(np, ASM9260_NUM_IRQS); + + return icoll_domain ? 0 : -ENODEV; +} +IRQCHIP_DECLARE(asm9260, "alphascale,asm9260-icoll", asm9260_of_init); -- 2.5.0