xref: /openbmc/qemu/hw/openrisc/cputimer.c (revision 53018216)
1*53018216SPaolo Bonzini /*
2*53018216SPaolo Bonzini  * QEMU OpenRISC timer support
3*53018216SPaolo Bonzini  *
4*53018216SPaolo Bonzini  * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5*53018216SPaolo Bonzini  *                         Zhizhou Zhang <etouzh@gmail.com>
6*53018216SPaolo Bonzini  *
7*53018216SPaolo Bonzini  * This library is free software; you can redistribute it and/or
8*53018216SPaolo Bonzini  * modify it under the terms of the GNU Lesser General Public
9*53018216SPaolo Bonzini  * License as published by the Free Software Foundation; either
10*53018216SPaolo Bonzini  * version 2 of the License, or (at your option) any later version.
11*53018216SPaolo Bonzini  *
12*53018216SPaolo Bonzini  * This library is distributed in the hope that it will be useful,
13*53018216SPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*53018216SPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*53018216SPaolo Bonzini  * Lesser General Public License for more details.
16*53018216SPaolo Bonzini  *
17*53018216SPaolo Bonzini  * You should have received a copy of the GNU Lesser General Public
18*53018216SPaolo Bonzini  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19*53018216SPaolo Bonzini  */
20*53018216SPaolo Bonzini 
21*53018216SPaolo Bonzini #include "cpu.h"
22*53018216SPaolo Bonzini #include "hw/hw.h"
23*53018216SPaolo Bonzini #include "qemu/timer.h"
24*53018216SPaolo Bonzini 
25*53018216SPaolo Bonzini #define TIMER_FREQ    (20 * 1000 * 1000)    /* 20MHz */
26*53018216SPaolo Bonzini 
27*53018216SPaolo Bonzini /* The time when TTCR changes */
28*53018216SPaolo Bonzini static uint64_t last_clk;
29*53018216SPaolo Bonzini static int is_counting;
30*53018216SPaolo Bonzini 
31*53018216SPaolo Bonzini void cpu_openrisc_count_update(OpenRISCCPU *cpu)
32*53018216SPaolo Bonzini {
33*53018216SPaolo Bonzini     uint64_t now, next;
34*53018216SPaolo Bonzini     uint32_t wait;
35*53018216SPaolo Bonzini 
36*53018216SPaolo Bonzini     now = qemu_get_clock_ns(vm_clock);
37*53018216SPaolo Bonzini     if (!is_counting) {
38*53018216SPaolo Bonzini         qemu_del_timer(cpu->env.timer);
39*53018216SPaolo Bonzini         last_clk = now;
40*53018216SPaolo Bonzini         return;
41*53018216SPaolo Bonzini     }
42*53018216SPaolo Bonzini 
43*53018216SPaolo Bonzini     cpu->env.ttcr += (uint32_t)muldiv64(now - last_clk, TIMER_FREQ,
44*53018216SPaolo Bonzini                                         get_ticks_per_sec());
45*53018216SPaolo Bonzini     last_clk = now;
46*53018216SPaolo Bonzini 
47*53018216SPaolo Bonzini     if ((cpu->env.ttmr & TTMR_TP) <= (cpu->env.ttcr & TTMR_TP)) {
48*53018216SPaolo Bonzini         wait = TTMR_TP - (cpu->env.ttcr & TTMR_TP) + 1;
49*53018216SPaolo Bonzini         wait += cpu->env.ttmr & TTMR_TP;
50*53018216SPaolo Bonzini     } else {
51*53018216SPaolo Bonzini         wait = (cpu->env.ttmr & TTMR_TP) - (cpu->env.ttcr & TTMR_TP);
52*53018216SPaolo Bonzini     }
53*53018216SPaolo Bonzini 
54*53018216SPaolo Bonzini     next = now + muldiv64(wait, get_ticks_per_sec(), TIMER_FREQ);
55*53018216SPaolo Bonzini     qemu_mod_timer(cpu->env.timer, next);
56*53018216SPaolo Bonzini }
57*53018216SPaolo Bonzini 
58*53018216SPaolo Bonzini void cpu_openrisc_count_start(OpenRISCCPU *cpu)
59*53018216SPaolo Bonzini {
60*53018216SPaolo Bonzini     is_counting = 1;
61*53018216SPaolo Bonzini     cpu_openrisc_count_update(cpu);
62*53018216SPaolo Bonzini }
63*53018216SPaolo Bonzini 
64*53018216SPaolo Bonzini void cpu_openrisc_count_stop(OpenRISCCPU *cpu)
65*53018216SPaolo Bonzini {
66*53018216SPaolo Bonzini     is_counting = 0;
67*53018216SPaolo Bonzini     cpu_openrisc_count_update(cpu);
68*53018216SPaolo Bonzini }
69*53018216SPaolo Bonzini 
70*53018216SPaolo Bonzini static void openrisc_timer_cb(void *opaque)
71*53018216SPaolo Bonzini {
72*53018216SPaolo Bonzini     OpenRISCCPU *cpu = opaque;
73*53018216SPaolo Bonzini 
74*53018216SPaolo Bonzini     if ((cpu->env.ttmr & TTMR_IE) &&
75*53018216SPaolo Bonzini          qemu_timer_expired(cpu->env.timer, qemu_get_clock_ns(vm_clock))) {
76*53018216SPaolo Bonzini         cpu->env.ttmr |= TTMR_IP;
77*53018216SPaolo Bonzini         cpu->env.interrupt_request |= CPU_INTERRUPT_TIMER;
78*53018216SPaolo Bonzini     }
79*53018216SPaolo Bonzini 
80*53018216SPaolo Bonzini     switch (cpu->env.ttmr & TTMR_M) {
81*53018216SPaolo Bonzini     case TIMER_NONE:
82*53018216SPaolo Bonzini         break;
83*53018216SPaolo Bonzini     case TIMER_INTR:
84*53018216SPaolo Bonzini         cpu->env.ttcr = 0;
85*53018216SPaolo Bonzini         cpu_openrisc_count_start(cpu);
86*53018216SPaolo Bonzini         break;
87*53018216SPaolo Bonzini     case TIMER_SHOT:
88*53018216SPaolo Bonzini         cpu_openrisc_count_stop(cpu);
89*53018216SPaolo Bonzini         break;
90*53018216SPaolo Bonzini     case TIMER_CONT:
91*53018216SPaolo Bonzini         cpu_openrisc_count_start(cpu);
92*53018216SPaolo Bonzini         break;
93*53018216SPaolo Bonzini     }
94*53018216SPaolo Bonzini }
95*53018216SPaolo Bonzini 
96*53018216SPaolo Bonzini void cpu_openrisc_clock_init(OpenRISCCPU *cpu)
97*53018216SPaolo Bonzini {
98*53018216SPaolo Bonzini     cpu->env.timer = qemu_new_timer_ns(vm_clock, &openrisc_timer_cb, cpu);
99*53018216SPaolo Bonzini     cpu->env.ttmr = 0x00000000;
100*53018216SPaolo Bonzini     cpu->env.ttcr = 0x00000000;
101*53018216SPaolo Bonzini }
102