1#include <vm/vm.h>
2
3#include "soc_omap3.h"
4
5enum {
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
29void
30OMAP3InterruptController::EnableInterrupt(int32 irq)
31{
32	uint32 bit = irq % 32, bank = irq / 32;
33	fRegBase[INTCPS_MIR_CLEARn + (8 * bank)] = 1 << bit;
34}
35
36
37void
38OMAP3InterruptController::DisableInterrupt(int32 irq)
39{
40	uint32 bit = irq % 32, bank = irq / 32;
41	fRegBase[INTCPS_MIR_SETn + (8 * bank)] = 1 << bit;
42}
43
44
45void
46OMAP3InterruptController::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
77void
78OMAP3InterruptController::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
97OMAP3InterruptController::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
113enum {
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
136int32
137OMAP3Timer::_InterruptWrapper(void *data)
138{
139	return ((OMAP3Timer*)data)->HandleInterrupt();
140}
141
142
143int32
144OMAP3Timer::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
165void
166OMAP3Timer::SetTimeout(bigtime_t timeout)
167{
168	fRegBase[TMAR] = fRegBase[TCRR] + timeout / 1000ULL;
169	fRegBase[TIER] |= 1; // Enable match interrupt
170}
171
172
173bigtime_t
174OMAP3Timer::Time()
175{
176	return fSystemTime + fRegBase[TCRR];
177}
178
179
180void
181OMAP3Timer::Clear()
182{
183	fRegBase[TIER] &= ~1; // Disable match interrupt
184}
185
186
187OMAP3Timer::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