2 Copyright © 2013-2019, 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
;
38 D(unsigned int last_CHI
);
40 D(bug("[Timer] Timer1Tick()\n"));
42 if (!(TimerBase
) || !(SysBase
))
44 bug("[Timer] Timer1Tick: Bad Params!\n");
48 D(last_CHI
= TimerBase
->tb_Platform
.tbp_CHI
);
49 last_CLO
= TimerBase
->tb_Platform
.tbp_CLO
;
51 /* Aknowledge and update our timer interrupt */
52 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << TICK_TIMER
); //TimerBase->tb_Platform.tbp_cs;
53 TimerBase
->tb_Platform
.tbp_CHI
= *((volatile unsigned int *)(SYSTIMER_CHI
));
54 TimerBase
->tb_Platform
.tbp_CLO
= *((volatile unsigned int *)(SYSTIMER_CLO
));
56 D(bug("[Timer] Timer1Tick: Updating EClock..\n"));
57 D(bug("[Timer] Timer1Tick: diff_CHI = %d\n", (TimerBase
->tb_Platform
.tbp_CHI
- last_CHI
)));
58 D(bug("[Timer] Timer1Tick: diff_CLO = %d\n", (TimerBase
->tb_Platform
.tbp_CLO
- last_CLO
)));
60 TimerBase
->tb_Platform
.tbp_TickRate
.tv_secs
= 0;
61 if ((TimerBase
->tb_Platform
.tbp_CLO
- last_CLO
) > 0)
62 TimerBase
->tb_Platform
.tbp_TickRate
.tv_micro
= TimerBase
->tb_Platform
.tbp_CLO
- last_CLO
;
64 TimerBase
->tb_Platform
.tbp_TickRate
.tv_micro
= ((1000000 - last_CLO
) + TimerBase
->tb_Platform
.tbp_CLO
);
66 /* Increment EClock value and process microhz requests */
67 ADDTIME(&TimerBase
->tb_CurrentTime
, &TimerBase
->tb_Platform
.tbp_TickRate
);
68 ADDTIME(&TimerBase
->tb_Elapsed
, &TimerBase
->tb_Platform
.tbp_TickRate
);
69 TimerBase
->tb_ticks_total
++;
71 D(bug("[Timer] Timer1Tick: Processing events.. \n"));
73 handleMicroHZ(TimerBase
, SysBase
);
74 // handleEClock(TimerBase, SysBase);
76 D(bug("[Timer] Timer1Tick: Reconfiguring interrupt..\n"));
78 TimerBase
->tb_Platform
.tbp_CLO
= *((volatile unsigned int *)(SYSTIMER_CLO
));
79 *((volatile unsigned int *)(SYSTIMER_C0
+ (TICK_TIMER
* 4))) = (TimerBase
->tb_Platform
.tbp_CLO
+ (1000000 / TimerBase
->tb_eclock_rate
));
81 D(bug("[Timer] Timer1Tick: Done..\n"));
84 /****************************************************************************************/
85 int vblank_Init(struct TimerBase
*LIBBASE
);
87 static int Timer_Init(struct TimerBase
*TimerBase
)
89 D(bug("[Timer] Timer_Init: kernel.resource @ 0x%p\n", KernelBase
));
91 TimerBase
->tb_Platform
.tbp_periiobase
= KrnGetSystemAttr(KATTR_PeripheralBase
);
93 /* Install timer IRQ handler */
94 TimerBase
->tb_TimerIRQHandle
= KrnAddIRQHandler(IRQ_TIMER0
+ TICK_TIMER
, Timer1Tick
, TimerBase
, SysBase
);
95 if (!TimerBase
->tb_TimerIRQHandle
)
98 D(bug("[Timer] Timer_Init: TimerIRQHandle @ 0x%p\n", TimerBase
->tb_TimerIRQHandle
));
100 /* By default we want 100 Hz EClock */
101 TimerBase
->tb_eclock_rate
= 100;
104 * Since we are software-driven, we can just ask the user which
105 * frequencies he wishes to use.
107 BootLoaderBase
= OpenResource("bootloader.resource");
110 struct List
*args
= GetBootInfo(BL_Args
);
116 for (node
= args
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
118 if (strncasecmp(node
->ln_Name
, "eclock=", 7) == 0)
120 TimerBase
->tb_eclock_rate
= atoi(&node
->ln_Name
[7]);
127 /* Set ExecBase public field. */
128 SysBase
->ex_EClockFrequency
= TimerBase
->tb_eclock_rate
;
129 D(bug("[Timer] Timer frequency is %d\n", TimerBase
->tb_eclock_rate
));
131 /* Calculate timer period in us */
132 TimerBase
->tb_Platform
.tbp_TickRate
.tv_secs
= 0;
133 TimerBase
->tb_Platform
.tbp_TickRate
.tv_micro
= 1000000 / TimerBase
->tb_eclock_rate
;
135 /* Start up GPU timer #TICK_TIMER */
137 TimerBase
->tb_Platform
.tbp_CHI
= *((volatile unsigned int *)(SYSTIMER_CHI
));
138 TimerBase
->tb_Platform
.tbp_CLO
= *((volatile unsigned int *)(SYSTIMER_CLO
));
139 *((volatile unsigned int *)(SYSTIMER_C0
+ (TICK_TIMER
* 4))) = (TimerBase
->tb_Platform
.tbp_CLO
+ TimerBase
->tb_Platform
.tbp_TickRate
.tv_micro
);
142 vblank_Init(TimerBase
);
144 D(bug("[Timer] Timer_Init: configured GPU timer %d\n", TICK_TIMER
));
149 static int Timer_Expunge(struct TimerBase
*TimerBase
)
151 D(bug("[Timer] Timer_Expunge()\n"));
153 if (TimerBase
->tb_TimerIRQHandle
)
154 KrnRemIRQHandler(TimerBase
->tb_TimerIRQHandle
);
159 ADD2INITLIB(Timer_Init
, 0)
160 ADD2EXPUNGELIB(Timer_Expunge
, 0)