summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/beagle/irq.c
blob: 81a511ae7e87b43940db495499da8a2f265729f2 (plain) (blame)
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
/**
 * @file
 *
 * @ingroup bsp_interrupt
 * @ingroup arm_beagle
 *
 * @brief Interrupt support.
 */

/*
 * Copyright (c) 2014 Ben Gras <beng@shrike-systems.com>. All rights reserved.
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.com/license/LICENSE.
 */

#include <bsp.h>
#include <bsp/irq-generic.h>
#include <bsp/linker-symbols.h>

#include <rtems/score/armv4.h>

#include <libcpu/arm-cp15.h>

struct omap_intr
{
  uint32_t base;
  int size;
};

#if IS_DM3730
static struct omap_intr omap_intr = {
  .base = OMAP3_DM37XX_INTR_BASE,
  .size = 0x1000,
};
#endif

#if IS_AM335X
static struct omap_intr omap_intr = {
  .base = OMAP3_AM335X_INTR_BASE,
  .size = 0x1000,
};
#endif

static int irqs_enabled[BSP_INTERRUPT_VECTOR_MAX+1];

volatile static int level = 0;

void bsp_interrupt_dispatch(void)
{
  /* get irq */
  uint32_t reg = mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ);
  int irq;
  irq = reg & OMAP3_INTR_ACTIVEIRQ_MASK;

  if(!irqs_enabled[irq]) {
	/* Ignore spurious interrupt */
  } else {
    bsp_interrupt_vector_disable(irq);

    /* enable new interrupts, and flush data cache to make sure
     * it hits the intc
     */
    mmio_write(omap_intr.base + OMAP3_INTCPS_CONTROL, OMAP3_INTR_NEWIRQAGR);
    flush_data_cache();
    mmio_read(omap_intr.base + OMAP3_INTCPS_SIR_IRQ);
    flush_data_cache();

    /* keep current irq masked but enable unmasked ones */
    uint32_t psr = _ARMV4_Status_irq_enable();
    bsp_interrupt_handler_dispatch(irq);

    _ARMV4_Status_restore(psr);

    bsp_interrupt_vector_enable(irq);
  }
}

static uint32_t get_mir_reg(int vector, uint32_t *mask)
{
  *mask = 1UL << (vector % 32);

  if(vector <   0) while(1) ;
  if(vector <  32) return OMAP3_INTCPS_MIR0;
  if(vector <  64) return OMAP3_INTCPS_MIR1;
  if(vector <  96) return OMAP3_INTCPS_MIR2;
  if(vector < 128) return OMAP3_INTCPS_MIR3;
  while(1) ;
}

rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
{
  uint32_t mask, cur;
  uint32_t mir_reg = get_mir_reg(vector, &mask);

  cur = mmio_read(omap_intr.base + mir_reg);
  mmio_write(omap_intr.base + mir_reg, cur & ~mask);
  flush_data_cache();

  irqs_enabled[vector] = 1;

  return RTEMS_SUCCESSFUL;
}

rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
{
  uint32_t mask, cur;
  uint32_t mir_reg = get_mir_reg(vector, &mask);

  cur = mmio_read(omap_intr.base + mir_reg);
  mmio_write(omap_intr.base + mir_reg, cur | mask);
  flush_data_cache();

  irqs_enabled[vector] = 0;

  return RTEMS_SUCCESSFUL;
}

rtems_status_code bsp_interrupt_facility_initialize(void)
{
  int i;
  uint32_t intc_ilrx;

  /* AM335X TRM 6.2.1 Initialization Sequence */
  mmio_write(omap_intr.base + OMAP3_INTCPS_SYSCONFIG, OMAP3_SYSCONFIG_AUTOIDLE);
  mmio_write(omap_intr.base + OMAP3_INTCPS_IDLE, 0);
  /* priority 0 to all IRQs */
  for(intc_ilrx = 0x100; intc_ilrx <= 0x2fc; intc_ilrx += 4) {
    mmio_write(omap_intr.base + intc_ilrx, 0);
  }

  /* Mask all interrupts */
  for(i = BSP_INTERRUPT_VECTOR_MIN; i <= BSP_INTERRUPT_VECTOR_MAX; i++)
    bsp_interrupt_vector_disable(i);

  /* Install generic interrupt handler */
  arm_cp15_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt);
  arm_cp15_set_vector_base_address(bsp_vector_table_begin);

  return RTEMS_SUCCESSFUL;
}