blob: e5d8894f54471a783efc11b1728f5de73a56e196 [file] [log] [blame]
wdenk12490652004-04-18 21:13:41 +00001/*
Michal Simek922ce202007-03-11 13:48:24 +01002 * (C) Copyright 2007 Michal Simek
wdenk12490652004-04-18 21:13:41 +00003 * (C) Copyright 2004 Atmark Techno, Inc.
4 *
Michal Simek922ce202007-03-11 13:48:24 +01005 * Michal SIMEK <monstr@monstr.eu>
wdenk12490652004-04-18 21:13:41 +00006 * Yasushi SHOJI <yashi@atmark-techno.com>
7 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
wdenk12490652004-04-18 21:13:41 +00009 */
10
Michal Simek922ce202007-03-11 13:48:24 +010011#include <common.h>
12#include <command.h>
Michal Simekcf848852016-02-15 12:10:32 +010013#include <fdtdec.h>
Michal Simek251ed2c2012-07-10 10:31:31 +020014#include <malloc.h>
Michal Simek922ce202007-03-11 13:48:24 +010015#include <asm/microblaze_intc.h>
Michal Simek77a1e242007-05-07 17:22:25 +020016#include <asm/asm.h>
Michal Simek922ce202007-03-11 13:48:24 +010017
Michal Simekcf848852016-02-15 12:10:32 +010018DECLARE_GLOBAL_DATA_PTR;
19
Michal Simek8b4bb3a2012-06-29 13:27:28 +020020void enable_interrupts(void)
wdenk12490652004-04-18 21:13:41 +000021{
Michal Simek056dbe82015-01-26 15:25:32 +010022 debug("Enable interrupts for the whole CPU\n");
Michal Simek98c19792007-05-07 23:58:31 +020023 MSRSET(0x2);
wdenk12490652004-04-18 21:13:41 +000024}
25
Michal Simek8b4bb3a2012-06-29 13:27:28 +020026int disable_interrupts(void)
wdenk12490652004-04-18 21:13:41 +000027{
Michal Simekc94f95e2010-12-21 08:30:39 +010028 unsigned int msr;
29
30 MFS(msr, rmsr);
Michal Simek98c19792007-05-07 23:58:31 +020031 MSRCLR(0x2);
Michal Simekc94f95e2010-12-21 08:30:39 +010032 return (msr & 0x2) != 0;
wdenk12490652004-04-18 21:13:41 +000033}
Michal Simek922ce202007-03-11 13:48:24 +010034
Michal Simek251ed2c2012-07-10 10:31:31 +020035static struct irq_action *vecs;
36static u32 irq_no;
Michal Simek922ce202007-03-11 13:48:24 +010037
38/* mapping structure to interrupt controller */
Michal Simek251ed2c2012-07-10 10:31:31 +020039microblaze_intc_t *intc;
Michal Simek922ce202007-03-11 13:48:24 +010040
41/* default handler */
Michal Simek251ed2c2012-07-10 10:31:31 +020042static void def_hdlr(void)
Michal Simek922ce202007-03-11 13:48:24 +010043{
Michal Simek8b4bb3a2012-06-29 13:27:28 +020044 puts("def_hdlr\n");
Michal Simek922ce202007-03-11 13:48:24 +010045}
46
Michal Simek251ed2c2012-07-10 10:31:31 +020047static void enable_one_interrupt(int irq)
Michal Simek922ce202007-03-11 13:48:24 +010048{
49 int mask;
50 int offset = 1;
Michal Simek8b4bb3a2012-06-29 13:27:28 +020051
Michal Simek922ce202007-03-11 13:48:24 +010052 offset <<= irq;
53 mask = intc->ier;
54 intc->ier = (mask | offset);
Michal Simekbaf51752015-01-26 14:37:52 +010055
56 debug("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask,
57 intc->ier);
58 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
59 intc->iar, intc->mer);
Michal Simek922ce202007-03-11 13:48:24 +010060}
61
Michal Simek251ed2c2012-07-10 10:31:31 +020062static void disable_one_interrupt(int irq)
Michal Simek922ce202007-03-11 13:48:24 +010063{
64 int mask;
65 int offset = 1;
Michal Simek8b4bb3a2012-06-29 13:27:28 +020066
Michal Simek922ce202007-03-11 13:48:24 +010067 offset <<= irq;
68 mask = intc->ier;
69 intc->ier = (mask & ~offset);
Michal Simekbaf51752015-01-26 14:37:52 +010070
71 debug("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask,
72 intc->ier);
73 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
74 intc->iar, intc->mer);
Michal Simek922ce202007-03-11 13:48:24 +010075}
76
Michal Simeke76a06e2012-06-29 14:21:52 +020077int install_interrupt_handler(int irq, interrupt_handler_t *hdlr, void *arg)
Michal Simek922ce202007-03-11 13:48:24 +010078{
79 struct irq_action *act;
Michal Simek8b4bb3a2012-06-29 13:27:28 +020080
Michal Simek922ce202007-03-11 13:48:24 +010081 /* irq out of range */
Michal Simek251ed2c2012-07-10 10:31:31 +020082 if ((irq < 0) || (irq > irq_no)) {
Michal Simek8b4bb3a2012-06-29 13:27:28 +020083 puts("IRQ out of range\n");
Michal Simeke76a06e2012-06-29 14:21:52 +020084 return -1;
Michal Simek922ce202007-03-11 13:48:24 +010085 }
86 act = &vecs[irq];
87 if (hdlr) { /* enable */
88 act->handler = hdlr;
89 act->arg = arg;
90 act->count = 0;
Michal Simek5e6c7472015-01-26 14:39:22 +010091 enable_one_interrupt(irq);
Michal Simeke76a06e2012-06-29 14:21:52 +020092 return 0;
Michal Simek922ce202007-03-11 13:48:24 +010093 }
Michal Simeke76a06e2012-06-29 14:21:52 +020094
95 /* Disable */
Michal Simek5e6c7472015-01-26 14:39:22 +010096 act->handler = (interrupt_handler_t *)def_hdlr;
Michal Simeke76a06e2012-06-29 14:21:52 +020097 act->arg = (void *)irq;
98 disable_one_interrupt(irq);
99 return 1;
Michal Simek922ce202007-03-11 13:48:24 +0100100}
101
102/* initialization interrupt controller - hardware */
Michal Simek251ed2c2012-07-10 10:31:31 +0200103static void intc_init(void)
Michal Simek922ce202007-03-11 13:48:24 +0100104{
105 intc->mer = 0;
106 intc->ier = 0;
107 intc->iar = 0xFFFFFFFF;
108 /* XIntc_Start - hw_interrupt enable and all interrupt enable */
109 intc->mer = 0x3;
Michal Simekbaf51752015-01-26 14:37:52 +0100110
111 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
112 intc->iar, intc->mer);
Michal Simek922ce202007-03-11 13:48:24 +0100113}
114
Michal Simekb78df3d2015-01-27 12:44:12 +0100115int interrupt_init(void)
Michal Simek922ce202007-03-11 13:48:24 +0100116{
117 int i;
Michal Simek251ed2c2012-07-10 10:31:31 +0200118
Michal Simekcf848852016-02-15 12:10:32 +0100119#ifdef CONFIG_OF_CONTROL
120 const void *blob = gd->fdt_blob;
121 int node = 0;
122
123 debug("INTC: Initialization\n");
124
125 node = fdt_node_offset_by_compatible(blob, node,
126 "xlnx,xps-intc-1.00.a");
127 if (node != -1) {
128 fdt_addr_t base = fdtdec_get_addr(blob, node, "reg");
129 if (base == FDT_ADDR_T_NONE)
130 return -1;
131
132 debug("INTC: Base addr %lx\n", base);
133 intc = (microblaze_intc_t *)base;
134 irq_no = fdtdec_get_int(blob, node, "xlnx,num-intr-inputs", 0);
135 debug("INTC: IRQ NO %x\n", irq_no);
136 } else {
137 return node;
138 }
139#else
Michal Simek251ed2c2012-07-10 10:31:31 +0200140#if defined(CONFIG_SYS_INTC_0_ADDR) && defined(CONFIG_SYS_INTC_0_NUM)
Michal Simek5e6c7472015-01-26 14:39:22 +0100141 intc = (microblaze_intc_t *)CONFIG_SYS_INTC_0_ADDR;
Michal Simek251ed2c2012-07-10 10:31:31 +0200142 irq_no = CONFIG_SYS_INTC_0_NUM;
143#endif
Michal Simekcf848852016-02-15 12:10:32 +0100144#endif
Michal Simek251ed2c2012-07-10 10:31:31 +0200145 if (irq_no) {
146 vecs = calloc(1, sizeof(struct irq_action) * irq_no);
147 if (vecs == NULL) {
148 puts("Interrupt vector allocation failed\n");
149 return -1;
150 }
151
152 /* initialize irq list */
153 for (i = 0; i < irq_no; i++) {
Michal Simek5e6c7472015-01-26 14:39:22 +0100154 vecs[i].handler = (interrupt_handler_t *)def_hdlr;
Michal Simek251ed2c2012-07-10 10:31:31 +0200155 vecs[i].arg = (void *)i;
156 vecs[i].count = 0;
157 }
158 /* initialize intc controller */
159 intc_init();
160 enable_interrupts();
161 } else {
162 puts("Undefined interrupt controller\n");
Michal Simek922ce202007-03-11 13:48:24 +0100163 }
Michal Simek922ce202007-03-11 13:48:24 +0100164 return 0;
165}
166
Michal Simek8b4bb3a2012-06-29 13:27:28 +0200167void interrupt_handler(void)
Michal Simek922ce202007-03-11 13:48:24 +0100168{
Michal Simek2c004492010-04-16 11:51:59 +0200169 int irqs = intc->ivr; /* find active interrupt */
170 int mask = 1;
Michal Simek77a1e242007-05-07 17:22:25 +0200171 int value;
Michal Simek2c004492010-04-16 11:51:59 +0200172 struct irq_action *act = vecs + irqs;
173
Michal Simekbaf51752015-01-26 14:37:52 +0100174 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
175 intc->iar, intc->mer);
176#ifdef DEBUG
177 R14(value);
Michal Simek922ce202007-03-11 13:48:24 +0100178#endif
Michal Simekbaf51752015-01-26 14:37:52 +0100179 debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
180
181 debug("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n",
182 (u32)act->handler, act->count, (u32)act->arg);
Michal Simek5e6c7472015-01-26 14:39:22 +0100183 act->handler(act->arg);
Michal Simek2c004492010-04-16 11:51:59 +0200184 act->count++;
Michal Simek77a1e242007-05-07 17:22:25 +0200185
Stephan Linz5db50d62012-02-22 19:12:43 +0100186 intc->iar = mask << irqs;
187
Michal Simekbaf51752015-01-26 14:37:52 +0100188 debug("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr,
189 intc->ier, intc->iar, intc->mer);
190#ifdef DEBUG
Michal Simek77a1e242007-05-07 17:22:25 +0200191 R14(value);
Michal Simek922ce202007-03-11 13:48:24 +0100192#endif
Michal Simekbaf51752015-01-26 14:37:52 +0100193 debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
Michal Simek922ce202007-03-11 13:48:24 +0100194}
Michal Simek922ce202007-03-11 13:48:24 +0100195
Jon Loeliger526e5ce2007-07-09 19:06:00 -0500196#if defined(CONFIG_CMD_IRQ)
Michal Simek251ed2c2012-07-10 10:31:31 +0200197int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[])
Michal Simek922ce202007-03-11 13:48:24 +0100198{
199 int i;
200 struct irq_action *act = vecs;
201
Michal Simek251ed2c2012-07-10 10:31:31 +0200202 if (irq_no) {
203 puts("\nInterrupt-Information:\n\n"
204 "Nr Routine Arg Count\n"
205 "-----------------------------\n");
Michal Simek922ce202007-03-11 13:48:24 +0100206
Michal Simek251ed2c2012-07-10 10:31:31 +0200207 for (i = 0; i < irq_no; i++) {
Michal Simek5e6c7472015-01-26 14:39:22 +0100208 if (act->handler != (interrupt_handler_t *)def_hdlr) {
Michal Simek251ed2c2012-07-10 10:31:31 +0200209 printf("%02d %08x %08x %d\n", i,
Michal Simek5e6c7472015-01-26 14:39:22 +0100210 (int)act->handler, (int)act->arg,
211 act->count);
Michal Simek251ed2c2012-07-10 10:31:31 +0200212 }
213 act++;
Michal Simek922ce202007-03-11 13:48:24 +0100214 }
Michal Simek251ed2c2012-07-10 10:31:31 +0200215 puts("\n");
216 } else {
217 puts("Undefined interrupt controller\n");
Michal Simek922ce202007-03-11 13:48:24 +0100218 }
Michal Simek251ed2c2012-07-10 10:31:31 +0200219 return 0;
Michal Simek922ce202007-03-11 13:48:24 +0100220}
221#endif