From patchwork Fri Sep 30 00:20:36 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Chubb X-Patchwork-Id: 117014 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BF9DB1007D4 for ; Fri, 30 Sep 2011 10:21:12 +1000 (EST) Received: from localhost ([::1]:42084 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R9Qqi-0001GJ-0p for incoming@patchwork.ozlabs.org; Thu, 29 Sep 2011 20:21:08 -0400 Received: from eggs.gnu.org ([140.186.70.92]:49693) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R9QqZ-0001G1-UJ for qemu-devel@nongnu.org; Thu, 29 Sep 2011 20:21:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1R9QqX-0004Xz-Pe for qemu-devel@nongnu.org; Thu, 29 Sep 2011 20:20:59 -0400 Received: from lemon.ertos.nicta.com.au ([203.143.174.143]:41516 helo=lemon.ken.nicta.com.au) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1R9QqX-0004Xt-3d for qemu-devel@nongnu.org; Thu, 29 Sep 2011 20:20:57 -0400 Received: from [2402:1800:4000:2:21d:e0ff:fe35:2bed] (port=40238 helo=croc.chubb.wattle.id.au) by lemon.ken.nicta.com.au with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.72) (envelope-from ) id 1R9QqG-0002it-4F; Fri, 30 Sep 2011 10:20:45 +1000 Date: Fri, 30 Sep 2011 10:20:36 +1000 Message-ID: From: Peter Chubb To: Peter Maydell In-Reply-To: References: User-Agent: Wanderlust/2.15.9 (Almost Unreal) SEMI/1.14.6 (Maruoka) FLIM/1.14.9 (=?UTF-8?B?R29qxY0=?=) APEL/10.8 Emacs/23.3 (x86_64-pc-linux-gnu) MULE/6.0 (HANACHIRUSATO) X-Face: GgFg(Z>fx((4\32hvXq<)|jndSniCH~~$D)Ka:P@e@JR1P%Vr}EwUdfwf-4j\rUs#JR{'h# !]])6%Jh~b$VA|ALhnpPiHu[-x~@<"@Iv&|%R)Fq[[, (&Z'O)Q)xCqe1\M[F8#9l8~}#u$S$Rm`S9% \'T@`:&8>Sb*c5d'=eDYI&GF`+t[LfDH="MP5rwOO]w>ALi7'=QJHz&y&C&TE_3j! Organization: National ICT Australia MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") X-SA-Exim-Connect-IP: 2402:1800:4000:2:21d:e0ff:fe35:2bed X-SA-Exim-Mail-From: peter.chubb@nicta.com.au X-SA-Exim-Version: 4.2.1 (built Mon, 22 Mar 2010 06:52:44 +0000) X-SA-Exim-Scanned: Yes (on lemon.ken.nicta.com.au) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 203.143.174.143 Cc: davidm@ok-labs.com, Peter Chubb , qemu-devel@nongnu.org, philipo@ok-labs.com, Paul Brook Subject: Re: [Qemu-devel] [PATCH] [ARM] Fix sp804 dual-timer X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Thanks Peter! Here's a reworked patch. From 7af8e24d6cbd9170a206b6aaac164e3934312b7c Mon Sep 17 00:00:00 2001 From: David Mirabito Date: Fri, 24 Jul 2009 11:43:14 +1000 Subject: [PATCH 53/57] Fix sp804 read/write for second timer. Properly implement the dual-timer read/write for the sp804 dual timer module. Based on ARM specs at http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html Signed-off-by: Peter Chubb Signed-off-by: David Mirabito Signed-off-by: Hans Jang --- hw/arm_timer.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 9 deletions(-) -- Dr Peter Chubb http://www.gelato.unsw.edu.au peterc AT gelato.unsw.edu.au http://www.ertos.nicta.com.au ERTOS within National ICT Australia Index: qemu-working/hw/arm_timer.c =================================================================== --- qemu-working.orig/hw/arm_timer.c 2011-09-29 12:40:24.657526348 +1000 +++ qemu-working/hw/arm_timer.c 2011-09-30 10:15:00.724397699 +1000 @@ -163,64 +163,108 @@ static arm_timer_state *arm_timer_init(u s->freq = freq; s->control = TIMER_CTRL_IE; bh = qemu_bh_new(arm_timer_tick, s); s->timer = ptimer_init(bh); vmstate_register(NULL, -1, &vmstate_arm_timer, s); return s; } /* ARM PrimeCell SP804 dual timer module. - Docs for this device don't seem to be publicly available. This - implementation is based on guesswork, the linux kernel sources and the - Integrator/CP timer modules. */ + * Docs at + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html +*/ typedef struct { SysBusDevice busdev; MemoryRegion iomem; arm_timer_state *timer[2]; int level[2]; qemu_irq irq; } sp804_state; +/* + * sp804_id should be: + * union { + * struct { + * uint32_t PartNumber:12; == 0x804 + * uint32_t DesignerID:8; == 'A' + * uint32_t Revision:4; == 1 + * uint32_t Configurations:6; == 0 + * }; + * uint8_t bytes[4]; + * }; + * but that gets into too many byte-ordering and packing issues. + */ +static const uint8_t sp804_id[] = {0x04, 0x18, 0x14, 0}; +static const uint8_t sp804_PrimeCellID[] = {0xB1, 0x05, 0xF0, 0x0D}; + /* Merge the IRQs from the two component devices. */ static void sp804_set_irq(void *opaque, int irq, int level) { sp804_state *s = (sp804_state *)opaque; s->level[irq] = level; qemu_set_irq(s->irq, s->level[0] || s->level[1]); } static uint64_t sp804_read(void *opaque, target_phys_addr_t offset, unsigned size) { sp804_state *s = (sp804_state *)opaque; - /* ??? Don't know the PrimeCell ID for this device. */ if (offset < 0x20) { return arm_timer_read(s->timer[0], offset); - } else { + } + if (offset < 0x40) { return arm_timer_read(s->timer[1], offset - 0x20); } + + /* + * Ids are packed into a word, then accessed one byte per word. + */ + /* TimerPeriphID */ + if (offset >= 0xfe0 && offset <= 0xfec) + return sp804_id[(offset - 0xfe0) >> 2]; + /* PrimeCellID */ + if (offset >= 0xff0 && offset <= 0xffc) + return sp804_PrimeCellID[(offset - 0xff0) >> 2] + + switch(offset){ + /* Integration Test control registers, which we won't support */ + case 0xf00: /* TimerITCR */ + case 0xf04: /* TimerITOP (strictly write only but..) */ + return 0; + + } + + hw_error("sp804_read: Bad offset %x\n", (int)offset); + return 0; } static void sp804_write(void *opaque, target_phys_addr_t offset, uint64_t value, unsigned size) { sp804_state *s = (sp804_state *)opaque; if (offset < 0x20) { arm_timer_write(s->timer[0], offset, value); - } else { + return; + } + + if (offset < 0x40) { arm_timer_write(s->timer[1], offset - 0x20, value); - } + return; + } + + /* Technically we could be writing to the Test Registers, but not likely */ + hw_error("sp804_write: Bad offset %x\n", (int)offset); } static const MemoryRegionOps sp804_ops = { .read = sp804_read, .write = sp804_write, .endianness = DEVICE_NATIVE_ENDIAN, }; static const VMStateDescription vmstate_sp804 = { .name = "sp804", @@ -262,36 +306,37 @@ typedef struct { } icp_pit_state; static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset, unsigned size) { icp_pit_state *s = (icp_pit_state *)opaque; int n; /* ??? Don't know the PrimeCell ID for this device. */ n = offset >> 8; + if (n > 3) { - hw_error("sp804_read: Bad timer %d\n", n); + hw_error("icp_pit_read: Bad timer %d\n", n); } return arm_timer_read(s->timer[n], offset & 0xff); } static void icp_pit_write(void *opaque, target_phys_addr_t offset, uint64_t value, unsigned size) { icp_pit_state *s = (icp_pit_state *)opaque; int n; n = offset >> 8; if (n > 3) { - hw_error("sp804_write: Bad timer %d\n", n); + hw_error("icp_pit_write: Bad timer %d\n", n); } arm_timer_write(s->timer[n], offset & 0xff, value); } static const MemoryRegionOps icp_pit_ops = { .read = icp_pit_read, .write = icp_pit_write, .endianness = DEVICE_NATIVE_ENDIAN, };