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