2 Copyright © 2013-2015, The AROS Development Team. All rights reserved.
9 * We use the GPU Timer #1 to handle EClock updates, since GPU Timer #3 is used for VBlank,
10 * and Timers #0 and #2 are used by the GPU itself.
16 #include <aros/bootloader.h>
17 #include <aros/debug.h>
18 #include <aros/symbolsets.h>
19 #include <exec/execbase.h>
20 #include <exec/interrupts.h>
21 #include <hardware/intbits.h>
22 #include <proto/arossupport.h>
23 #include <proto/bootloader.h>
24 #include <proto/exec.h>
25 #include <proto/kernel.h>
28 #include "timer_intern.h"
29 #include "timer_macros.h"
34 /* Timer 1 (EClock) interrupt handler */
35 static void Timer1Tick(struct TimerBase
*TimerBase
, struct ExecBase
*SysBase
)
37 unsigned int last_CLO
, last_CHI
;
39 D(bug("[Timer] Timer1Tick()\n"));
41 if (!(TimerBase
) || !(SysBase
))
43 bug("[Timer] Timer1Tick: Bad Params!\n");
47 last_CHI
= TimerBase
->tb_Platform
.tbp_CHI
;
48 last_CLO
= TimerBase
->tb_Platform
.tbp_CLO
;
50 /* Aknowledge and update our timer interrupt */
51 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << TICK_TIMER
); //TimerBase->tb_Platform.tbp_cs;
52 TimerBase
->tb_Platform
.tbp_CHI
= *((volatile unsigned int *)(SYSTIMER_CHI
));
53 TimerBase
->tb_Platform
.tbp_CLO
= *((volatile unsigned int *)(SYSTIMER_CLO
));
55 D(bug("[Timer] Timer1Tick: Updating EClock..\n"));
56 D(bug("[Timer] Timer1Tick: diff_CHI = %d\n", (TimerBase
->tb_Platform
.tbp_CHI
- last_CHI
)));
57 D(bug("[Timer] Timer1Tick: diff_CLO = %d\n", (TimerBase
->tb_Platform
.tbp_CLO
- last_CLO
)));
59 TimerBase
->tb_Platform
.tbp_TickRate
.tv_secs
= 0;
60 if ((TimerBase
->tb_Platform
.tbp_CLO
- last_CLO
) > 0)
61 TimerBase
->tb_Platform
.tbp_TickRate
.tv_micro
= TimerBase
->tb_Platform
.tbp_CLO
- last_CLO
;
63 TimerBase
->tb_Platform
.tbp_TickRate
.tv_micro
= ((1000000 - last_CLO
) + TimerBase
->tb_Platform
.tbp_CLO
);
65 /* Increment EClock value and process microhz requests */
66 ADDTIME(&TimerBase
->tb_CurrentTime
, &TimerBase
->tb_Platform
.tbp_TickRate
);
67 ADDTIME(&TimerBase
->tb_Elapsed
, &TimerBase
->tb_Platform
.tbp_TickRate
);
68 TimerBase
->tb_ticks_total
++;
70 D(bug("[Timer] Timer1Tick: Processing events.. \n"));
72 handleMicroHZ(TimerBase
, SysBase
);
73 // handleEClock(TimerBase, SysBase);
75 D(bug("[Timer] Timer1Tick: Reconfiguring interrupt..\n"));
77 TimerBase
->tb_Platform
.tbp_CLO
= *((volatile unsigned int *)(SYSTIMER_CLO
));
78 *((volatile unsigned int *)(SYSTIMER_C0
+ (TICK_TIMER
* 4))) = (TimerBase
->tb_Platform
.tbp_CLO
+ (1000000 / TimerBase
->tb_eclock_rate
));
80 D(bug("[Timer] Timer1Tick: Done..\n"));
83 /****************************************************************************************/
84 int vblank_Init(struct TimerBase
*LIBBASE
);
86 static int Timer_Init(struct TimerBase
*TimerBase
)
88 D(bug("[Timer] Timer_Init: kernel.resource @ 0x%p\n", KernelBase
));
90 TimerBase
->tb_Platform
.tbp_periiobase
= KrnGetSystemAttr(KATTR_PeripheralBase
);
92 /* Install timer IRQ handler */
93 TimerBase
->tb_TimerIRQHandle
= KrnAddIRQHandler(IRQ_TIMER0
+ TICK_TIMER
, Timer1Tick
, TimerBase
, SysBase
);
94 if (!TimerBase
->tb_TimerIRQHandle
)
97 D(bug("[Timer] Timer_Init: TimerIRQHandle @ 0x%p\n", TimerBase
->tb_TimerIRQHandle
));
99 /* By default we want 100 Hz EClock */
100 TimerBase
->tb_eclock_rate
= 100;
103 * Since we are software-driven, we can just ask the user which
104 * frequencies he wishes to use.
106 BootLoaderBase
= OpenResource("bootloader.resource");
109 struct List
*args
= GetBootInfo(BL_Args
);
115 for (node
= args
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
117 if (strncasecmp(node
->ln_Name
, "eclock=", 7) == 0)
119 TimerBase
->tb_eclock_rate
= atoi(&node
->ln_Name
[7]);
126 /* Set ExecBase public field. */
127 SysBase
->ex_EClockFrequency
= TimerBase
->tb_eclock_rate
;
128 D(bug("[Timer] Timer frequency is %d\n", TimerBase
->tb_eclock_rate
));
130 /* Calculate timer period in us */
131 TimerBase
->tb_Platform
.tbp_TickRate
.tv_secs
= 0;
132 TimerBase
->tb_Platform
.tbp_TickRate
.tv_micro
= 1000000 / TimerBase
->tb_eclock_rate
;
134 /* Start up GPU timer #TICK_TIMER */
136 TimerBase
->tb_Platform
.tbp_CHI
= *((volatile unsigned int *)(SYSTIMER_CHI
));
137 TimerBase
->tb_Platform
.tbp_CLO
= *((volatile unsigned int *)(SYSTIMER_CLO
));
138 *((volatile unsigned int *)(SYSTIMER_C0
+ (TICK_TIMER
* 4))) = (TimerBase
->tb_Platform
.tbp_CLO
+ TimerBase
->tb_Platform
.tbp_TickRate
.tv_micro
);
141 vblank_Init(TimerBase
);
143 D(bug("[Timer] Timer_Init: configured GPU timer %d\n", TICK_TIMER
));
148 static int Timer_Expunge(struct TimerBase
*TimerBase
)
150 D(bug("[Timer] Timer_Expunge()\n"));
152 if (TimerBase
->tb_TimerIRQHandle
)
153 KrnRemIRQHandler(TimerBase
->tb_TimerIRQHandle
);
158 ADD2INITLIB(Timer_Init
, 0)
159 ADD2EXPUNGELIB(Timer_Expunge
, 0)