blob: 010ca4a02c494a5d39e65b172cd6b26e572e50a5 [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 Simek9aa65ca2016-02-15 12:10:32 +010013#include <fdtdec.h>
Michal Simek575a3d22012-07-10 10:31:31 +020014#include <malloc.h>
Michal Simekcfc67112007-03-11 13:48:24 +010015#include <asm/microblaze_intc.h>
Michal Simek42efed62007-05-07 17:22:25 +020016#include <asm/asm.h>
Michal Simekcfc67112007-03-11 13:48:24 +010017
Michal Simek9aa65ca2016-02-15 12:10:32 +010018DECLARE_GLOBAL_DATA_PTR;
19
Michal Simek26e6da82012-06-29 13:27:28 +020020void enable_interrupts(void)
wdenk507bbe32004-04-18 21:13:41 +000021{
Michal Simek070b8e02015-01-26 15:25:32 +010022 debug("Enable interrupts for the whole CPU\n");
Michal Simekfb05f6d2007-05-07 23:58:31 +020023 MSRSET(0x2);
wdenk507bbe32004-04-18 21:13:41 +000024}
25
Michal Simek26e6da82012-06-29 13:27:28 +020026int disable_interrupts(void)
wdenk507bbe32004-04-18 21:13:41 +000027{
Michal Simek68e99e52010-12-21 08:30:39 +010028 unsigned int msr;
29
30 MFS(msr, rmsr);
Michal Simekfb05f6d2007-05-07 23:58:31 +020031 MSRCLR(0x2);
Michal Simek68e99e52010-12-21 08:30:39 +010032 return (msr & 0x2) != 0;
wdenk507bbe32004-04-18 21:13:41 +000033}
Michal Simekcfc67112007-03-11 13:48:24 +010034
Michal Simek575a3d22012-07-10 10:31:31 +020035static struct irq_action *vecs;
36static u32 irq_no;
Michal Simekcfc67112007-03-11 13:48:24 +010037
38/* mapping structure to interrupt controller */
Michal Simek575a3d22012-07-10 10:31:31 +020039microblaze_intc_t *intc;
Michal Simekcfc67112007-03-11 13:48:24 +010040
41/* default handler */
Michal Simek575a3d22012-07-10 10:31:31 +020042static void def_hdlr(void)
Michal Simekcfc67112007-03-11 13:48:24 +010043{
Michal Simek26e6da82012-06-29 13:27:28 +020044 puts("def_hdlr\n");
Michal Simekcfc67112007-03-11 13:48:24 +010045}
46
Michal Simek575a3d22012-07-10 10:31:31 +020047static void enable_one_interrupt(int irq)
Michal Simekcfc67112007-03-11 13:48:24 +010048{
49 int mask;
50 int offset = 1;
Michal Simek26e6da82012-06-29 13:27:28 +020051
Michal Simekcfc67112007-03-11 13:48:24 +010052 offset <<= irq;
53 mask = intc->ier;
54 intc->ier = (mask | offset);
Michal Simek4c0922f2015-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 Simekcfc67112007-03-11 13:48:24 +010060}
61
Michal Simek575a3d22012-07-10 10:31:31 +020062static void disable_one_interrupt(int irq)
Michal Simekcfc67112007-03-11 13:48:24 +010063{
64 int mask;
65 int offset = 1;
Michal Simek26e6da82012-06-29 13:27:28 +020066
Michal Simekcfc67112007-03-11 13:48:24 +010067 offset <<= irq;
68 mask = intc->ier;
69 intc->ier = (mask & ~offset);
Michal Simek4c0922f2015-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 Simekcfc67112007-03-11 13:48:24 +010075}
76
Michal Simek87069082012-06-29 14:21:52 +020077int install_interrupt_handler(int irq, interrupt_handler_t *hdlr, void *arg)
Michal Simekcfc67112007-03-11 13:48:24 +010078{
79 struct irq_action *act;
Michal Simek26e6da82012-06-29 13:27:28 +020080
Michal Simekcfc67112007-03-11 13:48:24 +010081 /* irq out of range */
Michal Simek575a3d22012-07-10 10:31:31 +020082 if ((irq < 0) || (irq > irq_no)) {
Michal Simek26e6da82012-06-29 13:27:28 +020083 puts("IRQ out of range\n");
Michal Simek87069082012-06-29 14:21:52 +020084 return -1;
Michal Simekcfc67112007-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 Simeke217b0d2015-01-26 14:39:22 +010091 enable_one_interrupt(irq);
Michal Simek87069082012-06-29 14:21:52 +020092 return 0;
Michal Simekcfc67112007-03-11 13:48:24 +010093 }
Michal Simek87069082012-06-29 14:21:52 +020094
95 /* Disable */
Michal Simeke217b0d2015-01-26 14:39:22 +010096 act->handler = (interrupt_handler_t *)def_hdlr;
Michal Simek87069082012-06-29 14:21:52 +020097 act->arg = (void *)irq;
98 disable_one_interrupt(irq);
99 return 1;
Michal Simekcfc67112007-03-11 13:48:24 +0100100}
101
102/* initialization interrupt controller - hardware */
Michal Simek575a3d22012-07-10 10:31:31 +0200103static void intc_init(void)
Michal Simekcfc67112007-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 Simek4c0922f2015-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 Simekcfc67112007-03-11 13:48:24 +0100113}
114
Michal Simek2c7c32f2015-01-27 12:44:12 +0100115int interrupt_init(void)
Michal Simekcfc67112007-03-11 13:48:24 +0100116{
117 int i;
Michal Simek9aa65ca2016-02-15 12:10:32 +0100118 const void *blob = gd->fdt_blob;
119 int node = 0;
120
121 debug("INTC: Initialization\n");
122
123 node = fdt_node_offset_by_compatible(blob, node,
124 "xlnx,xps-intc-1.00.a");
125 if (node != -1) {
126 fdt_addr_t base = fdtdec_get_addr(blob, node, "reg");
127 if (base == FDT_ADDR_T_NONE)
128 return -1;
129
130 debug("INTC: Base addr %lx\n", base);
131 intc = (microblaze_intc_t *)base;
132 irq_no = fdtdec_get_int(blob, node, "xlnx,num-intr-inputs", 0);
133 debug("INTC: IRQ NO %x\n", irq_no);
134 } else {
135 return node;
136 }
Michal Simeka359eaa2016-02-15 13:44:19 +0100137
Michal Simek575a3d22012-07-10 10:31:31 +0200138 if (irq_no) {
139 vecs = calloc(1, sizeof(struct irq_action) * irq_no);
140 if (vecs == NULL) {
141 puts("Interrupt vector allocation failed\n");
142 return -1;
143 }
144
145 /* initialize irq list */
146 for (i = 0; i < irq_no; i++) {
Michal Simeke217b0d2015-01-26 14:39:22 +0100147 vecs[i].handler = (interrupt_handler_t *)def_hdlr;
Michal Simek575a3d22012-07-10 10:31:31 +0200148 vecs[i].arg = (void *)i;
149 vecs[i].count = 0;
150 }
151 /* initialize intc controller */
152 intc_init();
153 enable_interrupts();
154 } else {
155 puts("Undefined interrupt controller\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100156 }
Michal Simekcfc67112007-03-11 13:48:24 +0100157 return 0;
158}
159
Michal Simek26e6da82012-06-29 13:27:28 +0200160void interrupt_handler(void)
Michal Simekcfc67112007-03-11 13:48:24 +0100161{
Michal Simek8125c982010-04-16 11:51:59 +0200162 int irqs = intc->ivr; /* find active interrupt */
163 int mask = 1;
Michal Simek42efed62007-05-07 17:22:25 +0200164 int value;
Michal Simek8125c982010-04-16 11:51:59 +0200165 struct irq_action *act = vecs + irqs;
166
Michal Simek4c0922f2015-01-26 14:37:52 +0100167 debug("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier,
168 intc->iar, intc->mer);
169#ifdef DEBUG
170 R14(value);
Michal Simekcfc67112007-03-11 13:48:24 +0100171#endif
Michal Simek4c0922f2015-01-26 14:37:52 +0100172 debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
173
174 debug("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n",
175 (u32)act->handler, act->count, (u32)act->arg);
Michal Simeke217b0d2015-01-26 14:39:22 +0100176 act->handler(act->arg);
Michal Simek8125c982010-04-16 11:51:59 +0200177 act->count++;
Michal Simek42efed62007-05-07 17:22:25 +0200178
Stephan Linz0f883262012-02-22 19:12:43 +0100179 intc->iar = mask << irqs;
180
Michal Simek4c0922f2015-01-26 14:37:52 +0100181 debug("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr,
182 intc->ier, intc->iar, intc->mer);
183#ifdef DEBUG
Michal Simek42efed62007-05-07 17:22:25 +0200184 R14(value);
Michal Simekcfc67112007-03-11 13:48:24 +0100185#endif
Michal Simek4c0922f2015-01-26 14:37:52 +0100186 debug("Interrupt handler on %x line, r14 %x\n", irqs, value);
Michal Simekcfc67112007-03-11 13:48:24 +0100187}
Michal Simekcfc67112007-03-11 13:48:24 +0100188
Jon Loeliger44312832007-07-09 19:06:00 -0500189#if defined(CONFIG_CMD_IRQ)
Michal Simek575a3d22012-07-10 10:31:31 +0200190int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[])
Michal Simekcfc67112007-03-11 13:48:24 +0100191{
192 int i;
193 struct irq_action *act = vecs;
194
Michal Simek575a3d22012-07-10 10:31:31 +0200195 if (irq_no) {
196 puts("\nInterrupt-Information:\n\n"
197 "Nr Routine Arg Count\n"
198 "-----------------------------\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100199
Michal Simek575a3d22012-07-10 10:31:31 +0200200 for (i = 0; i < irq_no; i++) {
Michal Simeke217b0d2015-01-26 14:39:22 +0100201 if (act->handler != (interrupt_handler_t *)def_hdlr) {
Michal Simek575a3d22012-07-10 10:31:31 +0200202 printf("%02d %08x %08x %d\n", i,
Michal Simeke217b0d2015-01-26 14:39:22 +0100203 (int)act->handler, (int)act->arg,
204 act->count);
Michal Simek575a3d22012-07-10 10:31:31 +0200205 }
206 act++;
Michal Simekcfc67112007-03-11 13:48:24 +0100207 }
Michal Simek575a3d22012-07-10 10:31:31 +0200208 puts("\n");
209 } else {
210 puts("Undefined interrupt controller\n");
Michal Simekcfc67112007-03-11 13:48:24 +0100211 }
Michal Simek575a3d22012-07-10 10:31:31 +0200212 return 0;
Michal Simekcfc67112007-03-11 13:48:24 +0100213}
Jon Loeliger44312832007-07-09 19:06:00 -0500214#endif