Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | /* * Copyright 2002 Momentum Computer * Author: mdharm@momenco.com * * arch/mips/momentum/ocelot_c/uart-irq.c * Interrupt routines for UARTs. Interrupt numbers are assigned from * 80 to 81 (2 interrupt sources). * * This program 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 2 of the License, or (at your * option) any later version. */ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/kernel.h> #include <asm/ptrace.h> #include <linux/config.h> #include <linux/sched.h> #include <linux/kernel_stat.h> #include <asm/io.h> #include <asm/irq.h> #include "ocelot_c_fpga.h" static inline int ls1bit8(unsigned int x) { int b = 7, s; s = 4; if (((unsigned char)(x << 4)) == 0) s = 0; b -= s; x <<= s; s = 2; if (((unsigned char)(x << 2)) == 0) s = 0; b -= s; x <<= s; s = 1; if (((unsigned char)(x << 1)) == 0) s = 0; b -= s; return b; } /* mask off an interrupt -- 0 is enable, 1 is disable */ static inline void mask_uart_irq(unsigned int irq) { uint8_t value; value = OCELOT_FPGA_READ(UART_INTMASK); value |= 1 << (irq - 74); OCELOT_FPGA_WRITE(value, UART_INTMASK); /* read the value back to assure that it's really been written */ value = OCELOT_FPGA_READ(UART_INTMASK); } /* unmask an interrupt -- 0 is enable, 1 is disable */ static inline void unmask_uart_irq(unsigned int irq) { uint8_t value; value = OCELOT_FPGA_READ(UART_INTMASK); value &= ~(1 << (irq - 74)); OCELOT_FPGA_WRITE(value, UART_INTMASK); /* read the value back to assure that it's really been written */ value = OCELOT_FPGA_READ(UART_INTMASK); } /* * Enables the IRQ in the FPGA */ static void enable_uart_irq(unsigned int irq) { unmask_uart_irq(irq); } /* * Initialize the IRQ in the FPGA */ static unsigned int startup_uart_irq(unsigned int irq) { unmask_uart_irq(irq); return 0; } /* * Disables the IRQ in the FPGA */ static void disable_uart_irq(unsigned int irq) { mask_uart_irq(irq); } /* * Masks and ACKs an IRQ */ static void mask_and_ack_uart_irq(unsigned int irq) { mask_uart_irq(irq); } /* * End IRQ processing */ static void end_uart_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) unmask_uart_irq(irq); } /* * Interrupt handler for interrupts coming from the FPGA chip. */ void ll_uart_irq(struct pt_regs *regs) { unsigned int irq_src, irq_mask; /* read the interrupt status registers */ irq_src = OCELOT_FPGA_READ(UART_INTSTAT); irq_mask = OCELOT_FPGA_READ(UART_INTMASK); /* mask for just the interrupts we want */ irq_src &= ~irq_mask; do_IRQ(ls1bit8(irq_src) + 74, regs); } #define shutdown_uart_irq disable_uart_irq struct hw_interrupt_type uart_irq_type = { "UART/FPGA", startup_uart_irq, shutdown_uart_irq, enable_uart_irq, disable_uart_irq, mask_and_ack_uart_irq, end_uart_irq, NULL }; void uart_irq_init(void) { /* Reset irq handlers pointers to NULL */ irq_desc[80].status = IRQ_DISABLED; irq_desc[80].action = 0; irq_desc[80].depth = 2; irq_desc[80].handler = &uart_irq_type; irq_desc[81].status = IRQ_DISABLED; irq_desc[81].action = 0; irq_desc[81].depth = 2; irq_desc[81].handler = &uart_irq_type; } |