Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/init.h>
0003 #include <linux/list.h>
0004 #include <linux/io.h>
0005 
0006 #include <asm/mach/irq.h>
0007 #include <asm/hardware/iomd.h>
0008 #include <asm/irq.h>
0009 #include <asm/fiq.h>
0010 
0011 // These are offsets from the stat register for each IRQ bank
0012 #define STAT    0x00
0013 #define REQ 0x04
0014 #define CLR 0x04
0015 #define MASK    0x08
0016 
0017 static const u8 irq_prio_h[256] = {
0018      0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10,
0019     12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10,
0020     13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
0021     13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
0022     14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10,
0023     14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10,
0024     13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
0025     13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
0026     15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10,
0027     15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10,
0028     13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
0029     13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
0030     15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10,
0031     15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10,
0032     13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
0033     13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10,
0034 };
0035 
0036 static const u8 irq_prio_d[256] = {
0037      0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0038     20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0039     21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0040     21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0041     22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0042     22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0043     21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0044     21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0045     23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0046     23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0047     21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0048     21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0049     22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0050     22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0051     21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0052     21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16,
0053 };
0054 
0055 static const u8 irq_prio_l[256] = {
0056      0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
0057      4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
0058      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
0059      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
0060      6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3,
0061      6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3,
0062      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
0063      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
0064      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0065      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0066      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0067      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0068      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0069      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0070      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0071      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
0072 };
0073 
0074 static int iomd_get_irq_nr(void)
0075 {
0076     int irq;
0077     u8 reg;
0078 
0079     /* get highest priority first */
0080     reg = readb(IOC_BASE + IOMD_IRQREQB);
0081     irq = irq_prio_h[reg];
0082     if (irq)
0083         return irq;
0084 
0085     /* get DMA  */
0086     reg = readb(IOC_BASE + IOMD_DMAREQ);
0087     irq = irq_prio_d[reg];
0088     if (irq)
0089         return irq;
0090 
0091     /* get low priority */
0092     reg = readb(IOC_BASE + IOMD_IRQREQA);
0093     irq = irq_prio_l[reg];
0094     if (irq)
0095         return irq;
0096     return 0;
0097 }
0098 
0099 static void iomd_handle_irq(struct pt_regs *regs)
0100 {
0101     int irq;
0102 
0103     do {
0104         irq = iomd_get_irq_nr();
0105         if (irq)
0106             generic_handle_irq(irq);
0107     } while (irq);
0108 }
0109 
0110 static void __iomem *iomd_get_base(struct irq_data *d)
0111 {
0112     void *cd = irq_data_get_irq_chip_data(d);
0113 
0114     return (void __iomem *)(unsigned long)cd;
0115 }
0116 
0117 static void iomd_set_base_mask(unsigned int irq, void __iomem *base, u32 mask)
0118 {
0119     struct irq_data *d = irq_get_irq_data(irq);
0120 
0121     d->mask = mask;
0122     irq_set_chip_data(irq, (void *)(unsigned long)base);
0123 }
0124 
0125 static void iomd_irq_mask_ack(struct irq_data *d)
0126 {
0127     void __iomem *base = iomd_get_base(d);
0128     unsigned int val, mask = d->mask;
0129 
0130     val = readb(base + MASK);
0131     writeb(val & ~mask, base + MASK);
0132     writeb(mask, base + CLR);
0133 }
0134 
0135 static void iomd_irq_mask(struct irq_data *d)
0136 {
0137     void __iomem *base = iomd_get_base(d);
0138     unsigned int val, mask = d->mask;
0139 
0140     val = readb(base + MASK);
0141     writeb(val & ~mask, base + MASK);
0142 }
0143 
0144 static void iomd_irq_unmask(struct irq_data *d)
0145 {
0146     void __iomem *base = iomd_get_base(d);
0147     unsigned int val, mask = d->mask;
0148 
0149     val = readb(base + MASK);
0150     writeb(val | mask, base + MASK);
0151 }
0152 
0153 static struct irq_chip iomd_chip_clr = {
0154     .irq_mask_ack   = iomd_irq_mask_ack,
0155     .irq_mask   = iomd_irq_mask,
0156     .irq_unmask = iomd_irq_unmask,
0157 };
0158 
0159 static struct irq_chip iomd_chip_noclr = {
0160     .irq_mask   = iomd_irq_mask,
0161     .irq_unmask = iomd_irq_unmask,
0162 };
0163 
0164 extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end;
0165 
0166 void __init rpc_init_irq(void)
0167 {
0168     unsigned int irq, clr, set;
0169 
0170     iomd_writeb(0, IOMD_IRQMASKA);
0171     iomd_writeb(0, IOMD_IRQMASKB);
0172     iomd_writeb(0, IOMD_FIQMASK);
0173     iomd_writeb(0, IOMD_DMAMASK);
0174 
0175     set_fiq_handler(&rpc_default_fiq_start,
0176         &rpc_default_fiq_end - &rpc_default_fiq_start);
0177 
0178     set_handle_irq(iomd_handle_irq);
0179 
0180     for (irq = 0; irq < NR_IRQS; irq++) {
0181         clr = IRQ_NOREQUEST;
0182         set = 0;
0183 
0184         if (irq <= 6 || (irq >= 9 && irq <= 15))
0185             clr |= IRQ_NOPROBE;
0186 
0187         if (irq == 21 || (irq >= 16 && irq <= 19) ||
0188             irq == IRQ_KEYBOARDTX)
0189             set |= IRQ_NOAUTOEN;
0190 
0191         switch (irq) {
0192         case 0 ... 7:
0193             irq_set_chip_and_handler(irq, &iomd_chip_clr,
0194                          handle_level_irq);
0195             irq_modify_status(irq, clr, set);
0196             iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATA,
0197                        BIT(irq));
0198             break;
0199 
0200         case 8 ... 15:
0201             irq_set_chip_and_handler(irq, &iomd_chip_noclr,
0202                          handle_level_irq);
0203             irq_modify_status(irq, clr, set);
0204             iomd_set_base_mask(irq, IOMD_BASE + IOMD_IRQSTATB,
0205                        BIT(irq - 8));
0206             break;
0207 
0208         case 16 ... 21:
0209             irq_set_chip_and_handler(irq, &iomd_chip_noclr,
0210                          handle_level_irq);
0211             irq_modify_status(irq, clr, set);
0212             iomd_set_base_mask(irq, IOMD_BASE + IOMD_DMASTAT,
0213                        BIT(irq - 16));
0214             break;
0215 
0216         case 64 ... 71:
0217             irq_set_chip(irq, &iomd_chip_noclr);
0218             irq_modify_status(irq, clr, set);
0219             iomd_set_base_mask(irq, IOMD_BASE + IOMD_FIQSTAT,
0220                        BIT(irq - 64));
0221             break;
0222         }
0223     }
0224 
0225     init_FIQ(FIQ_START);
0226 }