summaryrefslogtreecommitdiffstats
path: root/arch/m68k/cpu/interrupts.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/cpu/interrupts.c')
-rw-r--r--arch/m68k/cpu/interrupts.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/arch/m68k/cpu/interrupts.c b/arch/m68k/cpu/interrupts.c
new file mode 100644
index 0000000000..16aac38ad5
--- /dev/null
+++ b/arch/m68k/cpu/interrupts.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2008 Carsten Schlote <c.schlote@konzeptpark.de>
+ * See file CREDITS for list of people who contributed to this project.
+ *
+ * This file is part of U-Boot V2.
+ *
+ * U-Boot V2 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * U-Boot V2 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with U-Boot V2. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file
+ * Interrupt routines and supporting code for Coldfire V4E
+ */
+#include <common.h>
+#include <asm/ptrace.h>
+#include <asm/arch/mcf54xx-regs.h>
+
+#ifdef CONFIG_USE_IRQ
+void enable_interrupts(void)
+{
+ asm_set_ipl(0);
+}
+
+int disable_interrupts(void)
+{
+ return asm_set_ipl(7) ? 1 : 0;
+}
+#endif
+
+/**
+ */
+static void mcf_bad_mode (void)
+{
+ panic ("Resetting CPU ...\n");
+ mdelay(3000);
+ reset_cpu (0);
+}
+
+/**
+ */
+static void mcf_show_regs (struct pt_regs *regs)
+{
+ unsigned long flags;
+ flags = condition_codes (regs);
+
+ printf ("pc : [<%08lx>]\n"
+ "sp : %08lx fp : %08lx\n",
+ instruction_pointer (regs),
+ regs->M68K_sp, regs->M68K_a6);
+
+ printf ("d0-d3 : %08lx %08lx %08lx %08lx\n",
+ regs->M68K_d0, regs->M68K_d1, regs->M68K_d2, regs->M68K_d3);
+ printf ("d3-d7 : %08lx %08lx %08lx %08lx\n",
+ regs->M68K_d3, regs->M68K_d4, regs->M68K_d5, regs->M68K_d6);
+
+ printf ("a0-d3 : %08lx %08lx %08lx %08lx\n",
+ regs->M68K_a0, regs->M68K_a1, regs->M68K_a2, regs->M68K_a3);
+ printf ("a3-d7 : %08lx %08lx %08lx %08lx\n",
+ regs->M68K_a3, regs->M68K_a4, regs->M68K_a5, regs->M68K_a6);
+
+ printf ("fp0 : %08lx%08lx fp1 : %08lx%08lx\n",
+ regs->M68K_fp0+1, regs->M68K_fp0, regs->M68K_fp1+1, regs->M68K_fp1);
+ printf ("fp2 : %08lx%08lx fp3 : %08lx%08lx\n",
+ regs->M68K_fp2+1, regs->M68K_fp2, regs->M68K_fp3+1, regs->M68K_fp3);
+ printf ("fp4 : %08lx%08lx fp5 : %08lx%08lx\n",
+ regs->M68K_fp4+1, regs->M68K_fp4, regs->M68K_fp5+1, regs->M68K_fp5);
+ printf ("fp6 : %08lx%08lx fp7 : %08lx%08lx\n",
+ regs->M68K_fp6+1, regs->M68K_fp6, regs->M68K_fp7+1, regs->M68K_fp7);
+
+ printf ("Flags: %c%c%c%c",
+ flags & CC_X_BIT ? 'X' : 'x',
+ flags & CC_N_BIT ? 'N' : 'n',
+ flags & CC_Z_BIT ? 'Z' : 'z',
+ flags & CC_V_BIT ? 'V' : 'v',
+ flags & CC_C_BIT ? 'C' : 'c' );
+
+ printf (" IRQs %s (%0x) Mode %s\n",
+ interrupts_enabled (regs) ? "on" : "off", interrupts_enabled (regs),
+ user_mode (regs) ? "user" : "supervisor");
+}
+
+void mcf_execute_exception_handler (struct pt_regs *pt_regs)
+{
+ printf ("unhandled exception\n");
+ mcf_show_regs (pt_regs);
+ mcf_bad_mode ();
+}
+
+#ifndef CONFIG_USE_IRQ
+
+void mcf_execute_irq_handler (struct pt_regs *pt_regs, int vector)
+{
+ printf ("interrupt request\n");
+ mcf_show_regs (pt_regs);
+ mcf_bad_mode ();
+}
+
+#else
+
+#ifndef CONFIG_MAX_ISR_HANDLERS
+#define CONFIG_MAX_ISR_HANDLERS (20)
+#endif
+
+typedef struct
+{
+ int vector;
+ int (*handler)(void *, void *);
+ void *hdev;
+ void *harg;
+}
+mcfv4e_irq_handler_s;
+
+mcfv4e_irq_handler_s irq_handler_table[CONFIG_MAX_ISR_HANDLERS];
+
+/** Initialize an empty interrupt handler list
+ */
+void mcf_interrupts_initialize (void)
+{
+ int index;
+ for (index = 0; index < CONFIG_MAX_ISR_HANDLERS; index++)
+ {
+ irq_handler_table[index].vector = 0;
+ irq_handler_table[index].handler = 0;
+ irq_handler_table[index].hdev = 0;
+ irq_handler_table[index].harg = 0;
+ }
+}
+
+/** Add an interrupt handler to the handler list
+ *
+ * @param vector : M68k exception/interrupt vector number
+ * @param handler : Pointer to handler function
+ * @param hdev : Handler specific data
+ * @param harg : Handler specific arg
+ */
+int mcf_interrupts_register_handler(
+ int vector,
+ int (*handler)(void *, void *), void *hdev, void *harg)
+{
+ /*
+ * This function places an interrupt handler in the ISR table,
+ * thereby registering it so that the low-level handler may call it.
+ *
+ * The two parameters are intended for the first arg to be a
+ * pointer to the device itself, and the second a pointer to a data
+ * structure used by the device driver for that particular device.
+ */
+ int index;
+
+ if ((vector == 0) || (handler == NULL))
+ {
+ return 0;
+ }
+
+ for (index = 0; index < CONFIG_MAX_ISR_HANDLERS; index++)
+ {
+ if (irq_handler_table[index].vector == vector)
+ {
+ /* only one entry of each type per vector */
+ return 0;
+ }
+
+ if (irq_handler_table[index].vector == 0)
+ {
+ irq_handler_table[index].vector = vector;
+ irq_handler_table[index].handler = handler;
+ irq_handler_table[index].hdev = hdev;
+ irq_handler_table[index].harg = harg;
+ return 1;
+ }
+ }
+ return 0; /* no available slots */
+}
+
+/** Remove an interrupt handler from the handler list
+ *
+ * @param type : FIXME
+ * @param handler : Pointer of handler function to remove.
+ */
+void mcf_interrupts_remove_handler (int type ,int (*handler)(void *, void *))
+{
+ /*
+ * This routine removes from the ISR table all
+ * entries that matches 'handler'.
+ */
+ int index;
+
+ for (index = 0; index < CONFIG_MAX_ISR_HANDLERS; index++)
+ {
+ if (irq_handler_table[index].handler == handler)
+ {
+ irq_handler_table[index].vector = 0;
+ irq_handler_table[index].handler = 0;
+ irq_handler_table[index].hdev = 0;
+ irq_handler_table[index].harg = 0;
+ }
+ }
+}
+
+/** Traverse list of registered interrupts and call matching handlers.
+ *
+ * @param pt_regs : Pointer to saved register context
+ * @param vector : M68k exception/interrupt vector number
+ */
+int mcf_execute_irq_handler (struct pt_regs *pt_regs, int vector)
+{
+ /*
+ * This routine searches the ISR table for an entry that matches
+ * 'vector'. If one is found, then 'handler' is executed.
+ */
+ int index, retval = 0;
+
+ /*
+ * Try to locate a user-registered Interrupt Service Routine handler.
+ */
+ for (index = 0; index < CONFIG_MAX_ISR_HANDLERS; index++)
+ {
+ if (irq_handler_table[index].handler == NULL)
+ {
+ printf("\nFault: No handler for IRQ vector %ld found.\n", vector);
+ break;
+ }
+ if (irq_handler_table[index].vector == vector)
+ {
+ if (irq_handler_table[index].handler(irq_handler_table[index].hdev,irq_handler_table[index].harg))
+ {
+ retval = 1;
+ break;
+ }
+ }
+ }
+
+ return retval;
+}
+
+#endif