xref: /haiku/src/system/kernel/arch/arm/soc_omap3.cpp (revision 9f3bdf3d039430b5172c424def20ce5d9f7367d4)
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
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
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
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
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 
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
137 OMAP3Timer::_InterruptWrapper(void *data)
138 {
139 	return ((OMAP3Timer*)data)->HandleInterrupt();
140 }
141 
142 
143 int32
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
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
174 OMAP3Timer::Time()
175 {
176 	return fSystemTime + fRegBase[TCRR];
177 }
178 
179 
180 void
181 OMAP3Timer::Clear()
182 {
183 	fRegBase[TIER] &= ~1; // Disable match interrupt
184 }
185 
186 
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