162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2001, 2007-2008 MontaVista Software Inc. 362306a36Sopenharmony_ci * Author: MontaVista Software, Inc. <source@mvista.com> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 862306a36Sopenharmony_ci * under the terms of the GNU General Public License as published by the 962306a36Sopenharmony_ci * Free Software Foundation; either version 2 of the License, or (at your 1062306a36Sopenharmony_ci * option) any later version. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 1362306a36Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1462306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 1562306a36Sopenharmony_ci * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1662306a36Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1762306a36Sopenharmony_ci * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 1862306a36Sopenharmony_ci * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 1962306a36Sopenharmony_ci * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2062306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2162306a36Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License along 2462306a36Sopenharmony_ci * with this program; if not, write to the Free Software Foundation, Inc., 2562306a36Sopenharmony_ci * 675 Mass Ave, Cambridge, MA 02139, USA. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/export.h> 2962306a36Sopenharmony_ci#include <linux/init.h> 3062306a36Sopenharmony_ci#include <linux/interrupt.h> 3162306a36Sopenharmony_ci#include <linux/slab.h> 3262306a36Sopenharmony_ci#include <linux/syscore_ops.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <asm/irq_cpu.h> 3562306a36Sopenharmony_ci#include <asm/mach-au1x00/au1000.h> 3662306a36Sopenharmony_ci#include <asm/mach-au1x00/gpio-au1300.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* Interrupt Controller register offsets */ 3962306a36Sopenharmony_ci#define IC_CFG0RD 0x40 4062306a36Sopenharmony_ci#define IC_CFG0SET 0x40 4162306a36Sopenharmony_ci#define IC_CFG0CLR 0x44 4262306a36Sopenharmony_ci#define IC_CFG1RD 0x48 4362306a36Sopenharmony_ci#define IC_CFG1SET 0x48 4462306a36Sopenharmony_ci#define IC_CFG1CLR 0x4C 4562306a36Sopenharmony_ci#define IC_CFG2RD 0x50 4662306a36Sopenharmony_ci#define IC_CFG2SET 0x50 4762306a36Sopenharmony_ci#define IC_CFG2CLR 0x54 4862306a36Sopenharmony_ci#define IC_REQ0INT 0x54 4962306a36Sopenharmony_ci#define IC_SRCRD 0x58 5062306a36Sopenharmony_ci#define IC_SRCSET 0x58 5162306a36Sopenharmony_ci#define IC_SRCCLR 0x5C 5262306a36Sopenharmony_ci#define IC_REQ1INT 0x5C 5362306a36Sopenharmony_ci#define IC_ASSIGNRD 0x60 5462306a36Sopenharmony_ci#define IC_ASSIGNSET 0x60 5562306a36Sopenharmony_ci#define IC_ASSIGNCLR 0x64 5662306a36Sopenharmony_ci#define IC_WAKERD 0x68 5762306a36Sopenharmony_ci#define IC_WAKESET 0x68 5862306a36Sopenharmony_ci#define IC_WAKECLR 0x6C 5962306a36Sopenharmony_ci#define IC_MASKRD 0x70 6062306a36Sopenharmony_ci#define IC_MASKSET 0x70 6162306a36Sopenharmony_ci#define IC_MASKCLR 0x74 6262306a36Sopenharmony_ci#define IC_RISINGRD 0x78 6362306a36Sopenharmony_ci#define IC_RISINGCLR 0x78 6462306a36Sopenharmony_ci#define IC_FALLINGRD 0x7C 6562306a36Sopenharmony_ci#define IC_FALLINGCLR 0x7C 6662306a36Sopenharmony_ci#define IC_TESTBIT 0x80 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* per-processor fixed function irqs */ 6962306a36Sopenharmony_cistruct alchemy_irqmap { 7062306a36Sopenharmony_ci int irq; /* linux IRQ number */ 7162306a36Sopenharmony_ci int type; /* IRQ_TYPE_ */ 7262306a36Sopenharmony_ci int prio; /* irq priority, 0 highest, 3 lowest */ 7362306a36Sopenharmony_ci int internal; /* GPIC: internal source (no ext. pin)? */ 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int au1x_ic_settype(struct irq_data *d, unsigned int type); 7762306a36Sopenharmony_cistatic int au1300_gpic_settype(struct irq_data *d, unsigned int type); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* NOTE on interrupt priorities: The original writers of this code said: 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * Because of the tight timing of SETUP token to reply transactions, 8362306a36Sopenharmony_ci * the USB devices-side packet complete interrupt (USB_DEV_REQ_INT) 8462306a36Sopenharmony_ci * needs the highest priority. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistruct alchemy_irqmap au1000_irqmap[] __initdata = { 8762306a36Sopenharmony_ci { AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 8862306a36Sopenharmony_ci { AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 8962306a36Sopenharmony_ci { AU1000_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9062306a36Sopenharmony_ci { AU1000_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9162306a36Sopenharmony_ci { AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9262306a36Sopenharmony_ci { AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9362306a36Sopenharmony_ci { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9462306a36Sopenharmony_ci { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9562306a36Sopenharmony_ci { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9662306a36Sopenharmony_ci { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9762306a36Sopenharmony_ci { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9862306a36Sopenharmony_ci { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 9962306a36Sopenharmony_ci { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 10062306a36Sopenharmony_ci { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 10162306a36Sopenharmony_ci { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 10262306a36Sopenharmony_ci { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 10362306a36Sopenharmony_ci { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 10462306a36Sopenharmony_ci { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 10562306a36Sopenharmony_ci { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 10662306a36Sopenharmony_ci { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 10762306a36Sopenharmony_ci { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 10862306a36Sopenharmony_ci { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, 10962306a36Sopenharmony_ci { AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 11062306a36Sopenharmony_ci { AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 11162306a36Sopenharmony_ci { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, 11262306a36Sopenharmony_ci { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 11362306a36Sopenharmony_ci { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 11462306a36Sopenharmony_ci { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 11562306a36Sopenharmony_ci { AU1000_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 11662306a36Sopenharmony_ci { AU1000_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 11762306a36Sopenharmony_ci { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 11862306a36Sopenharmony_ci { -1, }, 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistruct alchemy_irqmap au1500_irqmap[] __initdata = { 12262306a36Sopenharmony_ci { AU1500_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 12362306a36Sopenharmony_ci { AU1500_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 12462306a36Sopenharmony_ci { AU1500_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 12562306a36Sopenharmony_ci { AU1500_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 12662306a36Sopenharmony_ci { AU1500_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 12762306a36Sopenharmony_ci { AU1500_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 12862306a36Sopenharmony_ci { AU1500_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 12962306a36Sopenharmony_ci { AU1500_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 13062306a36Sopenharmony_ci { AU1500_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 13162306a36Sopenharmony_ci { AU1500_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 13262306a36Sopenharmony_ci { AU1500_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 13362306a36Sopenharmony_ci { AU1500_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 13462306a36Sopenharmony_ci { AU1500_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 13562306a36Sopenharmony_ci { AU1500_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 13662306a36Sopenharmony_ci { AU1500_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 13762306a36Sopenharmony_ci { AU1500_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 13862306a36Sopenharmony_ci { AU1500_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 13962306a36Sopenharmony_ci { AU1500_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 14062306a36Sopenharmony_ci { AU1500_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 14162306a36Sopenharmony_ci { AU1500_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 14262306a36Sopenharmony_ci { AU1500_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 14362306a36Sopenharmony_ci { AU1500_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, 14462306a36Sopenharmony_ci { AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, 14562306a36Sopenharmony_ci { AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 14662306a36Sopenharmony_ci { AU1500_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 14762306a36Sopenharmony_ci { AU1500_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 14862306a36Sopenharmony_ci { AU1500_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 14962306a36Sopenharmony_ci { AU1500_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 15062306a36Sopenharmony_ci { AU1500_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 15162306a36Sopenharmony_ci { -1, }, 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistruct alchemy_irqmap au1100_irqmap[] __initdata = { 15562306a36Sopenharmony_ci { AU1100_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 15662306a36Sopenharmony_ci { AU1100_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 15762306a36Sopenharmony_ci { AU1100_SD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 15862306a36Sopenharmony_ci { AU1100_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 15962306a36Sopenharmony_ci { AU1100_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16062306a36Sopenharmony_ci { AU1100_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16162306a36Sopenharmony_ci { AU1100_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16262306a36Sopenharmony_ci { AU1100_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16362306a36Sopenharmony_ci { AU1100_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16462306a36Sopenharmony_ci { AU1100_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16562306a36Sopenharmony_ci { AU1100_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16662306a36Sopenharmony_ci { AU1100_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16762306a36Sopenharmony_ci { AU1100_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16862306a36Sopenharmony_ci { AU1100_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 16962306a36Sopenharmony_ci { AU1100_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 17062306a36Sopenharmony_ci { AU1100_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 17162306a36Sopenharmony_ci { AU1100_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 17262306a36Sopenharmony_ci { AU1100_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 17362306a36Sopenharmony_ci { AU1100_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 17462306a36Sopenharmony_ci { AU1100_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 17562306a36Sopenharmony_ci { AU1100_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 17662306a36Sopenharmony_ci { AU1100_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, 17762306a36Sopenharmony_ci { AU1100_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 17862306a36Sopenharmony_ci { AU1100_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 17962306a36Sopenharmony_ci { AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, 18062306a36Sopenharmony_ci { AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 18162306a36Sopenharmony_ci { AU1100_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 18262306a36Sopenharmony_ci { AU1100_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 18362306a36Sopenharmony_ci { AU1100_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 18462306a36Sopenharmony_ci { AU1100_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 18562306a36Sopenharmony_ci { AU1100_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 18662306a36Sopenharmony_ci { -1, }, 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistruct alchemy_irqmap au1550_irqmap[] __initdata = { 19062306a36Sopenharmony_ci { AU1550_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 19162306a36Sopenharmony_ci { AU1550_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 19262306a36Sopenharmony_ci { AU1550_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 19362306a36Sopenharmony_ci { AU1550_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 19462306a36Sopenharmony_ci { AU1550_CRYPTO_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 19562306a36Sopenharmony_ci { AU1550_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 19662306a36Sopenharmony_ci { AU1550_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 19762306a36Sopenharmony_ci { AU1550_PCI_RST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 19862306a36Sopenharmony_ci { AU1550_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 19962306a36Sopenharmony_ci { AU1550_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 20062306a36Sopenharmony_ci { AU1550_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 20162306a36Sopenharmony_ci { AU1550_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 20262306a36Sopenharmony_ci { AU1550_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 20362306a36Sopenharmony_ci { AU1550_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 20462306a36Sopenharmony_ci { AU1550_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 20562306a36Sopenharmony_ci { AU1550_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 20662306a36Sopenharmony_ci { AU1550_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 20762306a36Sopenharmony_ci { AU1550_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 20862306a36Sopenharmony_ci { AU1550_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 20962306a36Sopenharmony_ci { AU1550_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 21062306a36Sopenharmony_ci { AU1550_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 21162306a36Sopenharmony_ci { AU1550_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, 21262306a36Sopenharmony_ci { AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 21362306a36Sopenharmony_ci { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, 21462306a36Sopenharmony_ci { AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 21562306a36Sopenharmony_ci { AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, 21662306a36Sopenharmony_ci { AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 21762306a36Sopenharmony_ci { AU1550_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 21862306a36Sopenharmony_ci { -1, }, 21962306a36Sopenharmony_ci}; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistruct alchemy_irqmap au1200_irqmap[] __initdata = { 22262306a36Sopenharmony_ci { AU1200_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 22362306a36Sopenharmony_ci { AU1200_SWT_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 22462306a36Sopenharmony_ci { AU1200_SD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 22562306a36Sopenharmony_ci { AU1200_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 22662306a36Sopenharmony_ci { AU1200_MAE_BE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 22762306a36Sopenharmony_ci { AU1200_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 22862306a36Sopenharmony_ci { AU1200_MAE_FE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 22962306a36Sopenharmony_ci { AU1200_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 23062306a36Sopenharmony_ci { AU1200_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 23162306a36Sopenharmony_ci { AU1200_AES_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 23262306a36Sopenharmony_ci { AU1200_CAMERA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 23362306a36Sopenharmony_ci { AU1200_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 23462306a36Sopenharmony_ci { AU1200_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 23562306a36Sopenharmony_ci { AU1200_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 23662306a36Sopenharmony_ci { AU1200_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 23762306a36Sopenharmony_ci { AU1200_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 23862306a36Sopenharmony_ci { AU1200_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 23962306a36Sopenharmony_ci { AU1200_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 24062306a36Sopenharmony_ci { AU1200_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, 24162306a36Sopenharmony_ci { AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, 24262306a36Sopenharmony_ci { AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 24362306a36Sopenharmony_ci { AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 24462306a36Sopenharmony_ci { AU1200_MAE_BOTH_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, 24562306a36Sopenharmony_ci { -1, }, 24662306a36Sopenharmony_ci}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic struct alchemy_irqmap au1300_irqmap[] __initdata = { 24962306a36Sopenharmony_ci /* multifunction: gpio pin or device */ 25062306a36Sopenharmony_ci { AU1300_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25162306a36Sopenharmony_ci { AU1300_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25262306a36Sopenharmony_ci { AU1300_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25362306a36Sopenharmony_ci { AU1300_SD1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25462306a36Sopenharmony_ci { AU1300_SD2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25562306a36Sopenharmony_ci { AU1300_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25662306a36Sopenharmony_ci { AU1300_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25762306a36Sopenharmony_ci { AU1300_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25862306a36Sopenharmony_ci { AU1300_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 25962306a36Sopenharmony_ci { AU1300_NAND_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, 26062306a36Sopenharmony_ci /* au1300 internal */ 26162306a36Sopenharmony_ci { AU1300_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 26262306a36Sopenharmony_ci { AU1300_MMU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 26362306a36Sopenharmony_ci { AU1300_MPU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 26462306a36Sopenharmony_ci { AU1300_GPU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 26562306a36Sopenharmony_ci { AU1300_UDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 26662306a36Sopenharmony_ci { AU1300_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, 26762306a36Sopenharmony_ci { AU1300_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, 26862306a36Sopenharmony_ci { AU1300_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, 26962306a36Sopenharmony_ci { AU1300_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, 27062306a36Sopenharmony_ci { AU1300_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, 27162306a36Sopenharmony_ci { AU1300_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, 27262306a36Sopenharmony_ci { AU1300_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, 27362306a36Sopenharmony_ci { AU1300_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 1, }, 27462306a36Sopenharmony_ci { AU1300_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 27562306a36Sopenharmony_ci { AU1300_SD0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 27662306a36Sopenharmony_ci { AU1300_USB_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 27762306a36Sopenharmony_ci { AU1300_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 27862306a36Sopenharmony_ci { AU1300_BSA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 27962306a36Sopenharmony_ci { AU1300_MPE_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, 28062306a36Sopenharmony_ci { AU1300_ITE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 28162306a36Sopenharmony_ci { AU1300_AES_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 28262306a36Sopenharmony_ci { AU1300_CIM_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, 28362306a36Sopenharmony_ci { -1, }, /* terminator */ 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/******************************************************************************/ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic void au1x_ic0_unmask(struct irq_data *d) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; 29162306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_MASKSET); 29462306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_WAKESET); 29562306a36Sopenharmony_ci wmb(); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void au1x_ic1_unmask(struct irq_data *d) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; 30162306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_MASKSET); 30462306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_WAKESET); 30562306a36Sopenharmony_ci wmb(); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void au1x_ic0_mask(struct irq_data *d) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; 31162306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_MASKCLR); 31462306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_WAKECLR); 31562306a36Sopenharmony_ci wmb(); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic void au1x_ic1_mask(struct irq_data *d) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; 32162306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_MASKCLR); 32462306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_WAKECLR); 32562306a36Sopenharmony_ci wmb(); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic void au1x_ic0_ack(struct irq_data *d) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; 33162306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * This may assume that we don't get interrupts from 33562306a36Sopenharmony_ci * both edges at once, or if we do, that we don't care. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_FALLINGCLR); 33862306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_RISINGCLR); 33962306a36Sopenharmony_ci wmb(); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void au1x_ic1_ack(struct irq_data *d) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; 34562306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* 34862306a36Sopenharmony_ci * This may assume that we don't get interrupts from 34962306a36Sopenharmony_ci * both edges at once, or if we do, that we don't care. 35062306a36Sopenharmony_ci */ 35162306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_FALLINGCLR); 35262306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_RISINGCLR); 35362306a36Sopenharmony_ci wmb(); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void au1x_ic0_maskack(struct irq_data *d) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; 35962306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_WAKECLR); 36262306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_MASKCLR); 36362306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_RISINGCLR); 36462306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_FALLINGCLR); 36562306a36Sopenharmony_ci wmb(); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic void au1x_ic1_maskack(struct irq_data *d) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; 37162306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_WAKECLR); 37462306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_MASKCLR); 37562306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_RISINGCLR); 37662306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_FALLINGCLR); 37762306a36Sopenharmony_ci wmb(); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int au1x_ic1_setwake(struct irq_data *d, unsigned int on) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci int bit = d->irq - AU1000_INTC1_INT_BASE; 38362306a36Sopenharmony_ci unsigned long wakemsk, flags; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* only GPIO 0-7 can act as wakeup source. Fortunately these 38662306a36Sopenharmony_ci * are wired up identically on all supported variants. 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ci if ((bit < 0) || (bit > 7)) 38962306a36Sopenharmony_ci return -EINVAL; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci local_irq_save(flags); 39262306a36Sopenharmony_ci wakemsk = alchemy_rdsys(AU1000_SYS_WAKEMSK); 39362306a36Sopenharmony_ci if (on) 39462306a36Sopenharmony_ci wakemsk |= 1 << bit; 39562306a36Sopenharmony_ci else 39662306a36Sopenharmony_ci wakemsk &= ~(1 << bit); 39762306a36Sopenharmony_ci alchemy_wrsys(wakemsk, AU1000_SYS_WAKEMSK); 39862306a36Sopenharmony_ci local_irq_restore(flags); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/* 40462306a36Sopenharmony_ci * irq_chips for both ICs; this way the mask handlers can be 40562306a36Sopenharmony_ci * as short as possible. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_cistatic struct irq_chip au1x_ic0_chip = { 40862306a36Sopenharmony_ci .name = "Alchemy-IC0", 40962306a36Sopenharmony_ci .irq_ack = au1x_ic0_ack, 41062306a36Sopenharmony_ci .irq_mask = au1x_ic0_mask, 41162306a36Sopenharmony_ci .irq_mask_ack = au1x_ic0_maskack, 41262306a36Sopenharmony_ci .irq_unmask = au1x_ic0_unmask, 41362306a36Sopenharmony_ci .irq_set_type = au1x_ic_settype, 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic struct irq_chip au1x_ic1_chip = { 41762306a36Sopenharmony_ci .name = "Alchemy-IC1", 41862306a36Sopenharmony_ci .irq_ack = au1x_ic1_ack, 41962306a36Sopenharmony_ci .irq_mask = au1x_ic1_mask, 42062306a36Sopenharmony_ci .irq_mask_ack = au1x_ic1_maskack, 42162306a36Sopenharmony_ci .irq_unmask = au1x_ic1_unmask, 42262306a36Sopenharmony_ci .irq_set_type = au1x_ic_settype, 42362306a36Sopenharmony_ci .irq_set_wake = au1x_ic1_setwake, 42462306a36Sopenharmony_ci}; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct irq_chip *chip; 42962306a36Sopenharmony_ci unsigned int bit, irq = d->irq; 43062306a36Sopenharmony_ci irq_flow_handler_t handler = NULL; 43162306a36Sopenharmony_ci unsigned char *name = NULL; 43262306a36Sopenharmony_ci void __iomem *base; 43362306a36Sopenharmony_ci int ret; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (irq >= AU1000_INTC1_INT_BASE) { 43662306a36Sopenharmony_ci bit = irq - AU1000_INTC1_INT_BASE; 43762306a36Sopenharmony_ci chip = &au1x_ic1_chip; 43862306a36Sopenharmony_ci base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); 43962306a36Sopenharmony_ci } else { 44062306a36Sopenharmony_ci bit = irq - AU1000_INTC0_INT_BASE; 44162306a36Sopenharmony_ci chip = &au1x_ic0_chip; 44262306a36Sopenharmony_ci base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (bit > 31) 44662306a36Sopenharmony_ci return -EINVAL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci ret = 0; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci switch (flow_type) { /* cfgregs 2:1:0 */ 45162306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: /* 0:0:1 */ 45262306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG2CLR); 45362306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG1CLR); 45462306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG0SET); 45562306a36Sopenharmony_ci handler = handle_edge_irq; 45662306a36Sopenharmony_ci name = "riseedge"; 45762306a36Sopenharmony_ci break; 45862306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */ 45962306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG2CLR); 46062306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG1SET); 46162306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG0CLR); 46262306a36Sopenharmony_ci handler = handle_edge_irq; 46362306a36Sopenharmony_ci name = "falledge"; 46462306a36Sopenharmony_ci break; 46562306a36Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */ 46662306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG2CLR); 46762306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG1SET); 46862306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG0SET); 46962306a36Sopenharmony_ci handler = handle_edge_irq; 47062306a36Sopenharmony_ci name = "bothedge"; 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */ 47362306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG2SET); 47462306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG1CLR); 47562306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG0SET); 47662306a36Sopenharmony_ci handler = handle_level_irq; 47762306a36Sopenharmony_ci name = "hilevel"; 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */ 48062306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG2SET); 48162306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG1SET); 48262306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG0CLR); 48362306a36Sopenharmony_ci handler = handle_level_irq; 48462306a36Sopenharmony_ci name = "lowlevel"; 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci case IRQ_TYPE_NONE: /* 0:0:0 */ 48762306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG2CLR); 48862306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG1CLR); 48962306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_CFG0CLR); 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci default: 49262306a36Sopenharmony_ci ret = -EINVAL; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci irq_set_chip_handler_name_locked(d, chip, handler, name); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci wmb(); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return ret; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/******************************************************************************/ 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/* 50462306a36Sopenharmony_ci * au1300_gpic_chgcfg - change PIN configuration. 50562306a36Sopenharmony_ci * @gpio: pin to change (0-based GPIO number from datasheet). 50662306a36Sopenharmony_ci * @clr: clear all bits set in 'clr'. 50762306a36Sopenharmony_ci * @set: set these bits. 50862306a36Sopenharmony_ci * 50962306a36Sopenharmony_ci * modifies a pins' configuration register, bits set in @clr will 51062306a36Sopenharmony_ci * be cleared in the register, bits in @set will be set. 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_cistatic inline void au1300_gpic_chgcfg(unsigned int gpio, 51362306a36Sopenharmony_ci unsigned long clr, 51462306a36Sopenharmony_ci unsigned long set) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci void __iomem *r = AU1300_GPIC_ADDR; 51762306a36Sopenharmony_ci unsigned long l; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci r += gpio * 4; /* offset into pin config array */ 52062306a36Sopenharmony_ci l = __raw_readl(r + AU1300_GPIC_PINCFG); 52162306a36Sopenharmony_ci l &= ~clr; 52262306a36Sopenharmony_ci l |= set; 52362306a36Sopenharmony_ci __raw_writel(l, r + AU1300_GPIC_PINCFG); 52462306a36Sopenharmony_ci wmb(); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/* 52862306a36Sopenharmony_ci * au1300_pinfunc_to_gpio - assign a pin as GPIO input (GPIO ctrl). 52962306a36Sopenharmony_ci * @pin: pin (0-based GPIO number from datasheet). 53062306a36Sopenharmony_ci * 53162306a36Sopenharmony_ci * Assigns a GPIO pin to the GPIO controller, so its level can either 53262306a36Sopenharmony_ci * be read or set through the generic GPIO functions. 53362306a36Sopenharmony_ci * If you need a GPOUT, use au1300_gpio_set_value(pin, 0/1). 53462306a36Sopenharmony_ci * REVISIT: is this function really necessary? 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_civoid au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci au1300_gpio_direction_input(gpio + AU1300_GPIO_BASE); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(au1300_pinfunc_to_gpio); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci * au1300_pinfunc_to_dev - assign a pin to the device function. 54462306a36Sopenharmony_ci * @pin: pin (0-based GPIO number from datasheet). 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * Assigns a GPIO pin to its associated device function; the pin will be 54762306a36Sopenharmony_ci * driven by the device and not through GPIO functions. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_civoid au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci void __iomem *r = AU1300_GPIC_ADDR; 55262306a36Sopenharmony_ci unsigned long bit; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci r += GPIC_GPIO_BANKOFF(gpio); 55562306a36Sopenharmony_ci bit = GPIC_GPIO_TO_BIT(gpio); 55662306a36Sopenharmony_ci __raw_writel(bit, r + AU1300_GPIC_DEVSEL); 55762306a36Sopenharmony_ci wmb(); 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(au1300_pinfunc_to_dev); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci/* 56262306a36Sopenharmony_ci * au1300_set_irq_priority - set internal priority of IRQ. 56362306a36Sopenharmony_ci * @irq: irq to set priority (linux irq number). 56462306a36Sopenharmony_ci * @p: priority (0 = highest, 3 = lowest). 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_civoid au1300_set_irq_priority(unsigned int irq, int p) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci irq -= ALCHEMY_GPIC_INT_BASE; 56962306a36Sopenharmony_ci au1300_gpic_chgcfg(irq, GPIC_CFG_IL_MASK, GPIC_CFG_IL_SET(p)); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(au1300_set_irq_priority); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/* 57462306a36Sopenharmony_ci * au1300_set_dbdma_gpio - assign a gpio to one of the DBDMA triggers. 57562306a36Sopenharmony_ci * @dchan: dbdma trigger select (0, 1). 57662306a36Sopenharmony_ci * @gpio: pin to assign as trigger. 57762306a36Sopenharmony_ci * 57862306a36Sopenharmony_ci * DBDMA controller has 2 external trigger sources; this function 57962306a36Sopenharmony_ci * assigns a GPIO to the selected trigger. 58062306a36Sopenharmony_ci */ 58162306a36Sopenharmony_civoid au1300_set_dbdma_gpio(int dchan, unsigned int gpio) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci unsigned long r; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if ((dchan >= 0) && (dchan <= 1)) { 58662306a36Sopenharmony_ci r = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL); 58762306a36Sopenharmony_ci r &= ~(0xff << (8 * dchan)); 58862306a36Sopenharmony_ci r |= (gpio & 0x7f) << (8 * dchan); 58962306a36Sopenharmony_ci __raw_writel(r, AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL); 59062306a36Sopenharmony_ci wmb(); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic inline void gpic_pin_set_idlewake(unsigned int gpio, int allow) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci au1300_gpic_chgcfg(gpio, GPIC_CFG_IDLEWAKE, 59762306a36Sopenharmony_ci allow ? GPIC_CFG_IDLEWAKE : 0); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic void au1300_gpic_mask(struct irq_data *d) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci void __iomem *r = AU1300_GPIC_ADDR; 60362306a36Sopenharmony_ci unsigned long bit, irq = d->irq; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci irq -= ALCHEMY_GPIC_INT_BASE; 60662306a36Sopenharmony_ci r += GPIC_GPIO_BANKOFF(irq); 60762306a36Sopenharmony_ci bit = GPIC_GPIO_TO_BIT(irq); 60862306a36Sopenharmony_ci __raw_writel(bit, r + AU1300_GPIC_IDIS); 60962306a36Sopenharmony_ci wmb(); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci gpic_pin_set_idlewake(irq, 0); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic void au1300_gpic_unmask(struct irq_data *d) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci void __iomem *r = AU1300_GPIC_ADDR; 61762306a36Sopenharmony_ci unsigned long bit, irq = d->irq; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci irq -= ALCHEMY_GPIC_INT_BASE; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci gpic_pin_set_idlewake(irq, 1); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci r += GPIC_GPIO_BANKOFF(irq); 62462306a36Sopenharmony_ci bit = GPIC_GPIO_TO_BIT(irq); 62562306a36Sopenharmony_ci __raw_writel(bit, r + AU1300_GPIC_IEN); 62662306a36Sopenharmony_ci wmb(); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic void au1300_gpic_maskack(struct irq_data *d) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci void __iomem *r = AU1300_GPIC_ADDR; 63262306a36Sopenharmony_ci unsigned long bit, irq = d->irq; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci irq -= ALCHEMY_GPIC_INT_BASE; 63562306a36Sopenharmony_ci r += GPIC_GPIO_BANKOFF(irq); 63662306a36Sopenharmony_ci bit = GPIC_GPIO_TO_BIT(irq); 63762306a36Sopenharmony_ci __raw_writel(bit, r + AU1300_GPIC_IPEND); /* ack */ 63862306a36Sopenharmony_ci __raw_writel(bit, r + AU1300_GPIC_IDIS); /* mask */ 63962306a36Sopenharmony_ci wmb(); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci gpic_pin_set_idlewake(irq, 0); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic void au1300_gpic_ack(struct irq_data *d) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci void __iomem *r = AU1300_GPIC_ADDR; 64762306a36Sopenharmony_ci unsigned long bit, irq = d->irq; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci irq -= ALCHEMY_GPIC_INT_BASE; 65062306a36Sopenharmony_ci r += GPIC_GPIO_BANKOFF(irq); 65162306a36Sopenharmony_ci bit = GPIC_GPIO_TO_BIT(irq); 65262306a36Sopenharmony_ci __raw_writel(bit, r + AU1300_GPIC_IPEND); /* ack */ 65362306a36Sopenharmony_ci wmb(); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic struct irq_chip au1300_gpic = { 65762306a36Sopenharmony_ci .name = "GPIOINT", 65862306a36Sopenharmony_ci .irq_ack = au1300_gpic_ack, 65962306a36Sopenharmony_ci .irq_mask = au1300_gpic_mask, 66062306a36Sopenharmony_ci .irq_mask_ack = au1300_gpic_maskack, 66162306a36Sopenharmony_ci .irq_unmask = au1300_gpic_unmask, 66262306a36Sopenharmony_ci .irq_set_type = au1300_gpic_settype, 66362306a36Sopenharmony_ci}; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int au1300_gpic_settype(struct irq_data *d, unsigned int type) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci unsigned long s; 66862306a36Sopenharmony_ci unsigned char *name = NULL; 66962306a36Sopenharmony_ci irq_flow_handler_t hdl = NULL; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci switch (type) { 67262306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 67362306a36Sopenharmony_ci s = GPIC_CFG_IC_LEVEL_HIGH; 67462306a36Sopenharmony_ci name = "high"; 67562306a36Sopenharmony_ci hdl = handle_level_irq; 67662306a36Sopenharmony_ci break; 67762306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 67862306a36Sopenharmony_ci s = GPIC_CFG_IC_LEVEL_LOW; 67962306a36Sopenharmony_ci name = "low"; 68062306a36Sopenharmony_ci hdl = handle_level_irq; 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 68362306a36Sopenharmony_ci s = GPIC_CFG_IC_EDGE_RISE; 68462306a36Sopenharmony_ci name = "posedge"; 68562306a36Sopenharmony_ci hdl = handle_edge_irq; 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 68862306a36Sopenharmony_ci s = GPIC_CFG_IC_EDGE_FALL; 68962306a36Sopenharmony_ci name = "negedge"; 69062306a36Sopenharmony_ci hdl = handle_edge_irq; 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 69362306a36Sopenharmony_ci s = GPIC_CFG_IC_EDGE_BOTH; 69462306a36Sopenharmony_ci name = "bothedge"; 69562306a36Sopenharmony_ci hdl = handle_edge_irq; 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci case IRQ_TYPE_NONE: 69862306a36Sopenharmony_ci s = GPIC_CFG_IC_OFF; 69962306a36Sopenharmony_ci name = "disabled"; 70062306a36Sopenharmony_ci hdl = handle_level_irq; 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci default: 70362306a36Sopenharmony_ci return -EINVAL; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci irq_set_chip_handler_name_locked(d, &au1300_gpic, hdl, name); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci/******************************************************************************/ 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic inline void ic_init(void __iomem *base) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci /* initialize interrupt controller to a safe state */ 71862306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_CFG0CLR); 71962306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_CFG1CLR); 72062306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_CFG2CLR); 72162306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_MASKCLR); 72262306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_ASSIGNCLR); 72362306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_WAKECLR); 72462306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_SRCSET); 72562306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_FALLINGCLR); 72662306a36Sopenharmony_ci __raw_writel(0xffffffff, base + IC_RISINGCLR); 72762306a36Sopenharmony_ci __raw_writel(0x00000000, base + IC_TESTBIT); 72862306a36Sopenharmony_ci wmb(); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic unsigned long alchemy_gpic_pmdata[ALCHEMY_GPIC_INT_NUM + 6]; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci d[0] = __raw_readl(base + IC_CFG0RD); 73662306a36Sopenharmony_ci d[1] = __raw_readl(base + IC_CFG1RD); 73762306a36Sopenharmony_ci d[2] = __raw_readl(base + IC_CFG2RD); 73862306a36Sopenharmony_ci d[3] = __raw_readl(base + IC_SRCRD); 73962306a36Sopenharmony_ci d[4] = __raw_readl(base + IC_ASSIGNRD); 74062306a36Sopenharmony_ci d[5] = __raw_readl(base + IC_WAKERD); 74162306a36Sopenharmony_ci d[6] = __raw_readl(base + IC_MASKRD); 74262306a36Sopenharmony_ci ic_init(base); /* shut it up too while at it */ 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci ic_init(base); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci __raw_writel(d[0], base + IC_CFG0SET); 75062306a36Sopenharmony_ci __raw_writel(d[1], base + IC_CFG1SET); 75162306a36Sopenharmony_ci __raw_writel(d[2], base + IC_CFG2SET); 75262306a36Sopenharmony_ci __raw_writel(d[3], base + IC_SRCSET); 75362306a36Sopenharmony_ci __raw_writel(d[4], base + IC_ASSIGNSET); 75462306a36Sopenharmony_ci __raw_writel(d[5], base + IC_WAKESET); 75562306a36Sopenharmony_ci wmb(); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci __raw_writel(d[6], base + IC_MASKSET); 75862306a36Sopenharmony_ci wmb(); 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic int alchemy_ic_suspend(void) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), 76462306a36Sopenharmony_ci alchemy_gpic_pmdata); 76562306a36Sopenharmony_ci alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), 76662306a36Sopenharmony_ci &alchemy_gpic_pmdata[7]); 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic void alchemy_ic_resume(void) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), 77362306a36Sopenharmony_ci &alchemy_gpic_pmdata[7]); 77462306a36Sopenharmony_ci alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), 77562306a36Sopenharmony_ci alchemy_gpic_pmdata); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic int alchemy_gpic_suspend(void) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); 78162306a36Sopenharmony_ci int i; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* save 4 interrupt mask status registers */ 78462306a36Sopenharmony_ci alchemy_gpic_pmdata[0] = __raw_readl(base + AU1300_GPIC_IEN + 0x0); 78562306a36Sopenharmony_ci alchemy_gpic_pmdata[1] = __raw_readl(base + AU1300_GPIC_IEN + 0x4); 78662306a36Sopenharmony_ci alchemy_gpic_pmdata[2] = __raw_readl(base + AU1300_GPIC_IEN + 0x8); 78762306a36Sopenharmony_ci alchemy_gpic_pmdata[3] = __raw_readl(base + AU1300_GPIC_IEN + 0xc); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* save misc register(s) */ 79062306a36Sopenharmony_ci alchemy_gpic_pmdata[4] = __raw_readl(base + AU1300_GPIC_DMASEL); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* molto silenzioso */ 79362306a36Sopenharmony_ci __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0); 79462306a36Sopenharmony_ci __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4); 79562306a36Sopenharmony_ci __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8); 79662306a36Sopenharmony_ci __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc); 79762306a36Sopenharmony_ci wmb(); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* save pin/int-type configuration */ 80062306a36Sopenharmony_ci base += AU1300_GPIC_PINCFG; 80162306a36Sopenharmony_ci for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++) 80262306a36Sopenharmony_ci alchemy_gpic_pmdata[i + 5] = __raw_readl(base + (i << 2)); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci wmb(); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci return 0; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic void alchemy_gpic_resume(void) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); 81262306a36Sopenharmony_ci int i; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* disable all first */ 81562306a36Sopenharmony_ci __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0); 81662306a36Sopenharmony_ci __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4); 81762306a36Sopenharmony_ci __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8); 81862306a36Sopenharmony_ci __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc); 81962306a36Sopenharmony_ci wmb(); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* restore pin/int-type configurations */ 82262306a36Sopenharmony_ci base += AU1300_GPIC_PINCFG; 82362306a36Sopenharmony_ci for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++) 82462306a36Sopenharmony_ci __raw_writel(alchemy_gpic_pmdata[i + 5], base + (i << 2)); 82562306a36Sopenharmony_ci wmb(); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* restore misc register(s) */ 82862306a36Sopenharmony_ci base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); 82962306a36Sopenharmony_ci __raw_writel(alchemy_gpic_pmdata[4], base + AU1300_GPIC_DMASEL); 83062306a36Sopenharmony_ci wmb(); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci /* finally restore masks */ 83362306a36Sopenharmony_ci __raw_writel(alchemy_gpic_pmdata[0], base + AU1300_GPIC_IEN + 0x0); 83462306a36Sopenharmony_ci __raw_writel(alchemy_gpic_pmdata[1], base + AU1300_GPIC_IEN + 0x4); 83562306a36Sopenharmony_ci __raw_writel(alchemy_gpic_pmdata[2], base + AU1300_GPIC_IEN + 0x8); 83662306a36Sopenharmony_ci __raw_writel(alchemy_gpic_pmdata[3], base + AU1300_GPIC_IEN + 0xc); 83762306a36Sopenharmony_ci wmb(); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic struct syscore_ops alchemy_ic_pmops = { 84162306a36Sopenharmony_ci .suspend = alchemy_ic_suspend, 84262306a36Sopenharmony_ci .resume = alchemy_ic_resume, 84362306a36Sopenharmony_ci}; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic struct syscore_ops alchemy_gpic_pmops = { 84662306a36Sopenharmony_ci .suspend = alchemy_gpic_suspend, 84762306a36Sopenharmony_ci .resume = alchemy_gpic_resume, 84862306a36Sopenharmony_ci}; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/******************************************************************************/ 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci/* create chained handlers for the 4 IC requests to the MIPS IRQ ctrl */ 85362306a36Sopenharmony_ci#define DISP(name, base, addr) \ 85462306a36Sopenharmony_cistatic void au1000_##name##_dispatch(struct irq_desc *d) \ 85562306a36Sopenharmony_ci{ \ 85662306a36Sopenharmony_ci unsigned long r = __raw_readl((void __iomem *)KSEG1ADDR(addr)); \ 85762306a36Sopenharmony_ci if (likely(r)) \ 85862306a36Sopenharmony_ci generic_handle_irq(base + __ffs(r)); \ 85962306a36Sopenharmony_ci else \ 86062306a36Sopenharmony_ci spurious_interrupt(); \ 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ciDISP(ic0r0, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ0INT) 86462306a36Sopenharmony_ciDISP(ic0r1, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ1INT) 86562306a36Sopenharmony_ciDISP(ic1r0, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ0INT) 86662306a36Sopenharmony_ciDISP(ic1r1, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ1INT) 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic void alchemy_gpic_dispatch(struct irq_desc *d) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci int i = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_PRIENC); 87162306a36Sopenharmony_ci generic_handle_irq(ALCHEMY_GPIC_INT_BASE + i); 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci/******************************************************************************/ 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic void __init au1000_init_irq(struct alchemy_irqmap *map) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci unsigned int bit, irq_nr; 87962306a36Sopenharmony_ci void __iomem *base; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR)); 88262306a36Sopenharmony_ci ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR)); 88362306a36Sopenharmony_ci register_syscore_ops(&alchemy_ic_pmops); 88462306a36Sopenharmony_ci mips_cpu_irq_init(); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* register all 64 possible IC0+IC1 irq sources as type "none". 88762306a36Sopenharmony_ci * Use set_irq_type() to set edge/level behaviour at runtime. 88862306a36Sopenharmony_ci */ 88962306a36Sopenharmony_ci for (irq_nr = AU1000_INTC0_INT_BASE; 89062306a36Sopenharmony_ci (irq_nr < AU1000_INTC0_INT_BASE + 32); irq_nr++) 89162306a36Sopenharmony_ci au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci for (irq_nr = AU1000_INTC1_INT_BASE; 89462306a36Sopenharmony_ci (irq_nr < AU1000_INTC1_INT_BASE + 32); irq_nr++) 89562306a36Sopenharmony_ci au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* 89862306a36Sopenharmony_ci * Initialize IC0, which is fixed per processor. 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_ci while (map->irq != -1) { 90162306a36Sopenharmony_ci irq_nr = map->irq; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (irq_nr >= AU1000_INTC1_INT_BASE) { 90462306a36Sopenharmony_ci bit = irq_nr - AU1000_INTC1_INT_BASE; 90562306a36Sopenharmony_ci base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); 90662306a36Sopenharmony_ci } else { 90762306a36Sopenharmony_ci bit = irq_nr - AU1000_INTC0_INT_BASE; 90862306a36Sopenharmony_ci base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci if (map->prio == 0) 91162306a36Sopenharmony_ci __raw_writel(1 << bit, base + IC_ASSIGNSET); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci au1x_ic_settype(irq_get_irq_data(irq_nr), map->type); 91462306a36Sopenharmony_ci ++map; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, au1000_ic0r0_dispatch); 91862306a36Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, au1000_ic0r1_dispatch); 91962306a36Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, au1000_ic1r0_dispatch); 92062306a36Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, au1000_ic1r1_dispatch); 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic void __init alchemy_gpic_init_irq(const struct alchemy_irqmap *dints) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci int i; 92662306a36Sopenharmony_ci void __iomem *bank_base; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci register_syscore_ops(&alchemy_gpic_pmops); 92962306a36Sopenharmony_ci mips_cpu_irq_init(); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* disable & ack all possible interrupt sources */ 93262306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 93362306a36Sopenharmony_ci bank_base = AU1300_GPIC_ADDR + (i * 4); 93462306a36Sopenharmony_ci __raw_writel(~0UL, bank_base + AU1300_GPIC_IDIS); 93562306a36Sopenharmony_ci wmb(); 93662306a36Sopenharmony_ci __raw_writel(~0UL, bank_base + AU1300_GPIC_IPEND); 93762306a36Sopenharmony_ci wmb(); 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci /* register an irq_chip for them, with 2nd highest priority */ 94162306a36Sopenharmony_ci for (i = ALCHEMY_GPIC_INT_BASE; i <= ALCHEMY_GPIC_INT_LAST; i++) { 94262306a36Sopenharmony_ci au1300_set_irq_priority(i, 1); 94362306a36Sopenharmony_ci au1300_gpic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* setup known on-chip sources */ 94762306a36Sopenharmony_ci while ((i = dints->irq) != -1) { 94862306a36Sopenharmony_ci au1300_gpic_settype(irq_get_irq_data(i), dints->type); 94962306a36Sopenharmony_ci au1300_set_irq_priority(i, dints->prio); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (dints->internal) 95262306a36Sopenharmony_ci au1300_pinfunc_to_dev(i - ALCHEMY_GPIC_INT_BASE); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci dints++; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, alchemy_gpic_dispatch); 95862306a36Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, alchemy_gpic_dispatch); 95962306a36Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, alchemy_gpic_dispatch); 96062306a36Sopenharmony_ci irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, alchemy_gpic_dispatch); 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci/******************************************************************************/ 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_civoid __init arch_init_irq(void) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci switch (alchemy_get_cputype()) { 96862306a36Sopenharmony_ci case ALCHEMY_CPU_AU1000: 96962306a36Sopenharmony_ci au1000_init_irq(au1000_irqmap); 97062306a36Sopenharmony_ci break; 97162306a36Sopenharmony_ci case ALCHEMY_CPU_AU1500: 97262306a36Sopenharmony_ci au1000_init_irq(au1500_irqmap); 97362306a36Sopenharmony_ci break; 97462306a36Sopenharmony_ci case ALCHEMY_CPU_AU1100: 97562306a36Sopenharmony_ci au1000_init_irq(au1100_irqmap); 97662306a36Sopenharmony_ci break; 97762306a36Sopenharmony_ci case ALCHEMY_CPU_AU1550: 97862306a36Sopenharmony_ci au1000_init_irq(au1550_irqmap); 97962306a36Sopenharmony_ci break; 98062306a36Sopenharmony_ci case ALCHEMY_CPU_AU1200: 98162306a36Sopenharmony_ci au1000_init_irq(au1200_irqmap); 98262306a36Sopenharmony_ci break; 98362306a36Sopenharmony_ci case ALCHEMY_CPU_AU1300: 98462306a36Sopenharmony_ci alchemy_gpic_init_irq(au1300_irqmap); 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci default: 98762306a36Sopenharmony_ci pr_err("unknown Alchemy IRQ core\n"); 98862306a36Sopenharmony_ci break; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ciasmlinkage void plat_irq_dispatch(void) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci unsigned long r = (read_c0_status() & read_c0_cause()) >> 8; 99562306a36Sopenharmony_ci do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(r & 0xff)); 99662306a36Sopenharmony_ci} 997