xref: /haiku/src/system/kernel/arch/arm/soc_pxa.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 #include <vm/vm.h>
2 
3 #include "soc_pxa.h"
4 
5 /* PXA Interrupt Controller Registers */
6 #define PXA_ICIP	0x00
7 #define PXA_ICMR	0x01
8 #define PXA_ICFP	0x03
9 #define PXA_ICMR2	0x28
10 
11 void
12 PXAInterruptController::EnableInterrupt(int irq)
13 {
14 	if (irq <= 31) {
15 		fRegBase[PXA_ICMR] |= 1 << irq;
16 		return;
17 	}
18 
19 	fRegBase[PXA_ICMR2] |= 1 << (irq - 32);
20 }
21 
22 
23 void
24 PXAInterruptController::DisableInterrupt(int irq)
25 {
26 	if (irq <= 31) {
27 		fRegBase[PXA_ICMR] &= ~(1 << irq);
28 		return;
29 	}
30 
31 	fRegBase[PXA_ICMR2] &= ~(1 << (irq - 32));
32 }
33 
34 
35 void
36 PXAInterruptController::HandleInterrupt()
37 {
38 	for (int i=0; i < 32; i++) {
39 		if (fRegBase[PXA_ICIP] & (1 << i))
40 			int_io_interrupt_handler(i, true);
41 	}
42 }
43 
44 
45 PXAInterruptController::PXAInterruptController(uint32_t reg_base)
46 {
47 	fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "intc-pxa", (void**)&fRegBase,
48 		B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
49 		reg_base, false);
50 	if (fRegArea < 0)
51 		panic("PXAInterruptController: cannot map registers!");
52 
53 	fRegBase[PXA_ICMR] = 0;
54 	fRegBase[PXA_ICMR2] = 0;
55 }
56 
57 
58 #define PXA_TIMERS_INTERRUPT	7 /* OST_4_11 */
59 
60 #define PXA_OSSR	0x05
61 #define PXA_OIER	0x07
62 #define PXA_OSCR4	0x10
63 #define PXA_OSCR5	0x11
64 #define PXA_OSMR4	0x20
65 #define PXA_OSMR5	0x21
66 #define PXA_OMCR4	0x30
67 #define PXA_OMCR5	0x31
68 
69 #define PXA_RES_S	(3 << 0)
70 #define PXA_RES_MS	(1 << 1)
71 #define PXA_RES_US	(1 << 2)
72 
73 #define US2S(bt)	((bt) / 1000000ULL)
74 #define US2MS(bt)	((bt) / 1000ULL)
75 
76 void
77 PXATimer::SetTimeout(bigtime_t timeout)
78 {
79 	uint32 val = timeout & UINT_MAX;
80 	uint32 res = PXA_RES_US;
81 
82 	if (timeout & ~UINT_MAX) {
83 		// Does not fit, so scale resolution down to milliseconds
84 		if (US2MS(timeout) & ~UINT_MAX) {
85 			// Still does not fit, scale down to seconds as last ditch attempt
86 			val = US2S(timeout) & UINT_MAX;
87 			res = PXA_RES_S;
88 		} else {
89 			// Fits in millisecond resolution
90 			val = US2MS(timeout) & UINT_MAX;
91 			res = PXA_RES_MS;
92 		}
93 	}
94 
95 	dprintf("arch_timer_set_hardware_timer(val=%" B_PRIu32 ", res=%" B_PRIu32 ")\n", val, res);
96 	fRegBase[PXA_OIER] |= (1 << 4);
97 	fRegBase[PXA_OMCR4] = res;
98 	fRegBase[PXA_OSMR4] = val;
99 	fRegBase[PXA_OSCR4] = 0; // start counting from 0 again
100 }
101 
102 void
103 PXATimer::Clear()
104 {
105 	fRegBase[PXA_OMCR4] = 0; // disable our timer
106 	fRegBase[PXA_OIER] &= ~(1 << 4);
107 }
108 
109 
110 bigtime_t
111 PXATimer::Time()
112 {
113 	if (fRegArea < 0)
114 		return 0;
115 
116 	return (fRegBase != NULL) ?
117 		fSystemTime + fRegBase[PXA_OSCR5] :
118 		0ULL;
119 }
120 
121 
122 int32
123 PXATimer::_InterruptWrapper(void *data)
124 {
125 	return ((PXATimer*)data)->HandleInterrupt();
126 }
127 
128 
129 int32
130 PXATimer::HandleInterrupt()
131 {
132 	if (fRegBase[PXA_OSSR] & (1 << 4)) {
133 		fRegBase[PXA_OSSR] |= (1 << 4);
134 		return timer_interrupt();
135 	}
136 
137 	if (fRegBase[PXA_OSSR]  & (1 << 5)) {
138 		fRegBase[PXA_OSSR] |= (1 << 5);
139 		fSystemTime += UINT_MAX + 1ULL;
140 	}
141 
142 	return B_HANDLED_INTERRUPT;
143 }
144 
145 
146 PXATimer::PXATimer(uint32_t reg_base)
147 {
148 	fRegArea = vm_map_physical_memory(B_SYSTEM_TEAM, "pxa-timer", (void**)&fRegBase,
149 		B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
150 		reg_base, false);
151 	if (fRegArea < 0)
152 		panic("Cannot map PXATimer registers!");
153 
154 	fRegBase[PXA_OIER] |= (1 << 5); // enable timekeeping timer
155 	fRegBase[PXA_OMCR5] = PXA_RES_US | (1 << 7);
156 	fRegBase[PXA_OSMR5] = UINT_MAX;
157 	fRegBase[PXA_OSCR5] = 0;
158 
159 	install_io_interrupt_handler(PXA_TIMERS_INTERRUPT, &PXATimer::_InterruptWrapper, NULL, 0);
160 }
161