blob: b6d6610f2fd70ec6f3410b42c27a9d2013572183 [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 Simek070b8e02015-01-26 15:25:32 +010019 debug("Enable interrupts for the whole CPU\n");
Michal Simekfb05f6d2007-05-07 23:58:31 +020020 MSRSET(0x2);
wdenk507bbe32004-04-18 21:13:41 +000021}
22
Michal Simek26e6da82012-06-29 13:27:28 +020023int disable_interrupts(void)
wdenk507bbe32004-04-18 21:13:41 +000024{
Michal Simek68e99e52010-12-21 08:30:39 +010025 unsigned int msr;
26
27 MFS(msr, rmsr);
Michal Simekfb05f6d2007-05-07 23:58:31 +020028 MSRCLR(0x2);
Michal Simek68e99e52010-12-21 08:30:39 +010029 return (msr & 0x2) != 0;
wdenk507bbe32004-04-18 21:13:41 +000030}
Michal Simekcfc67112007-03-11 13:48:24 +010031
Michal Simek575a3d22012-07-10 10:31:31 +020032static struct irq_action *vecs;
33static u32 irq_no;
Michal Simekcfc67112007-03-11 13:48:24 +010034
35/* mapping structure to interrupt controller */
Michal Simek575a3d22012-07-10 10:31:31 +020036microblaze_intc_t *intc;
Michal Simekcfc67112007-03-11 13:48:24 +010037
38/* default handler */
Michal Simek575a3d22012-07-10 10:31:31 +020039static void def_hdlr(void)
Michal Simekcfc67112007-03-11 13:48:24 +010040{
Michal Simek26e6da82012-06-29 13:27:28 +020041 puts("def_hdlr\n");
Michal Simekcfc67112007-03-11 13:48:24 +010042}
43
Michal Simek575a3d22012-07-10 10:31:31 +020044static void enable_one_interrupt(int irq)
Michal Simekcfc67112007-03-11 13:48:24 +010045{
46 int mask;
47 int offset = 1;
Michal Simek26e6da82012-06-29 13:27:28 +020048
Michal Simekcfc67112007-03-11 13:48:24 +010049 offset <<= irq;
50 mask = intc->ier;
51 intc->ier = (mask | offset);
Michal Simek4c0922f2015-01-26 14:37:52 +010052
53 debug("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask,
54 intc->ier);
55 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
56 intc->iar, intc->mer);
Michal Simekcfc67112007-03-11 13:48:24 +010057}
58
Michal Simek575a3d22012-07-10 10:31:31 +020059static void disable_one_interrupt(int irq)
Michal Simekcfc67112007-03-11 13:48:24 +010060{
61 int mask;
62 int offset = 1;
Michal Simek26e6da82012-06-29 13:27:28 +020063
Michal Simekcfc67112007-03-11 13:48:24 +010064 offset <<= irq;
65 mask = intc->ier;
66 intc->ier = (mask & ~offset);
Michal Simek4c0922f2015-01-26 14:37:52 +010067
68 debug("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask,
69 intc->ier);
70 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
71 intc->iar, intc->mer);
Michal Simekcfc67112007-03-11 13:48:24 +010072}
73
Michal Simek87069082012-06-29 14:21:52 +020074int install_interrupt_handler(int irq, interrupt_handler_t *hdlr, void *arg)
Michal Simekcfc67112007-03-11 13:48:24 +010075{
76 struct irq_action *act;
Michal Simek26e6da82012-06-29 13:27:28 +020077
Michal Simekcfc67112007-03-11 13:48:24 +010078 /* irq out of range */
Michal Simek575a3d22012-07-10 10:31:31 +020079 if ((irq < 0) || (irq > irq_no)) {
Michal Simek26e6da82012-06-29 13:27:28 +020080 puts("IRQ out of range\n");
Michal Simek87069082012-06-29 14:21:52 +020081 return -1;
Michal Simekcfc67112007-03-11 13:48:24 +010082 }
83 act = &vecs[irq];
84 if (hdlr) { /* enable */
85 act->handler = hdlr;
86 act->arg = arg;
87 act->count = 0;
Michal Simeke217b0d2015-01-26 14:39:22 +010088 enable_one_interrupt(irq);
Michal Simek87069082012-06-29 14:21:52 +020089 return 0;
Michal Simekcfc67112007-03-11 13:48:24 +010090 }
Michal Simek87069082012-06-29 14:21:52 +020091
92 /* Disable */
Michal Simeke217b0d2015-01-26 14:39:22 +010093 act->handler = (interrupt_handler_t *)def_hdlr;
Michal Simek87069082012-06-29 14:21:52 +020094 act->arg = (void *)irq;
95 disable_one_interrupt(irq);
96 return 1;
Michal Simekcfc67112007-03-11 13:48:24 +010097}
98
99/* initialization interrupt controller - hardware */
Michal Simek575a3d22012-07-10 10:31:31 +0200100static void intc_init(void)
Michal Simekcfc67112007-03-11 13:48:24 +0100101{
102 intc->mer = 0;
103 intc->ier = 0;
104 intc->iar = 0xFFFFFFFF;
105 /* XIntc_Start - hw_interrupt enable and all interrupt enable */
106 intc->mer = 0x3;
Michal Simek4c0922f2015-01-26 14:37:52 +0100107
108 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
109 intc->iar, intc->mer);
Michal Simekcfc67112007-03-11 13:48:24 +0100110}
111
Michal Simek2c7c32f2015-01-27 12:44:12 +0100112int interrupt_init(void)
Michal Simekcfc67112007-03-11 13:48:24 +0100113{
114 int i;
Michal Simek575a3d22012-07-10 10:31:31 +0200115
116#if defined(CONFIG_SYS_INTC_0_ADDR) && defined(CONFIG_SYS_INTC_0_NUM)
Michal Simeke217b0d2015-01-26 14:39:22 +0100117 intc = (microblaze_intc_t *)CONFIG_SYS_INTC_0_ADDR;
Michal Simek575a3d22012-07-10 10:31:31 +0200118 irq_no = CONFIG_SYS_INTC_0_NUM;
119#endif
120 if (irq_no) {
121 vecs = calloc(1, sizeof(struct irq_action) * irq_no);
122 if (vecs == NULL) {
123 puts("Interrupt vector allocation failed\n");
124 return -1;
125 }
126
127 /* initialize irq list */
128 for (i = 0; i < irq_no; i++) {
Michal Simeke217b0d2015-01-26 14:39:22 +0100129 vecs[i].handler = (interrupt_handler_t *)def_hdlr;
Michal Simek575a3d22012-07-10 10:31:31 +0200130 vecs[i].arg = (void *)i;
131 vecs[i].count = 0;
132 }
133 /* initialize intc controller */
134 intc_init();
135 enable_interrupts();
136 } else {
137 puts("Undefined interrupt controller\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100138 }
Michal Simekcfc67112007-03-11 13:48:24 +0100139 return 0;
140}
141
Michal Simek26e6da82012-06-29 13:27:28 +0200142void interrupt_handler(void)
Michal Simekcfc67112007-03-11 13:48:24 +0100143{
Michal Simek8125c982010-04-16 11:51:59 +0200144 int irqs = intc->ivr; /* find active interrupt */
145 int mask = 1;
Michal Simek42efed62007-05-07 17:22:25 +0200146 int value;
Michal Simek8125c982010-04-16 11:51:59 +0200147 struct irq_action *act = vecs + irqs;
148
Michal Simek4c0922f2015-01-26 14:37:52 +0100149 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
150 intc->iar, intc->mer);
151#ifdef DEBUG
152 R14(value);
Michal Simekcfc67112007-03-11 13:48:24 +0100153#endif
Michal Simek4c0922f2015-01-26 14:37:52 +0100154 debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
155
156 debug("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n",
157 (u32)act->handler, act->count, (u32)act->arg);
Michal Simeke217b0d2015-01-26 14:39:22 +0100158 act->handler(act->arg);
Michal Simek8125c982010-04-16 11:51:59 +0200159 act->count++;
Michal Simek42efed62007-05-07 17:22:25 +0200160
Stephan Linz0f883262012-02-22 19:12:43 +0100161 intc->iar = mask << irqs;
162
Michal Simek4c0922f2015-01-26 14:37:52 +0100163 debug("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr,
164 intc->ier, intc->iar, intc->mer);
165#ifdef DEBUG
Michal Simek42efed62007-05-07 17:22:25 +0200166 R14(value);
Michal Simekcfc67112007-03-11 13:48:24 +0100167#endif
Michal Simek4c0922f2015-01-26 14:37:52 +0100168 debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
Michal Simekcfc67112007-03-11 13:48:24 +0100169}
Michal Simekcfc67112007-03-11 13:48:24 +0100170
Jon Loeliger44312832007-07-09 19:06:00 -0500171#if defined(CONFIG_CMD_IRQ)
Michal Simek575a3d22012-07-10 10:31:31 +0200172int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[])
Michal Simekcfc67112007-03-11 13:48:24 +0100173{
174 int i;
175 struct irq_action *act = vecs;
176
Michal Simek575a3d22012-07-10 10:31:31 +0200177 if (irq_no) {
178 puts("\nInterrupt-Information:\n\n"
179 "Nr Routine Arg Count\n"
180 "-----------------------------\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100181
Michal Simek575a3d22012-07-10 10:31:31 +0200182 for (i = 0; i < irq_no; i++) {
Michal Simeke217b0d2015-01-26 14:39:22 +0100183 if (act->handler != (interrupt_handler_t *)def_hdlr) {
Michal Simek575a3d22012-07-10 10:31:31 +0200184 printf("%02d %08x %08x %d\n", i,
Michal Simeke217b0d2015-01-26 14:39:22 +0100185 (int)act->handler, (int)act->arg,
186 act->count);
Michal Simek575a3d22012-07-10 10:31:31 +0200187 }
188 act++;
Michal Simekcfc67112007-03-11 13:48:24 +0100189 }
Michal Simek575a3d22012-07-10 10:31:31 +0200190 puts("\n");
191 } else {
192 puts("Undefined interrupt controller\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100193 }
Michal Simek575a3d22012-07-10 10:31:31 +0200194 return 0;
Michal Simekcfc67112007-03-11 13:48:24 +0100195}
Jon Loeliger44312832007-07-09 19:06:00 -0500196#endif