blob: 030e9147dc400c8aa4f66d387056f2d916e5558c [file] [log] [blame]
wdenk507bbe32004-04-18 21:13:41 +00001/*
Michal Simekcfc67112007-03-11 13:48:24 +01002 * (C) Copyright 2007 Michal Simek
wdenk507bbe32004-04-18 21:13:41 +00003 * (C) Copyright 2004 Atmark Techno, Inc.
4 *
Michal Simekcfc67112007-03-11 13:48:24 +01005 * Michal SIMEK <monstr@monstr.eu>
wdenk507bbe32004-04-18 21:13:41 +00006 * Yasushi SHOJI <yashi@atmark-techno.com>
7 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
wdenk507bbe32004-04-18 21:13:41 +00009 */
10
Michal Simekcfc67112007-03-11 13:48:24 +010011#include <common.h>
12#include <command.h>
Michal Simek575a3d22012-07-10 10:31:31 +020013#include <malloc.h>
Michal Simekcfc67112007-03-11 13:48:24 +010014#include <asm/microblaze_intc.h>
Michal Simek42efed62007-05-07 17:22:25 +020015#include <asm/asm.h>
Michal Simekcfc67112007-03-11 13:48:24 +010016
Michal Simek26e6da82012-06-29 13:27:28 +020017void enable_interrupts(void)
wdenk507bbe32004-04-18 21:13:41 +000018{
Michal Simekfb05f6d2007-05-07 23:58:31 +020019 MSRSET(0x2);
wdenk507bbe32004-04-18 21:13:41 +000020}
21
Michal Simek26e6da82012-06-29 13:27:28 +020022int disable_interrupts(void)
wdenk507bbe32004-04-18 21:13:41 +000023{
Michal Simek68e99e52010-12-21 08:30:39 +010024 unsigned int msr;
25
26 MFS(msr, rmsr);
Michal Simekfb05f6d2007-05-07 23:58:31 +020027 MSRCLR(0x2);
Michal Simek68e99e52010-12-21 08:30:39 +010028 return (msr & 0x2) != 0;
wdenk507bbe32004-04-18 21:13:41 +000029}
Michal Simekcfc67112007-03-11 13:48:24 +010030
Michal Simek575a3d22012-07-10 10:31:31 +020031static struct irq_action *vecs;
32static u32 irq_no;
Michal Simekcfc67112007-03-11 13:48:24 +010033
34/* mapping structure to interrupt controller */
Michal Simek575a3d22012-07-10 10:31:31 +020035microblaze_intc_t *intc;
Michal Simekcfc67112007-03-11 13:48:24 +010036
37/* default handler */
Michal Simek575a3d22012-07-10 10:31:31 +020038static void def_hdlr(void)
Michal Simekcfc67112007-03-11 13:48:24 +010039{
Michal Simek26e6da82012-06-29 13:27:28 +020040 puts("def_hdlr\n");
Michal Simekcfc67112007-03-11 13:48:24 +010041}
42
Michal Simek575a3d22012-07-10 10:31:31 +020043static void enable_one_interrupt(int irq)
Michal Simekcfc67112007-03-11 13:48:24 +010044{
45 int mask;
46 int offset = 1;
Michal Simek26e6da82012-06-29 13:27:28 +020047
Michal Simekcfc67112007-03-11 13:48:24 +010048 offset <<= irq;
49 mask = intc->ier;
50 intc->ier = (mask | offset);
Michal Simek4c0922f2015-01-26 14:37:52 +010051
52 debug("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask,
53 intc->ier);
54 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
55 intc->iar, intc->mer);
Michal Simekcfc67112007-03-11 13:48:24 +010056}
57
Michal Simek575a3d22012-07-10 10:31:31 +020058static void disable_one_interrupt(int irq)
Michal Simekcfc67112007-03-11 13:48:24 +010059{
60 int mask;
61 int offset = 1;
Michal Simek26e6da82012-06-29 13:27:28 +020062
Michal Simekcfc67112007-03-11 13:48:24 +010063 offset <<= irq;
64 mask = intc->ier;
65 intc->ier = (mask & ~offset);
Michal Simek4c0922f2015-01-26 14:37:52 +010066
67 debug("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask,
68 intc->ier);
69 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
70 intc->iar, intc->mer);
Michal Simekcfc67112007-03-11 13:48:24 +010071}
72
Michal Simek87069082012-06-29 14:21:52 +020073int install_interrupt_handler(int irq, interrupt_handler_t *hdlr, void *arg)
Michal Simekcfc67112007-03-11 13:48:24 +010074{
75 struct irq_action *act;
Michal Simek26e6da82012-06-29 13:27:28 +020076
Michal Simekcfc67112007-03-11 13:48:24 +010077 /* irq out of range */
Michal Simek575a3d22012-07-10 10:31:31 +020078 if ((irq < 0) || (irq > irq_no)) {
Michal Simek26e6da82012-06-29 13:27:28 +020079 puts("IRQ out of range\n");
Michal Simek87069082012-06-29 14:21:52 +020080 return -1;
Michal Simekcfc67112007-03-11 13:48:24 +010081 }
82 act = &vecs[irq];
83 if (hdlr) { /* enable */
84 act->handler = hdlr;
85 act->arg = arg;
86 act->count = 0;
87 enable_one_interrupt (irq);
Michal Simek87069082012-06-29 14:21:52 +020088 return 0;
Michal Simekcfc67112007-03-11 13:48:24 +010089 }
Michal Simek87069082012-06-29 14:21:52 +020090
91 /* Disable */
92 act->handler = (interrupt_handler_t *) def_hdlr;
93 act->arg = (void *)irq;
94 disable_one_interrupt(irq);
95 return 1;
Michal Simekcfc67112007-03-11 13:48:24 +010096}
97
98/* initialization interrupt controller - hardware */
Michal Simek575a3d22012-07-10 10:31:31 +020099static void intc_init(void)
Michal Simekcfc67112007-03-11 13:48:24 +0100100{
101 intc->mer = 0;
102 intc->ier = 0;
103 intc->iar = 0xFFFFFFFF;
104 /* XIntc_Start - hw_interrupt enable and all interrupt enable */
105 intc->mer = 0x3;
Michal Simek4c0922f2015-01-26 14:37:52 +0100106
107 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
108 intc->iar, intc->mer);
Michal Simekcfc67112007-03-11 13:48:24 +0100109}
110
Michal Simek575a3d22012-07-10 10:31:31 +0200111int interrupts_init(void)
Michal Simekcfc67112007-03-11 13:48:24 +0100112{
113 int i;
Michal Simek575a3d22012-07-10 10:31:31 +0200114
115#if defined(CONFIG_SYS_INTC_0_ADDR) && defined(CONFIG_SYS_INTC_0_NUM)
116 intc = (microblaze_intc_t *) (CONFIG_SYS_INTC_0_ADDR);
117 irq_no = CONFIG_SYS_INTC_0_NUM;
118#endif
119 if (irq_no) {
120 vecs = calloc(1, sizeof(struct irq_action) * irq_no);
121 if (vecs == NULL) {
122 puts("Interrupt vector allocation failed\n");
123 return -1;
124 }
125
126 /* initialize irq list */
127 for (i = 0; i < irq_no; i++) {
128 vecs[i].handler = (interrupt_handler_t *) def_hdlr;
129 vecs[i].arg = (void *)i;
130 vecs[i].count = 0;
131 }
132 /* initialize intc controller */
133 intc_init();
134 enable_interrupts();
135 } else {
136 puts("Undefined interrupt controller\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100137 }
Michal Simekcfc67112007-03-11 13:48:24 +0100138 return 0;
139}
140
Michal Simek26e6da82012-06-29 13:27:28 +0200141void interrupt_handler(void)
Michal Simekcfc67112007-03-11 13:48:24 +0100142{
Michal Simek8125c982010-04-16 11:51:59 +0200143 int irqs = intc->ivr; /* find active interrupt */
144 int mask = 1;
Michal Simek42efed62007-05-07 17:22:25 +0200145 int value;
Michal Simek8125c982010-04-16 11:51:59 +0200146 struct irq_action *act = vecs + irqs;
147
Michal Simek4c0922f2015-01-26 14:37:52 +0100148 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
149 intc->iar, intc->mer);
150#ifdef DEBUG
151 R14(value);
Michal Simekcfc67112007-03-11 13:48:24 +0100152#endif
Michal Simek4c0922f2015-01-26 14:37:52 +0100153 debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
154
155 debug("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n",
156 (u32)act->handler, act->count, (u32)act->arg);
Michal Simek8125c982010-04-16 11:51:59 +0200157 act->handler (act->arg);
158 act->count++;
Michal Simek42efed62007-05-07 17:22:25 +0200159
Stephan Linz0f883262012-02-22 19:12:43 +0100160 intc->iar = mask << irqs;
161
Michal Simek4c0922f2015-01-26 14:37:52 +0100162 debug("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr,
163 intc->ier, intc->iar, intc->mer);
164#ifdef DEBUG
Michal Simek42efed62007-05-07 17:22:25 +0200165 R14(value);
Michal Simekcfc67112007-03-11 13:48:24 +0100166#endif
Michal Simek4c0922f2015-01-26 14:37:52 +0100167 debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
Michal Simekcfc67112007-03-11 13:48:24 +0100168}
Michal Simekcfc67112007-03-11 13:48:24 +0100169
Jon Loeliger44312832007-07-09 19:06:00 -0500170#if defined(CONFIG_CMD_IRQ)
Michal Simek575a3d22012-07-10 10:31:31 +0200171int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[])
Michal Simekcfc67112007-03-11 13:48:24 +0100172{
173 int i;
174 struct irq_action *act = vecs;
175
Michal Simek575a3d22012-07-10 10:31:31 +0200176 if (irq_no) {
177 puts("\nInterrupt-Information:\n\n"
178 "Nr Routine Arg Count\n"
179 "-----------------------------\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100180
Michal Simek575a3d22012-07-10 10:31:31 +0200181 for (i = 0; i < irq_no; i++) {
182 if (act->handler != (interrupt_handler_t *) def_hdlr) {
183 printf("%02d %08x %08x %d\n", i,
184 (int)act->handler, (int)act->arg,
185 act->count);
186 }
187 act++;
Michal Simekcfc67112007-03-11 13:48:24 +0100188 }
Michal Simek575a3d22012-07-10 10:31:31 +0200189 puts("\n");
190 } else {
191 puts("Undefined interrupt controller\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100192 }
Michal Simek575a3d22012-07-10 10:31:31 +0200193 return 0;
Michal Simekcfc67112007-03-11 13:48:24 +0100194}
Jon Loeliger44312832007-07-09 19:06:00 -0500195#endif