xref: /haiku/src/system/kernel/arch/arm/arch_timer.cpp (revision 16c83730262f1e4f0fc69d80744bb36dcfbbe3af)
1 /*
2  * Copyright 2007-2012, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  * 		François Revol <revol@free.fr>
7  *              Ithamar R. Adema <ithamar@upgrade-android.com>
8  *
9  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
10  * Distributed under the terms of the NewOS License.
11  */
12 
13 
14 #include <boot/stage2.h>
15 #include <kernel.h>
16 #include <debug.h>
17 
18 #include <timer.h>
19 #include <arch/timer.h>
20 #include <arch/cpu.h>
21 
22 
23 //#define TRACE_ARCH_TIMER
24 #ifdef TRACE_ARCH_TIMER
25 #	define TRACE(x) dprintf x
26 #else
27 #	define TRACE(x) ;
28 #endif
29 
30 
31 #define PXA_TIMERS_PHYS_BASE	0x40A00000
32 #define PXA_TIMERS_SIZE		B_PAGE_SIZE
33 #define PXA_TIMERS_INTERRUPT	7 /* OST_4_11 */
34 
35 #define PXA_OSSR		0x05
36 #define PXA_OIER		0x07
37 #define PXA_OSCR4		0x10
38 #define PXA_OSCR5		0x11
39 #define PXA_OSMR4		0x20
40 #define PXA_OSMR5		0x21
41 #define PXA_OMCR4		0x30
42 #define PXA_OMCR5		0x31
43 
44 #define PXA_RES_S	(3 << 0)
45 #define PXA_RES_MS	(1 << 1)
46 #define PXA_RES_US	(1 << 2)
47 
48 #define US2S(bt)	((bt) / 1000000ULL)
49 #define US2MS(bt)	((bt) / 1000ULL)
50 
51 static area_id sPxaTimersArea = -1;
52 static uint32 *sPxaTimersBase = NULL;
53 static bigtime_t sSystemTime = 0;
54 
55 static int32
56 pxa_timer_interrupt(void *data)
57 {
58 	if (sPxaTimersBase[PXA_OSSR] & (1 << 4)) {
59 		sPxaTimersBase[PXA_OSSR] |= (1 << 4);
60 		return timer_interrupt();
61 	}
62 
63 	if (sPxaTimersBase[PXA_OSSR]  & (1 << 5)) {
64 		sPxaTimersBase[PXA_OSSR] |= (1 << 5);
65 		sSystemTime += UINT_MAX + 1ULL;
66 	}
67 
68 	return B_HANDLED_INTERRUPT;
69 }
70 
71 void
72 arch_timer_set_hardware_timer(bigtime_t timeout)
73 {
74 	uint32 val = timeout & UINT_MAX;
75 	uint32 res = PXA_RES_US;
76 
77 	if (timeout & ~UINT_MAX) {
78 		// Does not fit, so scale resolution down to milliseconds
79 		if (US2MS(timeout) & ~UINT_MAX) {
80 			// Still does not fit, scale down to seconds as last ditch attempt
81 			val = US2S(timeout) & UINT_MAX;
82 			res = PXA_RES_S;
83 		} else {
84 			// Fits in millisecond resolution
85 			val = US2MS(timeout) & UINT_MAX;
86 			res = PXA_RES_MS;
87 		}
88 	}
89 
90 	TRACE(("arch_timer_set_hardware_timer(val=%lu, res=%lu)\n", val, res));
91 	sPxaTimersBase[PXA_OIER] |= (1 << 4);
92 	sPxaTimersBase[PXA_OMCR4] = res;
93 	sPxaTimersBase[PXA_OSMR4] = val;
94 	sPxaTimersBase[PXA_OSCR4] = 0; // start counting from 0 again
95 }
96 
97 
98 void
99 arch_timer_clear_hardware_timer()
100 {
101 	TRACE(("arch_timer_clear_hardware_timer\n"));
102 
103 	sPxaTimersBase[PXA_OMCR4] = 0; // disable our timer
104 	sPxaTimersBase[PXA_OIER] &= ~(1 << 4);
105 }
106 
107 int
108 arch_init_timer(kernel_args *args)
109 {
110 	TRACE(("%s\n", __func__));
111 	sPxaTimersArea = map_physical_memory("pxa_timers", PXA_TIMERS_PHYS_BASE,
112 		PXA_TIMERS_SIZE, 0, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&sPxaTimersBase);
113 
114 	if (sPxaTimersArea < 0)
115 		return sPxaTimersArea;
116 
117 	sPxaTimersBase[PXA_OIER] |= (1 << 5); // enable timekeeping timer
118 	sPxaTimersBase[PXA_OMCR5] = PXA_RES_US | (1 << 7);
119 	sPxaTimersBase[PXA_OSMR5] = UINT_MAX;
120 	sPxaTimersBase[PXA_OSCR5] = 0;
121 
122 	install_io_interrupt_handler(PXA_TIMERS_INTERRUPT, &pxa_timer_interrupt, NULL, 0);
123 
124 	return B_OK;
125 }
126 
127 bigtime_t
128 system_time(void)
129 {
130 	if (sPxaTimersArea < 0)
131 		return 0;
132 
133 	return (sPxaTimersBase != NULL) ?
134 		sSystemTime + sPxaTimersBase[PXA_OSCR5] :
135 		0ULL;
136 }
137