From patchwork Fri May 28 17:43:15 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: cmchao X-Patchwork-Id: 53934 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 8A9F1B7D20 for ; Sat, 29 May 2010 03:49:52 +1000 (EST) Received: from localhost ([127.0.0.1]:34410 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OI3fJ-0007oj-F8 for incoming@patchwork.ozlabs.org; Fri, 28 May 2010 13:48:13 -0400 Received: from [140.186.70.92] (port=39624 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OI3b2-0005Td-Cd for qemu-devel@nongnu.org; Fri, 28 May 2010 13:43:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OI3b0-0007vx-6P for qemu-devel@nongnu.org; Fri, 28 May 2010 13:43:48 -0400 Received: from mail-px0-f173.google.com ([209.85.212.173]:42244) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OI3az-0007vN-QJ for qemu-devel@nongnu.org; Fri, 28 May 2010 13:43:46 -0400 Received: by mail-px0-f173.google.com with SMTP id 2so675814pxi.4 for ; Fri, 28 May 2010 10:43:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer:in-reply-to:references; bh=ot1uMRuE3H4hOooUe2CuA8nrvSDO55aCothxrBCCn/A=; b=oEO3MESXy1deIms/SQpEjg8J0d3b9ZZlCBJwrdpO3QaJQhOLuwqlx1X8lr99ZIk/K3 NyD5n5tLX0ty34gzbvtILNPdZaDSo4daL77j1iniOy1TZ1wakIjOrUxMx3yQFeWtBahm /sLkn5KftA/UKZwZa20HCVQNpxPUpdQVJ0Uic= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=OIA/JgNyfhQTlk29uFuW/Rq+NcD/zXXFjjtZqtpMmA/qVTELl+Uti+hIX/RvQw8cx1 Y1pyptiTiP+SSxFvSBxt2zzdrYNc07KexcBAlo7bweOaFbitz+3ccC5tyt2eOXol+kLA FQ4D49dROOKGFKE3gXXpJ6uRPc4bOr1NzptO8= Received: by 10.140.88.9 with SMTP id l9mr482925rvb.286.1275068625302; Fri, 28 May 2010 10:43:45 -0700 (PDT) Received: from localhost.localdomain (114-44-100-131.dynamic.hinet.net [114.44.100.131]) by mx.google.com with ESMTPS id o38sm2248891rvp.12.2010.05.28.10.43.42 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 28 May 2010 10:43:44 -0700 (PDT) From: cmchao To: qemu-devel@nongnu.org Date: Sat, 29 May 2010 01:43:15 +0800 Message-Id: <1275068605-14475-3-git-send-email-cmchao@gmail.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1275068605-14475-1-git-send-email-cmchao@gmail.com> References: <1275068605-14475-1-git-send-email-cmchao@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: cmchao Subject: [Qemu-devel] [PATCH 02/12] hw/omap2.c : separate gpio module X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: cmchao --- hw/omap.h | 3 + hw/omap2.c | 523 -------------------------------------------------------- hw/omap_gpio.c | 523 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 526 insertions(+), 523 deletions(-) diff --git a/hw/omap.h b/hw/omap.h index ebd166f..a37ee54 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -668,6 +668,7 @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s); void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler); void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down); +/* omap1 gpio module interface */ struct omap_gpio_s; struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, qemu_irq irq, omap_clk clk); @@ -675,9 +676,11 @@ void omap_gpio_reset(struct omap_gpio_s *s); qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s); void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler); +/* omap2 gpio interface */ struct omap_gpif_s; struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules); +void omap_gpif_reset(struct omap_gpif_s *s); qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start); void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler); diff --git a/hw/omap2.c b/hw/omap2.c index bd1b35e..bf5539d 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -557,529 +557,6 @@ void omap_synctimer_init(struct omap_target_agent_s *ta, omap_synctimer_readfn, omap_synctimer_writefn, s)); } -/* General-Purpose Interface of OMAP2 */ -struct omap2_gpio_s { - qemu_irq irq[2]; - qemu_irq wkup; - qemu_irq *in; - qemu_irq handler[32]; - - uint8_t config[2]; - uint32_t inputs; - uint32_t outputs; - uint32_t dir; - uint32_t level[2]; - uint32_t edge[2]; - uint32_t mask[2]; - uint32_t wumask; - uint32_t ints[2]; - uint32_t debounce; - uint8_t delay; -}; - -static inline void omap_gpio_module_int_update(struct omap2_gpio_s *s, - int line) -{ - qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]); -} - -static void omap_gpio_module_wake(struct omap2_gpio_s *s, int line) -{ - if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */ - return; - if (!(s->config[0] & (3 << 3))) /* Force Idle */ - return; - if (!(s->wumask & (1 << line))) - return; - - qemu_irq_raise(s->wkup); -} - -static inline void omap_gpio_module_out_update(struct omap2_gpio_s *s, - uint32_t diff) -{ - int ln; - - s->outputs ^= diff; - diff &= ~s->dir; - while ((ln = ffs(diff))) { - ln --; - qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1); - diff &= ~(1 << ln); - } -} - -static void omap_gpio_module_level_update(struct omap2_gpio_s *s, int line) -{ - s->ints[line] |= s->dir & - ((s->inputs & s->level[1]) | (~s->inputs & s->level[0])); - omap_gpio_module_int_update(s, line); -} - -static inline void omap_gpio_module_int(struct omap2_gpio_s *s, int line) -{ - s->ints[0] |= 1 << line; - omap_gpio_module_int_update(s, 0); - s->ints[1] |= 1 << line; - omap_gpio_module_int_update(s, 1); - omap_gpio_module_wake(s, line); -} - -static void omap_gpio_module_set(void *opaque, int line, int level) -{ - struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; - - if (level) { - if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1])) - omap_gpio_module_int(s, line); - s->inputs |= 1 << line; - } else { - if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0])) - omap_gpio_module_int(s, line); - s->inputs &= ~(1 << line); - } -} - -static void omap_gpio_module_reset(struct omap2_gpio_s *s) -{ - s->config[0] = 0; - s->config[1] = 2; - s->ints[0] = 0; - s->ints[1] = 0; - s->mask[0] = 0; - s->mask[1] = 0; - s->wumask = 0; - s->dir = ~0; - s->level[0] = 0; - s->level[1] = 0; - s->edge[0] = 0; - s->edge[1] = 0; - s->debounce = 0; - s->delay = 0; -} - -static uint32_t omap_gpio_module_read(void *opaque, target_phys_addr_t addr) -{ - struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; - - switch (addr) { - case 0x00: /* GPIO_REVISION */ - return 0x18; - - case 0x10: /* GPIO_SYSCONFIG */ - return s->config[0]; - - case 0x14: /* GPIO_SYSSTATUS */ - return 0x01; - - case 0x18: /* GPIO_IRQSTATUS1 */ - return s->ints[0]; - - case 0x1c: /* GPIO_IRQENABLE1 */ - case 0x60: /* GPIO_CLEARIRQENABLE1 */ - case 0x64: /* GPIO_SETIRQENABLE1 */ - return s->mask[0]; - - case 0x20: /* GPIO_WAKEUPENABLE */ - case 0x80: /* GPIO_CLEARWKUENA */ - case 0x84: /* GPIO_SETWKUENA */ - return s->wumask; - - case 0x28: /* GPIO_IRQSTATUS2 */ - return s->ints[1]; - - case 0x2c: /* GPIO_IRQENABLE2 */ - case 0x70: /* GPIO_CLEARIRQENABLE2 */ - case 0x74: /* GPIO_SETIREQNEABLE2 */ - return s->mask[1]; - - case 0x30: /* GPIO_CTRL */ - return s->config[1]; - - case 0x34: /* GPIO_OE */ - return s->dir; - - case 0x38: /* GPIO_DATAIN */ - return s->inputs; - - case 0x3c: /* GPIO_DATAOUT */ - case 0x90: /* GPIO_CLEARDATAOUT */ - case 0x94: /* GPIO_SETDATAOUT */ - return s->outputs; - - case 0x40: /* GPIO_LEVELDETECT0 */ - return s->level[0]; - - case 0x44: /* GPIO_LEVELDETECT1 */ - return s->level[1]; - - case 0x48: /* GPIO_RISINGDETECT */ - return s->edge[0]; - - case 0x4c: /* GPIO_FALLINGDETECT */ - return s->edge[1]; - - case 0x50: /* GPIO_DEBOUNCENABLE */ - return s->debounce; - - case 0x54: /* GPIO_DEBOUNCINGTIME */ - return s->delay; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_gpio_module_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; - uint32_t diff; - int ln; - - switch (addr) { - case 0x00: /* GPIO_REVISION */ - case 0x14: /* GPIO_SYSSTATUS */ - case 0x38: /* GPIO_DATAIN */ - OMAP_RO_REG(addr); - break; - - case 0x10: /* GPIO_SYSCONFIG */ - if (((value >> 3) & 3) == 3) - fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__); - if (value & 2) - omap_gpio_module_reset(s); - s->config[0] = value & 0x1d; - break; - - case 0x18: /* GPIO_IRQSTATUS1 */ - if (s->ints[0] & value) { - s->ints[0] &= ~value; - omap_gpio_module_level_update(s, 0); - } - break; - - case 0x1c: /* GPIO_IRQENABLE1 */ - s->mask[0] = value; - omap_gpio_module_int_update(s, 0); - break; - - case 0x20: /* GPIO_WAKEUPENABLE */ - s->wumask = value; - break; - - case 0x28: /* GPIO_IRQSTATUS2 */ - if (s->ints[1] & value) { - s->ints[1] &= ~value; - omap_gpio_module_level_update(s, 1); - } - break; - - case 0x2c: /* GPIO_IRQENABLE2 */ - s->mask[1] = value; - omap_gpio_module_int_update(s, 1); - break; - - case 0x30: /* GPIO_CTRL */ - s->config[1] = value & 7; - break; - - case 0x34: /* GPIO_OE */ - diff = s->outputs & (s->dir ^ value); - s->dir = value; - - value = s->outputs & ~s->dir; - while ((ln = ffs(diff))) { - diff &= ~(1 <<-- ln); - qemu_set_irq(s->handler[ln], (value >> ln) & 1); - } - - omap_gpio_module_level_update(s, 0); - omap_gpio_module_level_update(s, 1); - break; - - case 0x3c: /* GPIO_DATAOUT */ - omap_gpio_module_out_update(s, s->outputs ^ value); - break; - - case 0x40: /* GPIO_LEVELDETECT0 */ - s->level[0] = value; - omap_gpio_module_level_update(s, 0); - omap_gpio_module_level_update(s, 1); - break; - - case 0x44: /* GPIO_LEVELDETECT1 */ - s->level[1] = value; - omap_gpio_module_level_update(s, 0); - omap_gpio_module_level_update(s, 1); - break; - - case 0x48: /* GPIO_RISINGDETECT */ - s->edge[0] = value; - break; - - case 0x4c: /* GPIO_FALLINGDETECT */ - s->edge[1] = value; - break; - - case 0x50: /* GPIO_DEBOUNCENABLE */ - s->debounce = value; - break; - - case 0x54: /* GPIO_DEBOUNCINGTIME */ - s->delay = value; - break; - - case 0x60: /* GPIO_CLEARIRQENABLE1 */ - s->mask[0] &= ~value; - omap_gpio_module_int_update(s, 0); - break; - - case 0x64: /* GPIO_SETIRQENABLE1 */ - s->mask[0] |= value; - omap_gpio_module_int_update(s, 0); - break; - - case 0x70: /* GPIO_CLEARIRQENABLE2 */ - s->mask[1] &= ~value; - omap_gpio_module_int_update(s, 1); - break; - - case 0x74: /* GPIO_SETIREQNEABLE2 */ - s->mask[1] |= value; - omap_gpio_module_int_update(s, 1); - break; - - case 0x80: /* GPIO_CLEARWKUENA */ - s->wumask &= ~value; - break; - - case 0x84: /* GPIO_SETWKUENA */ - s->wumask |= value; - break; - - case 0x90: /* GPIO_CLEARDATAOUT */ - omap_gpio_module_out_update(s, s->outputs & value); - break; - - case 0x94: /* GPIO_SETDATAOUT */ - omap_gpio_module_out_update(s, ~s->outputs & value); - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static uint32_t omap_gpio_module_readp(void *opaque, target_phys_addr_t addr) -{ - return omap_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3); -} - -static void omap_gpio_module_writep(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - uint32_t cur = 0; - uint32_t mask = 0xffff; - - switch (addr & ~3) { - case 0x00: /* GPIO_REVISION */ - case 0x14: /* GPIO_SYSSTATUS */ - case 0x38: /* GPIO_DATAIN */ - OMAP_RO_REG(addr); - break; - - case 0x10: /* GPIO_SYSCONFIG */ - case 0x1c: /* GPIO_IRQENABLE1 */ - case 0x20: /* GPIO_WAKEUPENABLE */ - case 0x2c: /* GPIO_IRQENABLE2 */ - case 0x30: /* GPIO_CTRL */ - case 0x34: /* GPIO_OE */ - case 0x3c: /* GPIO_DATAOUT */ - case 0x40: /* GPIO_LEVELDETECT0 */ - case 0x44: /* GPIO_LEVELDETECT1 */ - case 0x48: /* GPIO_RISINGDETECT */ - case 0x4c: /* GPIO_FALLINGDETECT */ - case 0x50: /* GPIO_DEBOUNCENABLE */ - case 0x54: /* GPIO_DEBOUNCINGTIME */ - cur = omap_gpio_module_read(opaque, addr & ~3) & - ~(mask << ((addr & 3) << 3)); - - /* Fall through. */ - case 0x18: /* GPIO_IRQSTATUS1 */ - case 0x28: /* GPIO_IRQSTATUS2 */ - case 0x60: /* GPIO_CLEARIRQENABLE1 */ - case 0x64: /* GPIO_SETIRQENABLE1 */ - case 0x70: /* GPIO_CLEARIRQENABLE2 */ - case 0x74: /* GPIO_SETIREQNEABLE2 */ - case 0x80: /* GPIO_CLEARWKUENA */ - case 0x84: /* GPIO_SETWKUENA */ - case 0x90: /* GPIO_CLEARDATAOUT */ - case 0x94: /* GPIO_SETDATAOUT */ - value <<= (addr & 3) << 3; - omap_gpio_module_write(opaque, addr, cur | value); - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc * const omap_gpio_module_readfn[] = { - omap_gpio_module_readp, - omap_gpio_module_readp, - omap_gpio_module_read, -}; - -static CPUWriteMemoryFunc * const omap_gpio_module_writefn[] = { - omap_gpio_module_writep, - omap_gpio_module_writep, - omap_gpio_module_write, -}; - -static void omap_gpio_module_init(struct omap2_gpio_s *s, - struct omap_target_agent_s *ta, int region, - qemu_irq mpu, qemu_irq dsp, qemu_irq wkup, - omap_clk fclk, omap_clk iclk) -{ - int iomemtype; - - s->irq[0] = mpu; - s->irq[1] = dsp; - s->wkup = wkup; - s->in = qemu_allocate_irqs(omap_gpio_module_set, s, 32); - - iomemtype = l4_register_io_memory(omap_gpio_module_readfn, - omap_gpio_module_writefn, s); - omap_l4_attach(ta, region, iomemtype); -} - -struct omap_gpif_s { - struct omap2_gpio_s module[5]; - int modules; - - int autoidle; - int gpo; -}; - -static void omap_gpif_reset(struct omap_gpif_s *s) -{ - int i; - - for (i = 0; i < s->modules; i ++) - omap_gpio_module_reset(s->module + i); - - s->autoidle = 0; - s->gpo = 0; -} - -static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr) -{ - struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; - - switch (addr) { - case 0x00: /* IPGENERICOCPSPL_REVISION */ - return 0x18; - - case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ - return s->autoidle; - - case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ - return 0x01; - - case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ - return 0x00; - - case 0x40: /* IPGENERICOCPSPL_GPO */ - return s->gpo; - - case 0x50: /* IPGENERICOCPSPL_GPI */ - return 0x00; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; - - switch (addr) { - case 0x00: /* IPGENERICOCPSPL_REVISION */ - case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ - case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ - case 0x50: /* IPGENERICOCPSPL_GPI */ - OMAP_RO_REG(addr); - break; - - case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ - if (value & (1 << 1)) /* SOFTRESET */ - omap_gpif_reset(s); - s->autoidle = value & 1; - break; - - case 0x40: /* IPGENERICOCPSPL_GPO */ - s->gpo = value & 1; - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static CPUReadMemoryFunc * const omap_gpif_top_readfn[] = { - omap_gpif_top_read, - omap_gpif_top_read, - omap_gpif_top_read, -}; - -static CPUWriteMemoryFunc * const omap_gpif_top_writefn[] = { - omap_gpif_top_write, - omap_gpif_top_write, - omap_gpif_top_write, -}; - -struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, - qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules) -{ - int iomemtype, i; - struct omap_gpif_s *s = (struct omap_gpif_s *) - qemu_mallocz(sizeof(struct omap_gpif_s)); - int region[4] = { 0, 2, 4, 5 }; - - s->modules = modules; - for (i = 0; i < modules; i ++) - omap_gpio_module_init(s->module + i, ta, region[i], - irq[i], NULL, NULL, fclk[i], iclk); - - omap_gpif_reset(s); - - iomemtype = l4_register_io_memory(omap_gpif_top_readfn, - omap_gpif_top_writefn, s); - omap_l4_attach(ta, 1, iomemtype); - - return s; -} - -qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start) -{ - if (start >= s->modules * 32 || start < 0) - hw_error("%s: No GPIO line %i\n", __FUNCTION__, start); - return s->module[start >> 5].in + (start & 31); -} - -void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler) -{ - if (line >= s->modules * 32 || line < 0) - hw_error("%s: No GPIO line %i\n", __FUNCTION__, line); - s->module[line >> 5].handler[line & 31] = handler; -} - /* Multichannel SPI */ struct omap_mcspi_s { qemu_irq irq; diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index a162c1d..d978c7a 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -200,3 +200,526 @@ void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler) hw_error("%s: No GPIO line %i\n", __FUNCTION__, line); s->handler[line] = handler; } + +/* General-Purpose Interface of OMAP2 */ +struct omap2_gpio_s { + qemu_irq irq[2]; + qemu_irq wkup; + qemu_irq *in; + qemu_irq handler[32]; + + uint8_t config[2]; + uint32_t inputs; + uint32_t outputs; + uint32_t dir; + uint32_t level[2]; + uint32_t edge[2]; + uint32_t mask[2]; + uint32_t wumask; + uint32_t ints[2]; + uint32_t debounce; + uint8_t delay; +}; + +static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s, + int line) +{ + qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]); +} + +static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line) +{ + if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */ + return; + if (!(s->config[0] & (3 << 3))) /* Force Idle */ + return; + if (!(s->wumask & (1 << line))) + return; + + qemu_irq_raise(s->wkup); +} + +static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s, + uint32_t diff) +{ + int ln; + + s->outputs ^= diff; + diff &= ~s->dir; + while ((ln = ffs(diff))) { + ln --; + qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1); + diff &= ~(1 << ln); + } +} + +static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line) +{ + s->ints[line] |= s->dir & + ((s->inputs & s->level[1]) | (~s->inputs & s->level[0])); + omap2_gpio_module_int_update(s, line); +} + +static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line) +{ + s->ints[0] |= 1 << line; + omap2_gpio_module_int_update(s, 0); + s->ints[1] |= 1 << line; + omap2_gpio_module_int_update(s, 1); + omap2_gpio_module_wake(s, line); +} + +static void omap2_gpio_module_set(void *opaque, int line, int level) +{ + struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + + if (level) { + if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1])) + omap2_gpio_module_int(s, line); + s->inputs |= 1 << line; + } else { + if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0])) + omap2_gpio_module_int(s, line); + s->inputs &= ~(1 << line); + } +} + +static void omap2_gpio_module_reset(struct omap2_gpio_s *s) +{ + s->config[0] = 0; + s->config[1] = 2; + s->ints[0] = 0; + s->ints[1] = 0; + s->mask[0] = 0; + s->mask[1] = 0; + s->wumask = 0; + s->dir = ~0; + s->level[0] = 0; + s->level[1] = 0; + s->edge[0] = 0; + s->edge[1] = 0; + s->debounce = 0; + s->delay = 0; +} + +static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr) +{ + struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + + switch (addr) { + case 0x00: /* GPIO_REVISION */ + return 0x18; + + case 0x10: /* GPIO_SYSCONFIG */ + return s->config[0]; + + case 0x14: /* GPIO_SYSSTATUS */ + return 0x01; + + case 0x18: /* GPIO_IRQSTATUS1 */ + return s->ints[0]; + + case 0x1c: /* GPIO_IRQENABLE1 */ + case 0x60: /* GPIO_CLEARIRQENABLE1 */ + case 0x64: /* GPIO_SETIRQENABLE1 */ + return s->mask[0]; + + case 0x20: /* GPIO_WAKEUPENABLE */ + case 0x80: /* GPIO_CLEARWKUENA */ + case 0x84: /* GPIO_SETWKUENA */ + return s->wumask; + + case 0x28: /* GPIO_IRQSTATUS2 */ + return s->ints[1]; + + case 0x2c: /* GPIO_IRQENABLE2 */ + case 0x70: /* GPIO_CLEARIRQENABLE2 */ + case 0x74: /* GPIO_SETIREQNEABLE2 */ + return s->mask[1]; + + case 0x30: /* GPIO_CTRL */ + return s->config[1]; + + case 0x34: /* GPIO_OE */ + return s->dir; + + case 0x38: /* GPIO_DATAIN */ + return s->inputs; + + case 0x3c: /* GPIO_DATAOUT */ + case 0x90: /* GPIO_CLEARDATAOUT */ + case 0x94: /* GPIO_SETDATAOUT */ + return s->outputs; + + case 0x40: /* GPIO_LEVELDETECT0 */ + return s->level[0]; + + case 0x44: /* GPIO_LEVELDETECT1 */ + return s->level[1]; + + case 0x48: /* GPIO_RISINGDETECT */ + return s->edge[0]; + + case 0x4c: /* GPIO_FALLINGDETECT */ + return s->edge[1]; + + case 0x50: /* GPIO_DEBOUNCENABLE */ + return s->debounce; + + case 0x54: /* GPIO_DEBOUNCINGTIME */ + return s->delay; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque; + uint32_t diff; + int ln; + + switch (addr) { + case 0x00: /* GPIO_REVISION */ + case 0x14: /* GPIO_SYSSTATUS */ + case 0x38: /* GPIO_DATAIN */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* GPIO_SYSCONFIG */ + if (((value >> 3) & 3) == 3) + fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__); + if (value & 2) + omap2_gpio_module_reset(s); + s->config[0] = value & 0x1d; + break; + + case 0x18: /* GPIO_IRQSTATUS1 */ + if (s->ints[0] & value) { + s->ints[0] &= ~value; + omap2_gpio_module_level_update(s, 0); + } + break; + + case 0x1c: /* GPIO_IRQENABLE1 */ + s->mask[0] = value; + omap2_gpio_module_int_update(s, 0); + break; + + case 0x20: /* GPIO_WAKEUPENABLE */ + s->wumask = value; + break; + + case 0x28: /* GPIO_IRQSTATUS2 */ + if (s->ints[1] & value) { + s->ints[1] &= ~value; + omap2_gpio_module_level_update(s, 1); + } + break; + + case 0x2c: /* GPIO_IRQENABLE2 */ + s->mask[1] = value; + omap2_gpio_module_int_update(s, 1); + break; + + case 0x30: /* GPIO_CTRL */ + s->config[1] = value & 7; + break; + + case 0x34: /* GPIO_OE */ + diff = s->outputs & (s->dir ^ value); + s->dir = value; + + value = s->outputs & ~s->dir; + while ((ln = ffs(diff))) { + diff &= ~(1 <<-- ln); + qemu_set_irq(s->handler[ln], (value >> ln) & 1); + } + + omap2_gpio_module_level_update(s, 0); + omap2_gpio_module_level_update(s, 1); + break; + + case 0x3c: /* GPIO_DATAOUT */ + omap2_gpio_module_out_update(s, s->outputs ^ value); + break; + + case 0x40: /* GPIO_LEVELDETECT0 */ + s->level[0] = value; + omap2_gpio_module_level_update(s, 0); + omap2_gpio_module_level_update(s, 1); + break; + + case 0x44: /* GPIO_LEVELDETECT1 */ + s->level[1] = value; + omap2_gpio_module_level_update(s, 0); + omap2_gpio_module_level_update(s, 1); + break; + + case 0x48: /* GPIO_RISINGDETECT */ + s->edge[0] = value; + break; + + case 0x4c: /* GPIO_FALLINGDETECT */ + s->edge[1] = value; + break; + + case 0x50: /* GPIO_DEBOUNCENABLE */ + s->debounce = value; + break; + + case 0x54: /* GPIO_DEBOUNCINGTIME */ + s->delay = value; + break; + + case 0x60: /* GPIO_CLEARIRQENABLE1 */ + s->mask[0] &= ~value; + omap2_gpio_module_int_update(s, 0); + break; + + case 0x64: /* GPIO_SETIRQENABLE1 */ + s->mask[0] |= value; + omap2_gpio_module_int_update(s, 0); + break; + + case 0x70: /* GPIO_CLEARIRQENABLE2 */ + s->mask[1] &= ~value; + omap2_gpio_module_int_update(s, 1); + break; + + case 0x74: /* GPIO_SETIREQNEABLE2 */ + s->mask[1] |= value; + omap2_gpio_module_int_update(s, 1); + break; + + case 0x80: /* GPIO_CLEARWKUENA */ + s->wumask &= ~value; + break; + + case 0x84: /* GPIO_SETWKUENA */ + s->wumask |= value; + break; + + case 0x90: /* GPIO_CLEARDATAOUT */ + omap2_gpio_module_out_update(s, s->outputs & value); + break; + + case 0x94: /* GPIO_SETDATAOUT */ + omap2_gpio_module_out_update(s, ~s->outputs & value); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static uint32_t omap2_gpio_module_readp(void *opaque, target_phys_addr_t addr) +{ + return omap2_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3); +} + +static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + uint32_t cur = 0; + uint32_t mask = 0xffff; + + switch (addr & ~3) { + case 0x00: /* GPIO_REVISION */ + case 0x14: /* GPIO_SYSSTATUS */ + case 0x38: /* GPIO_DATAIN */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* GPIO_SYSCONFIG */ + case 0x1c: /* GPIO_IRQENABLE1 */ + case 0x20: /* GPIO_WAKEUPENABLE */ + case 0x2c: /* GPIO_IRQENABLE2 */ + case 0x30: /* GPIO_CTRL */ + case 0x34: /* GPIO_OE */ + case 0x3c: /* GPIO_DATAOUT */ + case 0x40: /* GPIO_LEVELDETECT0 */ + case 0x44: /* GPIO_LEVELDETECT1 */ + case 0x48: /* GPIO_RISINGDETECT */ + case 0x4c: /* GPIO_FALLINGDETECT */ + case 0x50: /* GPIO_DEBOUNCENABLE */ + case 0x54: /* GPIO_DEBOUNCINGTIME */ + cur = omap2_gpio_module_read(opaque, addr & ~3) & + ~(mask << ((addr & 3) << 3)); + + /* Fall through. */ + case 0x18: /* GPIO_IRQSTATUS1 */ + case 0x28: /* GPIO_IRQSTATUS2 */ + case 0x60: /* GPIO_CLEARIRQENABLE1 */ + case 0x64: /* GPIO_SETIRQENABLE1 */ + case 0x70: /* GPIO_CLEARIRQENABLE2 */ + case 0x74: /* GPIO_SETIREQNEABLE2 */ + case 0x80: /* GPIO_CLEARWKUENA */ + case 0x84: /* GPIO_SETWKUENA */ + case 0x90: /* GPIO_CLEARDATAOUT */ + case 0x94: /* GPIO_SETDATAOUT */ + value <<= (addr & 3) << 3; + omap2_gpio_module_write(opaque, addr, cur | value); + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc * const omap2_gpio_module_readfn[] = { + omap2_gpio_module_readp, + omap2_gpio_module_readp, + omap2_gpio_module_read, +}; + +static CPUWriteMemoryFunc * const omap2_gpio_module_writefn[] = { + omap2_gpio_module_writep, + omap2_gpio_module_writep, + omap2_gpio_module_write, +}; + +static void omap2_gpio_module_init(struct omap2_gpio_s *s, + struct omap_target_agent_s *ta, int region, + qemu_irq mpu, qemu_irq dsp, qemu_irq wkup, + omap_clk fclk, omap_clk iclk) +{ + int iomemtype; + + s->irq[0] = mpu; + s->irq[1] = dsp; + s->wkup = wkup; + s->in = qemu_allocate_irqs(omap2_gpio_module_set, s, 32); + + iomemtype = l4_register_io_memory(omap2_gpio_module_readfn, + omap2_gpio_module_writefn, s); + omap_l4_attach(ta, region, iomemtype); +} + +struct omap_gpif_s { + struct omap2_gpio_s module[5]; + int modules; + + int autoidle; + int gpo; +}; + +void omap_gpif_reset(struct omap_gpif_s *s) +{ + int i; + + for (i = 0; i < s->modules; i ++) + omap2_gpio_module_reset(s->module + i); + + s->autoidle = 0; + s->gpo = 0; +} + +static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; + + switch (addr) { + case 0x00: /* IPGENERICOCPSPL_REVISION */ + return 0x18; + + case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ + return s->autoidle; + + case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ + return 0x01; + + case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ + return 0x00; + + case 0x40: /* IPGENERICOCPSPL_GPO */ + return s->gpo; + + case 0x50: /* IPGENERICOCPSPL_GPI */ + return 0x00; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_gpif_s *s = (struct omap_gpif_s *) opaque; + + switch (addr) { + case 0x00: /* IPGENERICOCPSPL_REVISION */ + case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */ + case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */ + case 0x50: /* IPGENERICOCPSPL_GPI */ + OMAP_RO_REG(addr); + break; + + case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */ + if (value & (1 << 1)) /* SOFTRESET */ + omap_gpif_reset(s); + s->autoidle = value & 1; + break; + + case 0x40: /* IPGENERICOCPSPL_GPO */ + s->gpo = value & 1; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc * const omap_gpif_top_readfn[] = { + omap_gpif_top_read, + omap_gpif_top_read, + omap_gpif_top_read, +}; + +static CPUWriteMemoryFunc * const omap_gpif_top_writefn[] = { + omap_gpif_top_write, + omap_gpif_top_write, + omap_gpif_top_write, +}; + +struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta, + qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules) +{ + int iomemtype, i; + struct omap_gpif_s *s = (struct omap_gpif_s *) + qemu_mallocz(sizeof(struct omap_gpif_s)); + int region[4] = { 0, 2, 4, 5 }; + + s->modules = modules; + for (i = 0; i < modules; i ++) + omap2_gpio_module_init(s->module + i, ta, region[i], + irq[i], NULL, NULL, fclk[i], iclk); + + omap_gpif_reset(s); + + iomemtype = l4_register_io_memory(omap_gpif_top_readfn, + omap_gpif_top_writefn, s); + omap_l4_attach(ta, 1, iomemtype); + + return s; +} + +qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start) +{ + if (start >= s->modules * 32 || start < 0) + hw_error("%s: No GPIO line %i\n", __FUNCTION__, start); + return s->module[start >> 5].in + (start & 31); +} + +void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler) +{ + if (line >= s->modules * 32 || line < 0) + hw_error("%s: No GPIO line %i\n", __FUNCTION__, line); + s->module[line >> 5].handler[line & 31] = handler; +}