153018216SPaolo Bonzini /* 253018216SPaolo Bonzini * QEMU OpenRISC timer support 353018216SPaolo Bonzini * 453018216SPaolo Bonzini * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> 553018216SPaolo Bonzini * Zhizhou Zhang <etouzh@gmail.com> 653018216SPaolo Bonzini * 753018216SPaolo Bonzini * This library is free software; you can redistribute it and/or 853018216SPaolo Bonzini * modify it under the terms of the GNU Lesser General Public 953018216SPaolo Bonzini * License as published by the Free Software Foundation; either 10198a2d21SThomas Huth * version 2.1 of the License, or (at your option) any later version. 1153018216SPaolo Bonzini * 1253018216SPaolo Bonzini * This library is distributed in the hope that it will be useful, 1353018216SPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of 1453018216SPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553018216SPaolo Bonzini * Lesser General Public License for more details. 1653018216SPaolo Bonzini * 1753018216SPaolo Bonzini * You should have received a copy of the GNU Lesser General Public 1853018216SPaolo Bonzini * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1953018216SPaolo Bonzini */ 2053018216SPaolo Bonzini 21ed2decc6SPeter Maydell #include "qemu/osdep.h" 2253018216SPaolo Bonzini #include "cpu.h" 2353018216SPaolo Bonzini #include "hw/hw.h" 24*d6454270SMarkus Armbruster #include "migration/vmstate.h" 2553018216SPaolo Bonzini #include "qemu/timer.h" 2653018216SPaolo Bonzini 27ccaf1749SLaurent Vivier #define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */ 2853018216SPaolo Bonzini 296b4bbd6aSStafford Horne /* Tick Timer global state to allow all cores to be in sync */ 306b4bbd6aSStafford Horne typedef struct OR1KTimerState { 316b4bbd6aSStafford Horne uint32_t ttcr; 326b4bbd6aSStafford Horne uint64_t last_clk; 336b4bbd6aSStafford Horne } OR1KTimerState; 3453018216SPaolo Bonzini 356b4bbd6aSStafford Horne static OR1KTimerState *or1k_timer; 366b4bbd6aSStafford Horne 376b4bbd6aSStafford Horne void cpu_openrisc_count_set(OpenRISCCPU *cpu, uint32_t val) 386b4bbd6aSStafford Horne { 396b4bbd6aSStafford Horne or1k_timer->ttcr = val; 406b4bbd6aSStafford Horne } 416b4bbd6aSStafford Horne 426b4bbd6aSStafford Horne uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu) 436b4bbd6aSStafford Horne { 446b4bbd6aSStafford Horne return or1k_timer->ttcr; 456b4bbd6aSStafford Horne } 466b4bbd6aSStafford Horne 476b4bbd6aSStafford Horne /* Add elapsed ticks to ttcr */ 4853018216SPaolo Bonzini void cpu_openrisc_count_update(OpenRISCCPU *cpu) 4953018216SPaolo Bonzini { 50d5155217SSebastian Macke uint64_t now; 5153018216SPaolo Bonzini 526b4bbd6aSStafford Horne if (!cpu->env.is_counting) { 5353018216SPaolo Bonzini return; 5453018216SPaolo Bonzini } 55d5155217SSebastian Macke now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 566b4bbd6aSStafford Horne or1k_timer->ttcr += (uint32_t)((now - or1k_timer->last_clk) 576b4bbd6aSStafford Horne / TIMER_PERIOD); 586b4bbd6aSStafford Horne or1k_timer->last_clk = now; 59d5155217SSebastian Macke } 60d5155217SSebastian Macke 616b4bbd6aSStafford Horne /* Update the next timeout time as difference between ttmr and ttcr */ 62d5155217SSebastian Macke void cpu_openrisc_timer_update(OpenRISCCPU *cpu) 63d5155217SSebastian Macke { 64d5155217SSebastian Macke uint32_t wait; 65d5155217SSebastian Macke uint64_t now, next; 66d5155217SSebastian Macke 676b4bbd6aSStafford Horne if (!cpu->env.is_counting) { 68d5155217SSebastian Macke return; 69d5155217SSebastian Macke } 70d5155217SSebastian Macke 71d5155217SSebastian Macke cpu_openrisc_count_update(cpu); 726b4bbd6aSStafford Horne now = or1k_timer->last_clk; 7353018216SPaolo Bonzini 746b4bbd6aSStafford Horne if ((cpu->env.ttmr & TTMR_TP) <= (or1k_timer->ttcr & TTMR_TP)) { 756b4bbd6aSStafford Horne wait = TTMR_TP - (or1k_timer->ttcr & TTMR_TP) + 1; 7653018216SPaolo Bonzini wait += cpu->env.ttmr & TTMR_TP; 7753018216SPaolo Bonzini } else { 786b4bbd6aSStafford Horne wait = (cpu->env.ttmr & TTMR_TP) - (or1k_timer->ttcr & TTMR_TP); 7953018216SPaolo Bonzini } 80ccaf1749SLaurent Vivier next = now + (uint64_t)wait * TIMER_PERIOD; 81bc72ad67SAlex Bligh timer_mod(cpu->env.timer, next); 8253018216SPaolo Bonzini } 8353018216SPaolo Bonzini 8453018216SPaolo Bonzini void cpu_openrisc_count_start(OpenRISCCPU *cpu) 8553018216SPaolo Bonzini { 866b4bbd6aSStafford Horne cpu->env.is_counting = 1; 8753018216SPaolo Bonzini cpu_openrisc_count_update(cpu); 8853018216SPaolo Bonzini } 8953018216SPaolo Bonzini 9053018216SPaolo Bonzini void cpu_openrisc_count_stop(OpenRISCCPU *cpu) 9153018216SPaolo Bonzini { 92d5155217SSebastian Macke timer_del(cpu->env.timer); 9353018216SPaolo Bonzini cpu_openrisc_count_update(cpu); 946b4bbd6aSStafford Horne cpu->env.is_counting = 0; 9553018216SPaolo Bonzini } 9653018216SPaolo Bonzini 9753018216SPaolo Bonzini static void openrisc_timer_cb(void *opaque) 9853018216SPaolo Bonzini { 9953018216SPaolo Bonzini OpenRISCCPU *cpu = opaque; 10053018216SPaolo Bonzini 10153018216SPaolo Bonzini if ((cpu->env.ttmr & TTMR_IE) && 102bc72ad67SAlex Bligh timer_expired(cpu->env.timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL))) { 103259186a7SAndreas Färber CPUState *cs = CPU(cpu); 104259186a7SAndreas Färber 10553018216SPaolo Bonzini cpu->env.ttmr |= TTMR_IP; 106259186a7SAndreas Färber cs->interrupt_request |= CPU_INTERRUPT_TIMER; 10753018216SPaolo Bonzini } 10853018216SPaolo Bonzini 10953018216SPaolo Bonzini switch (cpu->env.ttmr & TTMR_M) { 11053018216SPaolo Bonzini case TIMER_NONE: 11153018216SPaolo Bonzini break; 11253018216SPaolo Bonzini case TIMER_INTR: 1136b4bbd6aSStafford Horne or1k_timer->ttcr = 0; 11453018216SPaolo Bonzini break; 11553018216SPaolo Bonzini case TIMER_SHOT: 11653018216SPaolo Bonzini cpu_openrisc_count_stop(cpu); 11753018216SPaolo Bonzini break; 11853018216SPaolo Bonzini case TIMER_CONT: 11953018216SPaolo Bonzini break; 12053018216SPaolo Bonzini } 121d5155217SSebastian Macke 122d5155217SSebastian Macke cpu_openrisc_timer_update(cpu); 123373b259bSStafford Horne qemu_cpu_kick(CPU(cpu)); 12453018216SPaolo Bonzini } 12553018216SPaolo Bonzini 1266b4bbd6aSStafford Horne static const VMStateDescription vmstate_or1k_timer = { 1276b4bbd6aSStafford Horne .name = "or1k_timer", 1286b4bbd6aSStafford Horne .version_id = 1, 1296b4bbd6aSStafford Horne .minimum_version_id = 1, 1306b4bbd6aSStafford Horne .fields = (VMStateField[]) { 1316b4bbd6aSStafford Horne VMSTATE_UINT32(ttcr, OR1KTimerState), 1326b4bbd6aSStafford Horne VMSTATE_UINT64(last_clk, OR1KTimerState), 1336b4bbd6aSStafford Horne VMSTATE_END_OF_LIST() 1346b4bbd6aSStafford Horne } 1356b4bbd6aSStafford Horne }; 1366b4bbd6aSStafford Horne 13753018216SPaolo Bonzini void cpu_openrisc_clock_init(OpenRISCCPU *cpu) 13853018216SPaolo Bonzini { 139bc72ad67SAlex Bligh cpu->env.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &openrisc_timer_cb, cpu); 14053018216SPaolo Bonzini cpu->env.ttmr = 0x00000000; 1416b4bbd6aSStafford Horne 1426b4bbd6aSStafford Horne if (or1k_timer == NULL) { 1436b4bbd6aSStafford Horne or1k_timer = g_new0(OR1KTimerState, 1); 1446b4bbd6aSStafford Horne vmstate_register(NULL, 0, &vmstate_or1k_timer, or1k_timer); 1456b4bbd6aSStafford Horne } 14653018216SPaolo Bonzini } 147