1 /*
2  * Copyright (c) 2008, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *  * Neither the name of Google, Inc. nor the names of its contributors
15  *    may be used to endorse or promote products derived from this
16  *    software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <arch/arm.h>
33 #include <lk/reg.h>
34 #include <kernel/thread.h>
35 #include <platform/interrupts.h>
36 #include <sync_write.h>
37 #include <platform/mt_typedefs.h>
38 #include <platform/mt_reg_base.h>
39 #include <platform/mt_gpt.h>
40 #include <platform/mt_irq.h>
41 
42 #include <lk/debug.h>
43 
44 #define GIC_ICDISER0    (GIC_DIST_BASE + 0x100)
45 #define GIC_ICDISER1    (GIC_DIST_BASE + 0x104)
46 #define GIC_ICDISER2    (GIC_DIST_BASE + 0x108)
47 #define GIC_ICDISER3    (GIC_DIST_BASE + 0x10C)
48 #define GIC_ICDISER4    (GIC_DIST_BASE + 0x110)
49 #define GIC_ICDISER5    (GIC_DIST_BASE + 0x114)
50 #define GIC_ICDISER6    (GIC_DIST_BASE + 0x118)
51 #define GIC_ICDISER7    (GIC_DIST_BASE + 0x11C)
52 
53 #define GIC_ICDICER0    (GIC_DIST_BASE + 0x180)
54 #define GIC_ICDICER1    (GIC_DIST_BASE + 0x184)
55 #define GIC_ICDICER2    (GIC_DIST_BASE + 0x188)
56 #define GIC_ICDICER3    (GIC_DIST_BASE + 0x18C)
57 #define GIC_ICDICER4    (GIC_DIST_BASE + 0x190)
58 #define GIC_ICDICER5    (GIC_DIST_BASE + 0x194)
59 #define GIC_ICDICER6    (GIC_DIST_BASE + 0x198)
60 #define GIC_ICDICER7    (GIC_DIST_BASE + 0x19C)
61 
62 #define INT_POL_CTL0  (MCUCFG_BASE + 0x620)
63 
mt_gic_cpu_init(void)64 static void mt_gic_cpu_init(void) {
65     DRV_WriteReg32(GIC_CPU_BASE + GIC_CPU_PRIMASK, 0xF0);
66     DRV_WriteReg32(GIC_CPU_BASE + GIC_CPU_CTRL, 0x1);
67     dsb();
68 }
69 
mt_gic_dist_init(void)70 static void mt_gic_dist_init(void) {
71     unsigned int i;
72 #ifndef MTK_FORCE_CLUSTER1
73     unsigned int cpumask = 1 << 0;
74 #else
75     unsigned int cpumask = 1 << 4;
76 #endif
77 
78     cpumask |= cpumask << 8;
79     cpumask |= cpumask << 16;
80 
81     DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CTRL, 0);
82 
83     /*
84      * Set all global interrupts to be level triggered, active low.
85      */
86     for (i = 32; i < (MT_NR_SPI + 32); i += 16) {
87         DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CONFIG + i * 4 / 16, 0);
88     }
89 
90     /*
91      * Set all global interrupts to this CPU only.
92      */
93     for (i = 32; i < (MT_NR_SPI + 32); i += 4) {
94         DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_TARGET + i * 4 / 4, cpumask);
95     }
96 
97     /*
98      * Set priority on all interrupts.
99      */
100     for (i = 0; i < NR_IRQ_LINE; i += 4) {
101         DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_PRI + i * 4 / 4, 0xA0A0A0A0);
102     }
103 
104     /*
105     * Disable all interrupts.
106     */
107     for (i = 0; i < NR_IRQ_LINE; i += 32) {
108         DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + i * 4 / 32, 0xFFFFFFFF);
109     }
110 
111     dsb();
112 
113     DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CTRL, 1);
114 }
115 
platform_init_interrupts(void)116 void platform_init_interrupts(void) {
117     mt_gic_dist_init();
118     mt_gic_cpu_init();
119 }
120 
platform_deinit_interrupts(void)121 void platform_deinit_interrupts(void) {
122     unsigned int irq;
123 
124     DRV_WriteReg32(GIC_ICDICER0, 0xFFFFFFFF);
125     DRV_WriteReg32(GIC_ICDICER1, 0xFFFFFFFF);
126     DRV_WriteReg32(GIC_ICDICER2, 0xFFFFFFFF);
127     DRV_WriteReg32(GIC_ICDICER3, 0xFFFFFFFF);
128     DRV_WriteReg32(GIC_ICDICER4, 0xFFFFFFFF);
129     DRV_WriteReg32(GIC_ICDICER5, 0xFFFFFFFF);
130     DRV_WriteReg32(GIC_ICDICER6, 0xFFFFFFFF);
131     DRV_WriteReg32(GIC_ICDICER7, 0xFFFFFFFF);
132     dsb();
133 
134     while ((irq = DRV_Reg32(GIC_CPU_BASE + GIC_CPU_INTACK)) != 1023 ) {
135         DRV_WriteReg32(GIC_CPU_BASE + GIC_CPU_EOI, irq);
136     }
137 }
138 
139 extern void lk_scheduler(void);
140 //extern void lk_usb_scheduler(void);
141 extern void lk_nand_irq_handler(unsigned int irq);
142 //extern void lk_msdc_irq_handler(unsigned int irq);
143 #ifdef DUMMY_AP
144 extern void dummy_ap_irq_handler(unsigned int irq);
145 #endif
146 
platform_irq(struct arm_iframe * frame)147 enum handler_return platform_irq(struct arm_iframe *frame) {
148     unsigned int irq = DRV_Reg32(GIC_CPU_BASE + GIC_CPU_INTACK);
149 
150     if (irq == MT_GPT_IRQ_ID)
151         lk_scheduler();
152 //  else if(irq == MT_USB0_IRQ_ID)
153 //      lk_usb_scheduler();
154 #ifndef MTK_EMMC_SUPPORT
155 //  else if(irq == MT_NFI_IRQ_ID)
156 //      lk_nand_irq_handler(irq);
157 #endif
158 //  else if(irq == MT_MSDC0_IRQ_ID || irq == MT_MSDC1_IRQ_ID)
159 //      lk_msdc_irq_handler(irq);
160 
161 #ifdef DUMMY_AP
162     dummy_ap_irq_handler(irq);
163 #endif
164 
165     //return INT_NO_RESCHEDULE;
166     return INT_RESCHEDULE;
167 }
168 
platform_fiq(struct arm_iframe * frame)169 void platform_fiq(struct arm_iframe *frame) {
170 
171 }
172 
mt_irq_set_polarity(unsigned int irq,unsigned int polarity)173 void mt_irq_set_polarity(unsigned int irq, unsigned int polarity) {
174     unsigned int offset;
175     unsigned int reg_index;
176     unsigned int value;
177 
178     // peripheral device's IRQ line is using GIC's SPI, and line ID >= GIC_PRIVATE_SIGNALS
179     if (irq < GIC_PRIVATE_SIGNALS) {
180         return;
181     }
182 
183     offset = (irq - GIC_PRIVATE_SIGNALS) & 0x1F;
184     reg_index = (irq - GIC_PRIVATE_SIGNALS) >> 5;
185     if (polarity == 0) {
186         value = DRV_Reg32(INT_POL_CTL0 + (reg_index * 4));
187         value |= (1 << offset); // always invert the incoming IRQ's polarity
188         DRV_WriteReg32((INT_POL_CTL0 + (reg_index * 4)), value);
189     } else {
190         value = DRV_Reg32(INT_POL_CTL0 + (reg_index * 4));
191         value &= ~(0x1 << offset);
192         DRV_WriteReg32(INT_POL_CTL0 + (reg_index * 4), value);
193     }
194 }
195 
mt_irq_set_sens(unsigned int irq,unsigned int sens)196 void mt_irq_set_sens(unsigned int irq, unsigned int sens) {
197     unsigned int config;
198 
199     if (sens == MT65xx_EDGE_SENSITIVE) {
200         config = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
201         config |= (0x2 << (irq % 16) * 2);
202         DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
203     } else {
204         config = DRV_Reg32(GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4);
205         config &= ~(0x2 << (irq % 16) * 2);
206         DRV_WriteReg32( GIC_DIST_BASE + GIC_DIST_CONFIG + (irq / 16) * 4, config);
207     }
208     dsb();
209 }
210 
211 /*
212  * mt_irq_mask: mask one IRQ
213  * @irq: IRQ line of the IRQ to mask
214  */
mt_irq_mask(unsigned int irq)215 void mt_irq_mask(unsigned int irq) {
216     unsigned int mask = 1 << (irq % 32);
217 
218     DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR + irq / 32 * 4, mask);
219     dsb();
220 }
221 
222 /*
223  * mt_irq_unmask: unmask one IRQ
224  * @irq: IRQ line of the IRQ to unmask
225  */
mt_irq_unmask(unsigned int irq)226 void mt_irq_unmask(unsigned int irq) {
227     unsigned int mask = 1 << (irq % 32);
228 
229     DRV_WriteReg32(GIC_DIST_BASE + GIC_DIST_ENABLE_SET + irq / 32 * 4, mask);
230     dsb();
231 }
232 
233 /*
234  * mt_irq_mask: mask one IRQ
235  * @irq: IRQ line of the IRQ to mask
236  */
mt_irq_ack(unsigned int irq)237 void mt_irq_ack(unsigned int irq) {
238     DRV_WriteReg32(GIC_CPU_BASE + GIC_CPU_EOI, irq);
239     dsb();
240 }
241 
242 /*
243  * mt_irq_mask_all: mask all IRQ lines. (This is ONLY used for the sleep driver)
244  * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
245  * Return 0 for success; return negative values for failure.
246  */
mt_irq_mask_all(struct mtk_irq_mask * mask)247 int mt_irq_mask_all(struct mtk_irq_mask *mask) {
248     if (mask) {
249 
250         mask->mask0 = DRV_Reg32(GIC_ICDISER0);
251         mask->mask1 = DRV_Reg32(GIC_ICDISER1);
252         mask->mask2 = DRV_Reg32(GIC_ICDISER2);
253         mask->mask3 = DRV_Reg32(GIC_ICDISER3);
254         mask->mask4 = DRV_Reg32(GIC_ICDISER4);
255         mask->mask5 = DRV_Reg32(GIC_ICDISER5);
256         mask->mask6 = DRV_Reg32(GIC_ICDISER6);
257         mask->mask7 = DRV_Reg32(GIC_ICDISER7);
258 
259         DRV_WriteReg32(GIC_ICDICER0, 0xFFFFFFFF);
260         DRV_WriteReg32(GIC_ICDICER1, 0xFFFFFFFF);
261         DRV_WriteReg32(GIC_ICDICER2, 0xFFFFFFFF);
262         DRV_WriteReg32(GIC_ICDICER3, 0xFFFFFFFF);
263         DRV_WriteReg32(GIC_ICDICER4, 0xFFFFFFFF);
264         DRV_WriteReg32(GIC_ICDICER5, 0xFFFFFFFF);
265         DRV_WriteReg32(GIC_ICDICER6, 0xFFFFFFFF);
266         DRV_WriteReg32(GIC_ICDICER7, 0xFFFFFFFF);
267 
268         dsb();
269 
270         mask->header = IRQ_MASK_HEADER;
271         mask->footer = IRQ_MASK_FOOTER;
272 
273         return 0;
274     } else {
275         return -1;
276     }
277 }
278 
279 /*
280  * mt_irq_mask_restore: restore all IRQ lines' masks. (This is ONLY used for the sleep driver)
281  * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
282  * Return 0 for success; return negative values for failure.
283  */
mt_irq_mask_restore(struct mtk_irq_mask * mask)284 int mt_irq_mask_restore(struct mtk_irq_mask *mask) {
285     if (!mask) {
286         return -1;
287     }
288     if (mask->header != IRQ_MASK_HEADER) {
289         return -1;
290     }
291     if (mask->footer != IRQ_MASK_FOOTER) {
292         return -1;
293     }
294 
295     DRV_WriteReg32(GIC_ICDISER0,mask->mask0);
296     DRV_WriteReg32(GIC_ICDISER1,mask->mask1);
297     DRV_WriteReg32(GIC_ICDISER2,mask->mask2);
298     DRV_WriteReg32(GIC_ICDISER3,mask->mask3);
299     DRV_WriteReg32(GIC_ICDISER4,mask->mask4);
300     DRV_WriteReg32(GIC_ICDISER5,mask->mask5);
301     DRV_WriteReg32(GIC_ICDISER6,mask->mask6);
302     DRV_WriteReg32(GIC_ICDISER7,mask->mask7);
303 
304     dsb();
305 
306 
307     return 0;
308 }
309