From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Lx36P-0002Z1-Gb for qemu-devel@nongnu.org; Thu, 23 Apr 2009 13:52:49 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Lx36O-0002Yn-VS for qemu-devel@nongnu.org; Thu, 23 Apr 2009 13:52:49 -0400 Received: from [199.232.76.173] (port=57451 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Lx36O-0002Yk-R0 for qemu-devel@nongnu.org; Thu, 23 Apr 2009 13:52:48 -0400 Received: from flounder.pepperfish.net ([87.237.62.181]:40035) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1Lx36O-0003BN-6F for qemu-devel@nongnu.org; Thu, 23 Apr 2009 13:52:48 -0400 Received: from [10.112.102.2] (helo=jennifer.kylikki.org) by flounder.pepperfish.net with esmtps (Exim 4.69 #1 (Debian)) id 1Lx36M-0002YG-4G for ; Thu, 23 Apr 2009 18:52:46 +0100 Received: from derik.kyllikki.org ([192.168.7.20] helo=derik) by jennifer.kylikki.org with esmtp (Exim 4.63) (envelope-from ) id 1Lx36M-0005uW-HQ for qemu-devel@nongnu.org; Thu, 23 Apr 2009 18:52:46 +0100 Received: from vince by derik with local (Exim 4.69) (envelope-from ) id 1Lx36M-0003ml-FQ for qemu-devel@nongnu.org; Thu, 23 Apr 2009 18:52:46 +0100 Date: Thu, 23 Apr 2009 18:52:46 +0100 From: Vincent Sanders Subject: [Qemu-devel] [PATCH 4/16] S3C irq controller Message-ID: <20090423175246.GG4629@derik> References: <20090423171503.GC4629@derik> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20090423171503.GC4629@derik> List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org S3C IRQ controller Signed-off-by: Vincent Sanders --- s3c24xx_irq.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff -urN qemusvnclean/hw/s3c24xx_irq.c qemusvnpatches/hw/s3c24xx_irq.c --- qemusvnclean/hw/s3c24xx_irq.c 1970-01-01 01:00:00.000000000 +0100 +++ qemusvnpatches/hw/s3c24xx_irq.c 2009-04-23 16:00:07.000000000 +0100 @@ -0,0 +1,200 @@ +/* hw/s3c24xx_irq.c + * + * Samsung S3C24XX IRQ controller emulation + * + * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#include "hw.h" + +#include "s3c24xx.h" + +/* IRQ request status RW WORD */ +#define S3C_IRQ_SRCPND 0 +/* Interrupt mode control WR WORD */ +#define S3C_IRQ_INTMOD 1 +/* Interrupt mask control RW WORD */ +#define S3C_IRQ_INTMSK 2 +/* IRQ priority control WR WORD */ +#define S3C_IRQ_PRIORITY 3 +/* Interrupt request status RW WORD */ +#define S3C_IRQ_INTPND 4 +/* Interrupt request source offset RO WORD */ +#define S3C_IRQ_OFFSET 5 +/* Sub-source pending RW WORD */ +#define S3C_IRQ_SUBSRCPND 6 +/* Interrupt sub-mask RW WORD */ +#define S3C_IRQ_INTSUBMSK 7 + + +static void +s3c24xx_percolate_interrupt(S3CState *soc) +{ + /* Take the status of the srcpnd register, percolate it through, raise to + * CPU if necessary */ + uint32_t ints = (soc->irq_reg[S3C_IRQ_SRCPND] & + ~soc->irq_reg[S3C_IRQ_INTMSK]); + int fsb = ffs(ints); + + /* TODO: Priority encoder could go here */ + if (ints & soc->irq_reg[S3C_IRQ_INTMOD]) { + /* Detected a FIQ */ + cpu_interrupt(soc->cpu_env, CPU_INTERRUPT_FIQ); + return; + } else { + /* No FIQ here today */ + cpu_reset_interrupt(soc->cpu_env, CPU_INTERRUPT_FIQ); + } + + /* No FIQ, check for a normal IRQ */ + if (fsb) { + if ((soc->irq_reg[S3C_IRQ_INTPND] == 0) || + (soc->irq_reg[S3C_IRQ_INTPND] > 1<<(fsb-1))) { + /* Current INTPND is lower priority than fsb of ints (or empty) */ + soc->irq_reg[S3C_IRQ_INTPND] = 1<<(fsb-1); + soc->irq_reg[S3C_IRQ_OFFSET] = fsb-1; + } + } else { + /* No FSB, thus no IRQ, thus nothing to do yet */ + } + + if (soc->irq_reg[S3C_IRQ_INTPND] != 0) { + cpu_interrupt(soc->cpu_env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(soc->cpu_env, CPU_INTERRUPT_HARD); + } +} + +static void +s3c24xx_percolate_subsrc_interrupt(S3CState *soc) +{ + uint32_t ints; + + soc->irq_reg[S3C_IRQ_SRCPND] |= soc->irq_main_level; + soc->irq_reg[S3C_IRQ_SUBSRCPND] |= soc->irq_subsrc_level; + + ints = (soc->irq_reg[S3C_IRQ_SUBSRCPND] & + ~soc->irq_reg[S3C_IRQ_INTSUBMSK]); + + /* If UART0 has asserted, raise that */ + if( ints & 0x7 ) { + soc->irq_reg[S3C_IRQ_SRCPND] |= (1<<28); + } + + /* Ditto UART1 */ + if( ints & 0x7<<3 ) soc->irq_reg[S3C_IRQ_SRCPND] |= (1<<23); + + /* Ditto UART2 */ + if( ints & 0x7<<6 ) soc->irq_reg[S3C_IRQ_SRCPND] |= (1<<15); + + /* And percolate it through */ + s3c24xx_percolate_interrupt(soc); +} + +static void +s3c24xx_irq_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value) +{ + S3CState *soc = (S3CState *)opaque; + int addr = (addr_ >> 2) & 7; + + if (addr == S3C_IRQ_SRCPND || + addr == S3C_IRQ_INTPND || + addr == S3C_IRQ_SUBSRCPND) { + soc->irq_reg[addr] &= ~value; + } else { + soc->irq_reg[addr] = value; + } + + /* Start at the subsrc irqs and percolate from there */ + s3c24xx_percolate_subsrc_interrupt(soc); +} + +static uint32_t +s3c24xx_irq_read_f(void *opaque, target_phys_addr_t addr_) +{ + S3CState *soc = (S3CState *)opaque; + int addr = (addr_ >> 2) & 0x7; + + return soc->irq_reg[addr]; +} + + +static CPUReadMemoryFunc *s3c24xx_irq_read[] = { + &s3c24xx_irq_read_f, + &s3c24xx_irq_read_f, + &s3c24xx_irq_read_f, +}; + +static CPUWriteMemoryFunc *s3c24xx_irq_write[] = { + &s3c24xx_irq_write_f, + &s3c24xx_irq_write_f, + &s3c24xx_irq_write_f, +}; + +static void +s3c24xx_irq_set_interrupt_level(S3CState *soc, int irq_num, int level, int set_level) +{ + if (level) { + if (set_level) soc->irq_main_level |= 1<irq_reg[S3C_IRQ_SRCPND] |= 1<irq_main_level &= ~(1<irq_reg[S3C_IRQ_SRCPND] &= ~(1<irq_subsrc_level |= 1<irq_reg[S3C_IRQ_SUBSRCPND] |= 1<irq_subsrc_level &= ~(1<irq_reg[S3C_IRQ_SUBSRCPND] &= ~(1<irq_reg[S3C_IRQ_SRCPND] = 0x00; + soc->irq_reg[S3C_IRQ_INTMOD] = 0x00; + soc->irq_reg[S3C_IRQ_INTMSK] = 0xFFFFFFFF; + soc->irq_reg[S3C_IRQ_PRIORITY] = 0x7F; + soc->irq_reg[S3C_IRQ_INTPND] = 0x00; + soc->irq_reg[S3C_IRQ_OFFSET] = 0x00; + soc->irq_reg[S3C_IRQ_SUBSRCPND] = 0x00; + soc->irq_reg[S3C_IRQ_INTSUBMSK] = 0x7FF; + + /* Allocate the interrupts and return them. All 64 potential ones. + * We return them doubled up because the latter half are level where + * the former half are edge. + */ + return qemu_allocate_irqs(s3c24xx_irq_handler, soc, 128); +} -- Regards Vincent http://www.kyllikki.org/