1 #include <vm/vm.h>
2
3 #include "soc_omap3.h"
4
5 enum {
6 INTCPS_REVISION = 0,
7 INTCPS_SYSCONFIG = 4,
8 INTCPS_SYSSTATUS,
9 INTCPS_SIR_IRQ = 16,
10 INTCPS_SIR_FIQ = 17,
11 INTCPS_CONTROL = 18,
12 INTCPS_PROTECTION = 19,
13 INTCPS_IDLE = 20,
14 INTCPS_IRQ_PRIORITY = 24,
15 INTCPS_FIQ_PRIORITY = 25,
16 INTCPS_THRESHOLD = 26,
17 INTCPS_ITRn = 32,
18 INTCPS_MIRn = 33,
19 INTCPS_MIR_CLEARn = 34,
20 INTCPS_MIR_SETn = 35,
21 INTCPS_ISR_SETn = 36,
22 INTCPS_ISR_CLEARn = 37,
23 INTCPS_PENDING_IRQn = 38,
24 INTCPS_PENDING_FIQn = 39,
25 INTCPS_ILRm = 40,
26 };
27
28
29 void
EnableInterrupt(int32 irq)30 OMAP3InterruptController::EnableInterrupt(int32 irq)
31 {
32 uint32 bit = irq % 32, bank = irq / 32;
33 fRegBase[INTCPS_MIR_CLEARn + (8 * bank)] = 1 << bit;
34 }
35
36
37 void
DisableInterrupt(int32 irq)38 OMAP3InterruptController::DisableInterrupt(int32 irq)
39 {
40 uint32 bit = irq % 32, bank = irq / 32;
41 fRegBase[INTCPS_MIR_SETn + (8 * bank)] = 1 << bit;
42 }
43
44
45 void
HandleInterrupt()46 OMAP3InterruptController::HandleInterrupt()
47 {
48 bool handledIRQ = false;
49 int irqnr = 0;
50
51 do {
52 for (uint32 i=0; i < fNumPending; i++) {
53 irqnr = fRegBase[INTCPS_PENDING_IRQn + (8 * i)];
54 if (irqnr)
55 break;
56 }
57
58 if (!irqnr)
59 break;
60
61 irqnr = fRegBase[INTCPS_SIR_IRQ];
62 irqnr &= 0x7f; /* ACTIVEIRQ */
63
64 if (irqnr) {
65 int_io_interrupt_handler(irqnr, true);
66 handledIRQ = true;
67 }
68 } while(irqnr);
69
70 // If IRQ got cleared before we could handle it, simply
71 // ack it.
72 if (!handledIRQ)
73 fRegBase[INTCPS_CONTROL] = 1;
74 }
75
76
77 void
SoftReset()78 OMAP3InterruptController::SoftReset()
79 {
80 uint32 tmp = fRegBase[INTCPS_REVISION] & 0xff;
81
82 dprintf("OMAP: INTC found at 0x%p (rev %" B_PRIu32 ".%" B_PRIu32 ")\n",
83 fRegBase, tmp >> 4, tmp & 0xf);
84
85 tmp = fRegBase[INTCPS_SYSCONFIG];
86 tmp |= 1 << 1; /* soft reset */
87 fRegBase[INTCPS_SYSCONFIG] = tmp;
88
89 while (!(fRegBase[INTCPS_SYSSTATUS] & 0x1))
90 /* Wait for reset to complete */;
91
92 /* Enable autoidle */
93 fRegBase[INTCPS_SYSCONFIG] = 1;
94 }
95
96
OMAP3InterruptController(uint32_t reg_base)97 OMAP3InterruptController::OMAP3InterruptController(uint32_t reg_base)
98 : fNumPending(3)
99 {
100 fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-omap3", (void**)&fRegBase,
101 B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
102 reg_base, false);
103 if (fRegArea < 0)
104 panic("OMAP3InterruptController: cannot map registers!");
105
106 SoftReset();
107
108 // Enable protection (MPU registers only available in privileged mode)
109 fRegBase[INTCPS_PROTECTION] |= 1;
110 }
111
112
113 enum {
114 TIDR = 0,
115 TIOCP_CFG = 4,
116 TISTAT,
117 TISR,
118 TIER,
119 TWER,
120 TCLR,
121 TCRR,
122 TLDR,
123 TTGR,
124 TWPS,
125 TMAR,
126 TCAR1,
127 TSICR,
128 TCAR2,
129 TPIR,
130 TNIR,
131 TCVR,
132 TOCR,
133 TOWR,
134 };
135
136 int32
_InterruptWrapper(void * data)137 OMAP3Timer::_InterruptWrapper(void *data)
138 {
139 return ((OMAP3Timer*)data)->HandleInterrupt();
140 }
141
142
143 int32
HandleInterrupt()144 OMAP3Timer::HandleInterrupt()
145 {
146 uint32 ints = fRegBase[TISR] & 7;
147
148 if (ints & 1) { // Match?
149 dprintf("OMAP3Timer: match!\n");
150 timer_interrupt();
151 } else if (ints & 2) { // Overflow?
152 dprintf("OMAP3Timer: overflow!\n");
153 fSystemTime += UINT_MAX +1;
154 } else if (ints & 4) { // Capture?
155 dprintf("OMAP3Timer: capture!\n");
156 }
157
158 // clear interrupt
159 fRegBase[TISR] = ints;
160
161 return B_HANDLED_INTERRUPT;
162 }
163
164
165 void
SetTimeout(bigtime_t timeout)166 OMAP3Timer::SetTimeout(bigtime_t timeout)
167 {
168 fRegBase[TMAR] = fRegBase[TCRR] + timeout / 1000ULL;
169 fRegBase[TIER] |= 1; // Enable match interrupt
170 }
171
172
173 bigtime_t
Time()174 OMAP3Timer::Time()
175 {
176 return fSystemTime + fRegBase[TCRR];
177 }
178
179
180 void
Clear()181 OMAP3Timer::Clear()
182 {
183 fRegBase[TIER] &= ~1; // Disable match interrupt
184 }
185
186
OMAP3Timer(uint32_t reg_base,uint32_t interrupt)187 OMAP3Timer::OMAP3Timer(uint32_t reg_base, uint32_t interrupt)
188 : fSystemTime(0)
189 {
190 fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "timer-omap3", (void**)&fRegBase,
191 B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
192 reg_base, false);
193 if (fRegArea < 0)
194 panic("Cannot map OMAP3Timer registers!");
195
196 fInterrupt = interrupt;
197 if (fInterrupt < 0)
198 panic("Cannot get OMAP3Timer interrupt!");
199
200 uint32 rev = fRegBase[TIDR];
201 dprintf("OMAP: Found timer @ 0x%p, IRQ %d (rev %" B_PRIu32 ".%" B_PRIu32 ")\n",
202 fRegBase, fInterrupt, (rev >> 4) & 0xf, rev & 0xf);
203
204 // Let the timer run (so we can use it as clocksource)
205 fRegBase[TCLR] |= 1;
206 fRegBase[TIER] = 2; // Enable overflow interrupt
207
208 install_io_interrupt_handler(fInterrupt, &OMAP3Timer::_InterruptWrapper, this, 0);
209 }
210