162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/init.h> 362306a36Sopenharmony_ci#include <linux/list.h> 462306a36Sopenharmony_ci#include <linux/io.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <asm/mach/irq.h> 762306a36Sopenharmony_ci#include <asm/hardware/iomd.h> 862306a36Sopenharmony_ci#include <asm/irq.h> 962306a36Sopenharmony_ci#include <asm/fiq.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci// These are offsets from the stat register for each IRQ bank 1262306a36Sopenharmony_ci#define STAT 0x00 1362306a36Sopenharmony_ci#define REQ 0x04 1462306a36Sopenharmony_ci#define CLR 0x04 1562306a36Sopenharmony_ci#define MASK 0x08 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic const u8 irq_prio_h[256] = { 1862306a36Sopenharmony_ci 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10, 1962306a36Sopenharmony_ci 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10, 2062306a36Sopenharmony_ci 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 2162306a36Sopenharmony_ci 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 2262306a36Sopenharmony_ci 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10, 2362306a36Sopenharmony_ci 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10, 2462306a36Sopenharmony_ci 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 2562306a36Sopenharmony_ci 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 2662306a36Sopenharmony_ci 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10, 2762306a36Sopenharmony_ci 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10, 2862306a36Sopenharmony_ci 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 2962306a36Sopenharmony_ci 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 3062306a36Sopenharmony_ci 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10, 3162306a36Sopenharmony_ci 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10, 3262306a36Sopenharmony_ci 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 3362306a36Sopenharmony_ci 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10, 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic const u8 irq_prio_d[256] = { 3762306a36Sopenharmony_ci 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 3862306a36Sopenharmony_ci 20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 3962306a36Sopenharmony_ci 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4062306a36Sopenharmony_ci 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4162306a36Sopenharmony_ci 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4262306a36Sopenharmony_ci 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4362306a36Sopenharmony_ci 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4462306a36Sopenharmony_ci 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4562306a36Sopenharmony_ci 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4662306a36Sopenharmony_ci 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4762306a36Sopenharmony_ci 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4862306a36Sopenharmony_ci 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 4962306a36Sopenharmony_ci 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 5062306a36Sopenharmony_ci 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 5162306a36Sopenharmony_ci 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 5262306a36Sopenharmony_ci 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic const u8 irq_prio_l[256] = { 5662306a36Sopenharmony_ci 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5762306a36Sopenharmony_ci 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5862306a36Sopenharmony_ci 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5962306a36Sopenharmony_ci 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6062306a36Sopenharmony_ci 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 6162306a36Sopenharmony_ci 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 6262306a36Sopenharmony_ci 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6362306a36Sopenharmony_ci 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6462306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6562306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6662306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6762306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6862306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6962306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7062306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7162306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int iomd_get_irq_nr(void) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int irq; 7762306a36Sopenharmony_ci u8 reg; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* get highest priority first */ 8062306a36Sopenharmony_ci reg = readb(IOC_BASE + IOMD_IRQREQB); 8162306a36Sopenharmony_ci irq = irq_prio_h[reg]; 8262306a36Sopenharmony_ci if (irq) 8362306a36Sopenharmony_ci return irq; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* get DMA */ 8662306a36Sopenharmony_ci reg = readb(IOC_BASE + IOMD_DMAREQ); 8762306a36Sopenharmony_ci irq = irq_prio_d[reg]; 8862306a36Sopenharmony_ci if (irq) 8962306a36Sopenharmony_ci return irq; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* get low priority */ 9262306a36Sopenharmony_ci reg = readb(IOC_BASE + IOMD_IRQREQA); 9362306a36Sopenharmony_ci irq = irq_prio_l[reg]; 9462306a36Sopenharmony_ci if (irq) 9562306a36Sopenharmony_ci return irq; 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void iomd_handle_irq(struct pt_regs *regs) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci int irq; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci do { 10462306a36Sopenharmony_ci irq = iomd_get_irq_nr(); 10562306a36Sopenharmony_ci if (irq) 10662306a36Sopenharmony_ci generic_handle_irq(irq); 10762306a36Sopenharmony_ci } while (irq); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void __iomem *iomd_get_base(struct irq_data *d) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci void *cd = irq_data_get_irq_chip_data(d); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return (void __iomem *)(unsigned long)cd; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void iomd_set_base_mask(unsigned int irq, void __iomem *base, u32 mask) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct irq_data *d = irq_get_irq_data(irq); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci d->mask = mask; 12262306a36Sopenharmony_ci irq_set_chip_data(irq, (void *)(unsigned long)base); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void iomd_irq_mask_ack(struct irq_data *d) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci void __iomem *base = iomd_get_base(d); 12862306a36Sopenharmony_ci unsigned int val, mask = d->mask; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci val = readb(base + MASK); 13162306a36Sopenharmony_ci writeb(val & ~mask, base + MASK); 13262306a36Sopenharmony_ci writeb(mask, base + CLR); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void iomd_irq_mask(struct irq_data *d) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci void __iomem *base = iomd_get_base(d); 13862306a36Sopenharmony_ci unsigned int val, mask = d->mask; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci val = readb(base + MASK); 14162306a36Sopenharmony_ci writeb(val & ~mask, base + MASK); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void iomd_irq_unmask(struct irq_data *d) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci void __iomem *base = iomd_get_base(d); 14762306a36Sopenharmony_ci unsigned int val, mask = d->mask; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci val = readb(base + MASK); 15062306a36Sopenharmony_ci writeb(val | mask, base + MASK); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic struct irq_chip iomd_chip_clr = { 15462306a36Sopenharmony_ci .irq_mask_ack = iomd_irq_mask_ack, 15562306a36Sopenharmony_ci .irq_mask = iomd_irq_mask, 15662306a36Sopenharmony_ci .irq_unmask = iomd_irq_unmask, 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic struct irq_chip iomd_chip_noclr = { 16062306a36Sopenharmony_ci .irq_mask = iomd_irq_mask, 16162306a36Sopenharmony_ci .irq_unmask = iomd_irq_unmask, 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ciextern unsigned char rpc_default_fiq_start, rpc_default_fiq_end; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_civoid __init rpc_init_irq(void) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci unsigned int irq, clr, set; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci iomd_writeb(0, IOMD_IRQMASKA); 17162306a36Sopenharmony_ci iomd_writeb(0, IOMD_IRQMASKB); 17262306a36Sopenharmony_ci iomd_writeb(0, IOMD_FIQMASK); 17362306a36Sopenharmony_ci iomd_writeb(0, IOMD_DMAMASK); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci set_fiq_handler(&rpc_default_fiq_start, 17662306a36Sopenharmony_ci &rpc_default_fiq_end - &rpc_default_fiq_start); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci set_handle_irq(iomd_handle_irq); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci for (irq = 0; irq < NR_IRQS; irq++) { 18162306a36Sopenharmony_ci clr = IRQ_NOREQUEST; 18262306a36Sopenharmony_ci set = 0; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (irq <= 6 || (irq >= 9 && irq <= 15)) 18562306a36Sopenharmony_ci clr |= IRQ_NOPROBE; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (irq == 21 || (irq >= 16 && irq <= 19) || 18862306a36Sopenharmony_ci irq == IRQ_KEYBOARDTX) 18962306a36Sopenharmony_ci set |= IRQ_NOAUTOEN; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci switch (irq) { 19262306a36Sopenharmony_ci case 0 ... 7: 19362306a36Sopenharmony_ci irq_set_chip_and_handler(irq, &iomd_chip_clr, 19462306a36Sopenharmony_ci handle_level_irq); 19562306a36Sopenharmony_ci irq_modify_status(irq, clr, set); 19662306a36Sopenharmony_ci iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATA, 19762306a36Sopenharmony_ci BIT(irq)); 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci case 8 ... 15: 20162306a36Sopenharmony_ci irq_set_chip_and_handler(irq, &iomd_chip_noclr, 20262306a36Sopenharmony_ci handle_level_irq); 20362306a36Sopenharmony_ci irq_modify_status(irq, clr, set); 20462306a36Sopenharmony_ci iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATB, 20562306a36Sopenharmony_ci BIT(irq - 8)); 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci case 16 ... 21: 20962306a36Sopenharmony_ci irq_set_chip_and_handler(irq, &iomd_chip_noclr, 21062306a36Sopenharmony_ci handle_level_irq); 21162306a36Sopenharmony_ci irq_modify_status(irq, clr, set); 21262306a36Sopenharmony_ci iomd_set_base_mask(irq, IOMD_BASE + IOMD_DMASTAT, 21362306a36Sopenharmony_ci BIT(irq - 16)); 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci case 64 ... 71: 21762306a36Sopenharmony_ci irq_set_chip(irq, &iomd_chip_noclr); 21862306a36Sopenharmony_ci irq_modify_status(irq, clr, set); 21962306a36Sopenharmony_ci iomd_set_base_mask(irq, IOMD_BASE + IOMD_FIQSTAT, 22062306a36Sopenharmony_ci BIT(irq - 64)); 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci init_FIQ(FIQ_START); 22662306a36Sopenharmony_ci} 227