yuezonghe | 824eb0c | 2024-06-27 02:32:26 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * linux/arch/arm/mach-zx297510/irq.c |
| 3 | * |
| 4 | * Copyright (C) 2013 ZTE-TSP |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | */ |
| 16 | |
| 17 | #include <linux/init.h> |
| 18 | #include <linux/module.h> |
| 19 | #include <linux/mm.h> |
| 20 | #include <linux/types.h> |
| 21 | #include <linux/irq.h> |
| 22 | |
| 23 | |
| 24 | #include <mach/iomap.h> |
| 25 | #include <mach/irqs.h> |
| 26 | #include <mach/debug.h> |
| 27 | #include <mach/pcu.h> |
| 28 | |
| 29 | #include <asm/irq.h> |
| 30 | #include <asm/setup.h> |
| 31 | #include <asm/io.h> |
| 32 | #include <asm/system.h> |
| 33 | #include <asm/cp15.h> |
| 34 | |
| 35 | |
| 36 | #include <asm/mach/arch.h> |
| 37 | #include <asm/mach/irq.h> |
| 38 | #include <asm/mach/map.h> |
| 39 | #include <asm/hardware/gic.h> |
| 40 | |
| 41 | |
| 42 | //#pragma GCC optimize("O0") |
| 43 | #define GIC_DIST_BASE (A9_PERIPHERAL_VA+0x1000) |
| 44 | #define GIC_CPU_BASE (A9_PERIPHERAL_VA+0x100) |
| 45 | #define A9_INT_MODE_BASE (A9_PERIPHERAL_VA+0x3050) |
| 46 | |
| 47 | |
| 48 | #define INT_HIGHLEVEL (0x0) /* 00: high level */ |
| 49 | #define INT_LOWLEVEL (0x1) /* 01: low level */ |
| 50 | #define INT_POSEDGE (0x2) /* 10: raise edge */ |
| 51 | #define INT_NEGEDGE (0x3) /* 11: fall edge */ |
| 52 | |
| 53 | |
| 54 | |
| 55 | extern struct gic_chip_data gic_data[MAX_GIC_NR]; |
| 56 | |
| 57 | extern int gic_set_type(struct irq_data *d, unsigned int type); |
| 58 | |
| 59 | /* |
| 60 | * copy from tegra, get pending intterrupt number |
| 61 | */ |
| 62 | unsigned int zx29_gic_pending_interrupt(void) |
| 63 | { |
| 64 | unsigned int irq; |
| 65 | |
| 66 | irq = ioread32(GIC_CPU_BASE + GIC_CPU_HIGHPRI); |
| 67 | irq &= 0x3ff; |
| 68 | |
| 69 | return irq; |
| 70 | } |
| 71 | |
| 72 | /* |
| 73 | *GIC only support IRQ_TYPE_LEVEL_HIGH and IRQ_TYPE_EDGE_RISING. In order to support |
| 74 | *full interrupt trigger mode(high,low,falling,rising), zx297510 add a little thing to do that.It |
| 75 | *is only for SPIs. The little thing treats all level interrupt as high level interrupt, and then |
| 76 | *sends them to GIC. Edge interrupt is treated as rising interrupt as well. |
| 77 | *external int need additional configuration in PCU |
| 78 | */ |
| 79 | |
| 80 | static int zx297510_int_set_type(struct irq_data *d, unsigned int type) |
| 81 | { |
| 82 | unsigned int data_tmp=0; |
| 83 | unsigned int srctype=0; |
| 84 | unsigned int reg_index=0,pos_index=0; |
| 85 | |
| 86 | unsigned int hwirq = d->hwirq; |
| 87 | |
| 88 | switch (type) { |
| 89 | case IRQ_TYPE_LEVEL_HIGH: |
| 90 | srctype = INT_HIGHLEVEL; |
| 91 | break; |
| 92 | case IRQ_TYPE_EDGE_RISING: |
| 93 | srctype = INT_POSEDGE; |
| 94 | break; |
| 95 | case IRQ_TYPE_LEVEL_LOW: |
| 96 | srctype = INT_LOWLEVEL; |
| 97 | break; |
| 98 | case IRQ_TYPE_EDGE_FALLING: |
| 99 | srctype = INT_NEGEDGE; |
| 100 | break; |
| 101 | default: |
| 102 | return -EINVAL; |
| 103 | } |
| 104 | reg_index=(hwirq-32)/16; |
| 105 | pos_index=((hwirq-32)%16)*2; |
| 106 | |
| 107 | |
| 108 | data_tmp=ioread32(A9_INT_MODE_BASE+reg_index*4); |
| 109 | data_tmp &= ~(3<<pos_index); |
| 110 | data_tmp |= srctype<<pos_index; |
| 111 | iowrite32(data_tmp,A9_INT_MODE_BASE+reg_index*4); |
| 112 | |
| 113 | return 0; |
| 114 | } |
| 115 | |
| 116 | |
| 117 | /* |
| 118 | * set default interrupt trigger type |
| 119 | */ |
| 120 | static void int_set_type_default(unsigned int line) |
| 121 | { |
| 122 | unsigned int int_type=0; |
| 123 | unsigned int irq=0; |
| 124 | struct gic_chip_data *gic = &gic_data[0]; |
| 125 | struct irq_data *d; |
| 126 | |
| 127 | if(line<GIC_PPI_START) |
| 128 | return; |
| 129 | |
| 130 | irq = irq_find_mapping(gic->domain, (unsigned long)line); //get linux irq number |
| 131 | d = irq_get_irq_data(irq); //get irq_data |
| 132 | |
| 133 | /*set the interrupt mode --raise edge,fall edge, high level, low level*/ |
| 134 | switch ( line ) |
| 135 | { |
| 136 | case TIMER0_INT: |
| 137 | case TIMER1_INT: |
| 138 | case GSM_SYS0_INT: |
| 139 | case GSM_SYS1_INT: |
| 140 | case SSC0_CONFLICT_INT: |
| 141 | case SSC1_CONFLICT_INT: |
| 142 | case TD_FRM_INT: // it is edge interrupt, maybe rising or falling??? |
| 143 | case TD_LPM4_INT: // it is edge interrupt, maybe rising or falling??? |
| 144 | { |
| 145 | int_type = IRQ_TYPE_EDGE_RISING; |
| 146 | break; |
| 147 | } |
| 148 | case I2C0_INT: |
| 149 | case I2C1_INT: |
| 150 | { |
| 151 | int_type = IRQ_TYPE_LEVEL_LOW; |
| 152 | break; |
| 153 | } |
| 154 | default: |
| 155 | { |
| 156 | int_type = IRQ_TYPE_LEVEL_HIGH; |
| 157 | break; |
| 158 | } |
| 159 | } |
| 160 | gic_set_type(d,int_type); |
| 161 | } |
| 162 | |
| 163 | |
| 164 | /* |
| 165 | * Initialize the interrupt controller unit. |
| 166 | */ |
| 167 | void __init zx297510_init_irq(void) |
| 168 | { |
| 169 | unsigned int i; |
| 170 | |
| 171 | /* |
| 172 | * in order to avoid config repeatedly, let bits needed by a9 in these registers default |
| 173 | * maybe some devices used by a9 should invoke functions in PCU.h to set interrupt type |
| 174 | * and clear interrupt |
| 175 | */ |
| 176 | |
| 177 | #if 0 |
| 178 | /* |
| 179 | * config int type and polarity in PCU |
| 180 | * timer2 and timer3 int is not taken care, its be config in timer driver |
| 181 | * some times external int may need different type, so zx297510_int_set_type() |
| 182 | * will config it automatically |
| 183 | */ |
| 184 | iowrite32(0xfffff3f9, PCU_BASE_VA+0x60); /*int type*/ |
| 185 | iowrite32(0xffffffe7,PCU_BASE_VA+0x70); /*int pol*/ |
| 186 | iowrite32(0x04c3, PCU_BASE_VA+0xe4); /*int type*/ |
| 187 | iowrite32(0x1ff8, PCU_BASE_VA+0xe8); /*int pol*/ |
| 188 | |
| 189 | /*clear fake int*/ |
| 190 | iowrite32(0xffffffff, PCU_BASE_VA+0x80); |
| 191 | iowrite32(0x1fff, PCU_BASE_VA+0xec); |
| 192 | #endif |
| 193 | |
| 194 | gic_arch_extn.irq_set_type = zx297510_int_set_type; |
| 195 | gic_init(0, GIC_PPI_START, GIC_DIST_BASE, GIC_CPU_BASE); |
| 196 | |
| 197 | /*config int type and polarity int INT_MODE_REG and GIC*/ |
| 198 | for (i = GIC_PPI_START; i < NR_IRQS; i++) { |
| 199 | int_set_type_default(i); |
| 200 | } |
| 201 | |
| 202 | printk(KERN_INFO "ZTE-TSP zx297510 GIC initialized\n"); |
| 203 | } |
| 204 | |
| 205 | |