source: rtems/c/src/lib/libbsp/arm/beagle/irq.c @ 8c5c53f4

Last change on this file since 8c5c53f4 was 8c5c53f4, checked in by Martin Galvan <martin.galvan@…>, on Feb 27, 2016 at 11:19:33 PM

am335x irq handling improvement

This patch makes the following changes to the Beaglebone IRQ handling code:

  • Disable support for nested interrupts.
  • Detect spurious IRQs using the SPURIOUSIRQ field of the INTC_SIR_IRQ register.
  • Acknowledge spurious IRQs by setting the NewIRQAgr bit of the INTC_CONTROL register. This cleans the SPURIOUSIRQ field and allows new interrupts to be generated.
  • Improve the get_mir_reg function a bit.

Closes #2580.

  • Property mode set to 100644
File size: 3.5 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup bsp_interrupt
5 * @ingroup arm_beagle
6 *
7 * @brief Interrupt support.
8 */
9
10/*
11 * Copyright (c) 2014 Ben Gras <beng@shrike-systems.com>. All rights reserved.
12 *
13 * The license and distribution terms for this file may be
14 * found in the file LICENSE in this distribution or at
15 * http://www.rtems.org/license/LICENSE.
16 */
17
18#include <bsp.h>
19#include <bsp/irq-generic.h>
20#include <bsp/linker-symbols.h>
21#include <bsp/fatal.h>
22
23#include <rtems/score/armv4.h>
24
25#include <libcpu/arm-cp15.h>
26
27struct omap_intr
28{
29  uint32_t base;
30  int size;
31};
32
33#if IS_DM3730
34static struct omap_intr omap_intr = {
35  .base = OMAP3_DM37XX_INTR_BASE,
36  .size = 0x1000,
37};
38#endif
39
40#if IS_AM335X
41static struct omap_intr omap_intr = {
42  .base = OMAP3_AM335X_INTR_BASE,
43  .size = 0x1000,
44};
45#endif
46
47/* Enables interrupts at the Interrupt Controller side. */
48static inline void omap_irq_ack(void)
49{
50  mmio_write(omap_intr.base + OMAP3_INTCPS_CONTROL, OMAP3_INTR_NEWIRQAGR);
51
52  /* Flush data cache to make sure all the previous writes are done
53     before re-enabling interrupts. */
54  flush_data_cache();
55}
56
57void bsp_interrupt_dispatch(void)
58{
59  const uint32_t reg = mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ);
60
61  if ((reg & OMAP3_INTR_SPURIOUSIRQ_MASK) != OMAP3_INTR_SPURIOUSIRQ_MASK) {
62    const rtems_vector_number irq = reg & OMAP3_INTR_ACTIVEIRQ_MASK;
63
64    bsp_interrupt_handler_dispatch(irq);
65  } else {
66    /* Ignore spurious interrupts. We'll still ACK it so new interrupts
67       can be generated. */
68  }
69
70  omap_irq_ack();
71}
72
73/* There are 4 32-bit interrupt mask registers for a total of 128 interrupts.
74   The IRQ number tells us which register to use. */
75static uint32_t omap_get_mir_reg(rtems_vector_number vector, uint32_t *const mask)
76{
77  uint32_t mir_reg;
78
79  /* Select which bit to set/clear in the MIR register. */
80  *mask = 1ul << (vector % 32u);
81
82  if (vector < 32u) {
83    mir_reg = OMAP3_INTCPS_MIR0;
84  } else if (vector < 64u) {
85    mir_reg = OMAP3_INTCPS_MIR1;
86  } else if (vector < 96u) {
87    mir_reg = OMAP3_INTCPS_MIR2;
88  } else if (vector < 128u) {
89    mir_reg = OMAP3_INTCPS_MIR3;
90  } else {
91    /* Invalid IRQ number. This should never happen. */
92    bsp_fatal(0);
93  }
94
95  return mir_reg;
96}
97
98rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
99{
100  uint32_t mask, cur;
101  uint32_t mir_reg = omap_get_mir_reg(vector, &mask);
102
103  cur = mmio_read(omap_intr.base + mir_reg);
104  mmio_write(omap_intr.base + mir_reg, cur & ~mask);
105  flush_data_cache();
106
107  return RTEMS_SUCCESSFUL;
108}
109
110rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
111{
112  uint32_t mask, cur;
113  uint32_t mir_reg = omap_get_mir_reg(vector, &mask);
114
115  cur = mmio_read(omap_intr.base + mir_reg);
116  mmio_write(omap_intr.base + mir_reg, cur | mask);
117  flush_data_cache();
118
119  return RTEMS_SUCCESSFUL;
120}
121
122rtems_status_code bsp_interrupt_facility_initialize(void)
123{
124  int i;
125  uint32_t intc_ilrx;
126
127  /* AM335X TRM 6.2.1 Initialization Sequence */
128  mmio_write(omap_intr.base + OMAP3_INTCPS_SYSCONFIG, OMAP3_SYSCONFIG_AUTOIDLE);
129  mmio_write(omap_intr.base + OMAP3_INTCPS_IDLE, 0);
130  /* priority 0 to all IRQs */
131  for(intc_ilrx = 0x100; intc_ilrx <= 0x2fc; intc_ilrx += 4) {
132    mmio_write(omap_intr.base + intc_ilrx, 0);
133  }
134
135  /* Mask all interrupts */
136  for(i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; i++)
137    bsp_interrupt_vector_disable(i);
138
139  /* Install generic interrupt handler */
140  arm_cp15_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt);
141  arm_cp15_set_vector_base_address(bsp_vector_table_begin);
142
143  return RTEMS_SUCCESSFUL;
144}
Note: See TracBrowser for help on using the repository browser.