Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sead3-int.c
Go to the documentation of this file.
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License. See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
7  */
8 #include <linux/init.h>
9 #include <linux/irq.h>
10 #include <linux/io.h>
11 
12 #include <asm/gic.h>
13 #include <asm/irq_cpu.h>
14 #include <asm/setup.h>
15 
17 
18 #define SEAD_CONFIG_GIC_PRESENT_SHF 1
19 #define SEAD_CONFIG_GIC_PRESENT_MSK (1 << SEAD_CONFIG_GIC_PRESENT_SHF)
20 #define SEAD_CONFIG_BASE 0x1b100110
21 #define SEAD_CONFIG_SIZE 4
22 
24 static unsigned long sead3_config_reg;
25 
26 /*
27  * This table defines the setup for each external GIC interrupt. It is
28  * indexed by interrupt number.
29  */
30 #define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
31 static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
41  { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
42  { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
43  { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
44  { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
45  { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
46  { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
47  { GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED, GIC_UNUSED },
48 };
49 
51 {
52  unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
53  int irq;
54 
55  irq = (fls(pending) - CAUSEB_IP - 1);
56  if (irq >= 0)
58  else
60 }
61 
63 {
64  int i;
65 
66  if (!cpu_has_veic) {
68 
69  if (cpu_has_vint) {
70  /* install generic handler */
71  for (i = 0; i < 8; i++)
73  }
74  }
75 
76  sead3_config_reg = (unsigned long)ioremap_nocache(SEAD_CONFIG_BASE,
78  gic_present = (REG32(sead3_config_reg) & SEAD_CONFIG_GIC_PRESENT_MSK) >>
80  pr_info("GIC: %spresent\n", (gic_present) ? "" : "not ");
81  pr_info("EIC: %s\n",
82  (current_cpu_data.options & MIPS_CPU_VEIC) ? "on" : "off");
83 
84  if (gic_present)
86  ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
87 }
88 
89 void gic_enable_interrupt(int irq_vec)
90 {
91  unsigned int i, irq_source;
92 
93  /* enable all the interrupts associated with this vector */
94  for (i = 0; i < gic_shared_intr_map[irq_vec].num_shared_intr; i++) {
95  irq_source = gic_shared_intr_map[irq_vec].intr_list[i];
96  GIC_SET_INTR_MASK(irq_source);
97  }
98  /* enable all local interrupts associated with this vector */
99  if (gic_shared_intr_map[irq_vec].local_intr_mask) {
100  GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
101  GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SMASK),
102  gic_shared_intr_map[irq_vec].local_intr_mask);
103  }
104 }
105 
106 void gic_disable_interrupt(int irq_vec)
107 {
108  unsigned int i, irq_source;
109 
110  /* disable all the interrupts associated with this vector */
111  for (i = 0; i < gic_shared_intr_map[irq_vec].num_shared_intr; i++) {
112  irq_source = gic_shared_intr_map[irq_vec].intr_list[i];
113  GIC_CLR_INTR_MASK(irq_source);
114  }
115  /* disable all local interrupts associated with this vector */
116  if (gic_shared_intr_map[irq_vec].local_intr_mask) {
117  GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
118  GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK),
119  gic_shared_intr_map[irq_vec].local_intr_mask);
120  }
121 }
122 
123 void gic_irq_ack(struct irq_data *d)
124 {
126 }
127 
128 void gic_finish_irq(struct irq_data *d)
129 {
130  unsigned int irq = (d->irq - gic_irq_base);
131  unsigned int i, irq_source;
132 
133  /* Clear edge detectors. */
134  for (i = 0; i < gic_shared_intr_map[irq].num_shared_intr; i++) {
135  irq_source = gic_shared_intr_map[irq].intr_list[i];
136  if (gic_irq_flags[irq_source] & GIC_TRIG_EDGE)
137  GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq_source);
138  }
139 
140  /* Enable interrupts. */
141  GIC_SET_INTR_MASK(irq);
142 }
143 
144 void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
145 {
146  int i;
147 
148  /*
149  * For non-EIC mode, we want to setup the GIC in pass-through
150  * mode, as if the GIC didn't exist. Do not map any interrupts
151  * for an external interrupt controller.
152  */
153  if (!cpu_has_veic)
154  return;
155 
156  for (i = gic_irq_base; i < (gic_irq_base + irqs); i++)
157  irq_set_chip_and_handler(i, irq_controller, handle_percpu_irq);
158 }