xref: /haiku/src/system/kernel/arch/arm/soc_omap3.cpp (revision c9d6d52b03e472d2335e58f402159b50a1eea1bd)
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 #if 0
96 OMAP3InterruptController::OMAP3InterruptController(fdt_module_info *fdt, fdt_device_node node)
97 	: InterruptController(fdt, node),
98 	fNumPending(3)
99 {
100 	fRegArea = fFDT->map_reg_range(node, 0, (void**)&fRegBase);
101 	if (fRegArea < 0)
102 		panic("OMAP3InterruptController: cannot map registers!");
103 
104 	SoftReset();
105 
106 	// Enable protection (MPU registers only available in privileged mode)
107 	fRegBase[INTCPS_PROTECTION] |= 1;
108 }
109 #endif
110 
111 
112 enum {
113 	TIDR = 0,
114 	TIOCP_CFG = 4,
115 	TISTAT,
116 	TISR,
117 	TIER,
118 	TWER,
119 	TCLR,
120 	TCRR,
121 	TLDR,
122 	TTGR,
123 	TWPS,
124 	TMAR,
125 	TCAR1,
126 	TSICR,
127 	TCAR2,
128 	TPIR,
129 	TNIR,
130 	TCVR,
131 	TOCR,
132 	TOWR,
133 };
134 
135 int32
136 OMAP3Timer::_InterruptWrapper(void *data)
137 {
138 	return ((OMAP3Timer*)data)->HandleInterrupt();
139 }
140 
141 
142 int32
143 OMAP3Timer::HandleInterrupt()
144 {
145 	uint32 ints = fRegBase[TISR] & 7;
146 
147 	if (ints & 1) { // Match?
148 		dprintf("OMAP3Timer: match!\n");
149 		timer_interrupt();
150 	} else if (ints & 2) { // Overflow?
151 		dprintf("OMAP3Timer: overflow!\n");
152 		fSystemTime += UINT_MAX +1;
153 	} else if (ints & 4) { // Capture?
154 		dprintf("OMAP3Timer: capture!\n");
155 	}
156 
157 	// clear interrupt
158 	fRegBase[TISR] = ints;
159 
160 	return B_HANDLED_INTERRUPT;
161 }
162 
163 
164 void
165 OMAP3Timer::SetTimeout(bigtime_t timeout)
166 {
167 	fRegBase[TMAR] = fRegBase[TCRR] + timeout / 1000ULL;
168 	fRegBase[TIER] |= 1; // Enable match interrupt
169 }
170 
171 
172 bigtime_t
173 OMAP3Timer::Time()
174 {
175 	return fSystemTime + fRegBase[TCRR];
176 }
177 
178 
179 void
180 OMAP3Timer::Clear()
181 {
182 	fRegBase[TIER] &= ~1; // Disable match interrupt
183 }
184 
185 
186 #if 0
187 OMAP3Timer::OMAP3Timer(fdt_module_info *fdtModule, fdt_device_node node)
188 	: HardwareTimer(fdtModule, node),
189 	fSystemTime(0)
190 {
191 	fRegArea = fFDT->map_reg_range(node, 0, (void**)&fRegBase);
192 	if (fRegArea < 0)
193 		panic("Cannot map OMAP3Timer registers!");
194 
195 	fInterrupt = fFDT->get_interrupt(node, 0);
196 	if (fInterrupt < 0)
197 		panic("Cannot get OMAP3Timer interrupt!");
198 
199 	uint32 rev = fRegBase[TIDR];
200 	dprintf("OMAP: Found timer @ 0x%p, IRQ %d (rev %ld.%ld)\n", fRegBase, fInterrupt, (rev >> 4) & 0xf, rev & 0xf);
201 
202 	// Let the timer run (so we can use it as clocksource)
203 	fRegBase[TCLR] |= 1;
204 	fRegBase[TIER] = 2; // Enable overflow interrupt
205 
206 	install_io_interrupt_handler(fInterrupt, &OMAP3Timer::_InterruptWrapper, this, 0);
207 }
208 #endif
209