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