From patchwork Tue Feb 9 22:15:10 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 8266121 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9EAB79F38B for ; Tue, 9 Feb 2016 22:24:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id BF24720218 for ; Tue, 9 Feb 2016 22:24:22 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B56C92022D for ; Tue, 9 Feb 2016 22:24:21 +0000 (UTC) Received: from localhost ([::1]:32995 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aTGhp-0005sv-3S for patchwork-qemu-devel@patchwork.kernel.org; Tue, 09 Feb 2016 17:24:21 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47115) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aTGba-0004HP-43 for qemu-devel@nongnu.org; Tue, 09 Feb 2016 17:17:55 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aTGbV-0001BD-0t for qemu-devel@nongnu.org; Tue, 09 Feb 2016 17:17:53 -0500 Received: from mail-bl2nam02on0079.outbound.protection.outlook.com ([104.47.38.79]:1664 helo=NAM02-BL2-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aTGbU-0001Ap-Qc for qemu-devel@nongnu.org; Tue, 09 Feb 2016 17:17:48 -0500 Received: from SN1NAM02FT031.eop-nam02.prod.protection.outlook.com (10.152.72.57) by SN1NAM02HT029.eop-nam02.prod.protection.outlook.com (10.152.73.104) with Microsoft SMTP Server (TLS) id 15.1.409.7; Tue, 9 Feb 2016 22:17:47 +0000 Authentication-Results: spf=fail (sender IP is 149.199.60.96) smtp.mailfrom=xilinx.com; linaro.org; dkim=none (message not signed) header.d=none; linaro.org; dmarc=none action=none header.from=xilinx.com; Received-SPF: Fail (protection.outlook.com: domain of xilinx.com does not designate 149.199.60.96 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.60.96; helo=xsj-tvapsmtpgw01; Received: from xsj-tvapsmtpgw01 (149.199.60.96) by SN1NAM02FT031.mail.protection.outlook.com (10.152.72.116) with Microsoft SMTP Server (TLS) id 15.1.409.7 via Frontend Transport; Tue, 9 Feb 2016 22:17:47 +0000 Received: from 172-16-1-203.xilinx.com ([172.16.1.203]:35460 helo=xsj-tvapsmtp02.xilinx.com) by xsj-tvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1aTGbS-0002my-Fj; Tue, 09 Feb 2016 14:17:46 -0800 Received: from [127.0.0.1] (port=42677 helo=tsj-smtp-dlp1.xlnx.xilinx.com) by xsj-tvapsmtp02.xilinx.com with esmtp (Exim 4.63) (envelope-from ) id 1aTGbS-0007ch-Ay; Tue, 09 Feb 2016 14:17:46 -0800 Received: from xsj-tvapsmtp02 (smtptest.xilinx.com [172.16.1.203]) by tsj-smtp-dlp1.xlnx.xilinx.com (8.13.8/8.13.1) with ESMTP id u19MC5ZY011649; Tue, 9 Feb 2016 14:12:05 -0800 Received: from [172.19.74.182] (port=49738 helo=xsjalistai50.xlnx.xilinx.com) by xsj-tvapsmtp02 with esmtp (Exim 4.63) (envelope-from ) id 1aTGbR-0007cG-CN; Tue, 09 Feb 2016 14:17:45 -0800 From: Alistair Francis To: , Date: Tue, 9 Feb 2016 14:15:10 -0800 Message-ID: X-Mailer: git-send-email 2.5.0 In-Reply-To: References: X-RCIS-Action: ALLOW X-TM-AS-MML: disable X-TM-AS-Product-Ver: IMSS-7.1.0.1679-8.0.0.1202-22054.006 X-TM-AS-Result: No--14.634-7.0-31-10 X-imss-scan-details: No--14.634-7.0-31-10 X-TMASE-MatchedRID: PcpujJYVsdH/uyguzMmOKFz+axQLnAVB+eBf9ovw8I1zeKCaw73ZgQQy VB/q66frzTKJ5j6MjLVffUkQRDINxPgBWl/Ex3vB+cKX6yCQ13v/dK6JacgEu7rHn+Gm5OqdIE6 KlxNg++sXlHizt4pAW751pkQVwz+7sPJBU3ZwaVHETBJM55VRDjuvYa1v2IFhZ5yuplze9pscZl LfWkPQrfdpDV4B9OxWBTc+DFVPogSLywREuewe743NgkEqAN0RwJjn8yqLU6KjD9XxfoENjtPiu 9NSfhOYxD4yspF6GNvje4wJCyzaHTFmWZmMuV5m/4ToWehCRQWAfODDLypXmmpdOVekTLTRo8WM kQWv6iXBcIE78YqRWo6HM5rqDwqtgw5M0GpnaPMWIXP9tEnbSK3v9Pimg3aPCtY3R9qbugjl4de Vvp4eTg== X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:149.199.60.96; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(2980300002)(1109001)(1110001)(339900001)(199003)(189002)(19580405001)(4326007)(87936001)(19580395003)(2950100001)(106466001)(5890100001)(229853001)(105606002)(50226001)(5003940100001)(189998001)(77096005)(1220700001)(586003)(2906002)(11100500001)(5008740100001)(6806005)(1096002)(5001770100001)(85426001)(64026002)(5001960100002)(47776003)(118296001)(50986999)(36756003)(5003600100002)(86362001)(92566002)(48376002)(33646002)(50466002)(76176999)(107986001); DIR:OUT; SFP:1101; SCL:1; SRVR:SN1NAM02HT029; H:xsj-tvapsmtpgw01; FPR:; SPF:Fail; MLV:sfv; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 8b08f02b-ca66-48aa-7ccc-08d3319ed73a X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:SN1NAM02HT029; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(192813158149592); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(13018025)(8121501046)(5005006)(13024025)(13015025)(13023025)(13017025)(3002001)(10201501046); SRVR:SN1NAM02HT029; BCL:0; PCL:0; RULEID:; SRVR:SN1NAM02HT029; X-Forefront-PRVS: 08476BC6EF X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Feb 2016 22:17:47.1306 (UTC) X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c; Ip=[149.199.60.96]; Helo=[xsj-tvapsmtpgw01] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN1NAM02HT029 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.38.79 Cc: edgar.iglesias@xilinx.com, alistair.francis@xilinx.com, crosthwaitepeter@gmail.com, edgar.iglesias@gmail.com, alex.bennee@linaro.org, afaerber@suse.de, fred.konrad@greensocs.com Subject: [Qemu-devel] [PATCH v4 14/16] register: Add GPIO API 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+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Peter Crosthwaite Add GPIO functionality to the register API. This allows association and automatic connection of GPIOs to bits in registers. GPIO inputs will attach to handlers that automatically set read-only bits in registers. GPIO outputs will be updated to reflect their field value when their respective registers are written (or reset). Supports active low GPIOs. This is particularly effective for implementing system level controllers, where heterogenous collections of control signals are placed is a SoC specific peripheral then propagated all over the system. Signed-off-by: Peter Crosthwaite [ EI Changes: * register: Add a polarity field to GPIO connections Makes it possible to directly connect active low signals to generic interrupt pins. ] Signed-off-by: Edgar E. Iglesias Signed-off-by: Alistair Francis --- hw/core/register.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/register.h | 37 ++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/hw/core/register.c b/hw/core/register.c index ac866f6..1dc7ccc 100644 --- a/hw/core/register.c +++ b/hw/core/register.c @@ -106,6 +106,7 @@ void register_write(RegisterInfo *reg, uint64_t val, uint64_t we) } register_write_val(reg, new_val); + register_refresh_gpios(reg, old_val); if (ac->post_write) { ac->post_write(reg, new_val); @@ -147,19 +148,113 @@ void register_reset(RegisterInfo *reg) g_assert(reg); g_assert(reg->data); g_assert(reg->access); + uint64_t old_val; + + old_val = register_read_val(reg); register_write_val(reg, reg->access->reset); + register_refresh_gpios(reg, old_val); +} + +void register_refresh_gpios(RegisterInfo *reg, uint64_t old_value) +{ + const RegisterAccessInfo *ac; + const RegisterGPIOMapping *gpio; + + ac = reg->access; + for (gpio = ac->gpios; gpio && gpio->name; gpio++) { + int i; + + if (gpio->input) { + continue; + } + + for (i = 0; i < gpio->num; ++i) { + uint64_t gpio_value, gpio_value_old; + + qemu_irq gpo = qdev_get_gpio_out_named(DEVICE(reg), gpio->name, i); + gpio_value_old = extract64(old_value, + gpio->bit_pos + i * gpio->width, + gpio->width) ^ gpio->polarity; + gpio_value = extract64(register_read_val(reg), + gpio->bit_pos + i * gpio->width, + gpio->width) ^ gpio->polarity; + if (!(gpio_value_old ^ gpio_value)) { + continue; + } + if (reg->debug && gpo) { + qemu_log("refreshing gpio out %s to %" PRIx64 "\n", + gpio->name, gpio_value); + } + qemu_set_irq(gpo, gpio_value); + } + } +} + +typedef struct DeviceNamedGPIOHandlerOpaque { + DeviceState *dev; + const char *name; +} DeviceNamedGPIOHandlerOpaque; + +static void register_gpio_handler(void *opaque, int n, int level) +{ + DeviceNamedGPIOHandlerOpaque *gho = opaque; + RegisterInfo *reg = REGISTER(gho->dev); + + const RegisterAccessInfo *ac; + const RegisterGPIOMapping *gpio; + + ac = reg->access; + for (gpio = ac->gpios; gpio && gpio->name; gpio++) { + if (gpio->input && !strcmp(gho->name, gpio->name)) { + register_write_val(reg, deposit64(register_read_val(reg), + gpio->bit_pos + n * gpio->width, + gpio->width, + level ^ gpio->polarity)); + return; + } + } + + abort(); } void register_init(RegisterInfo *reg) { assert(reg); + const RegisterAccessInfo *ac; + const RegisterGPIOMapping *gpio; if (!reg->data || !reg->access) { return; } object_initialize((void *)reg, sizeof(*reg), TYPE_REGISTER); + + ac = reg->access; + for (gpio = ac->gpios; gpio && gpio->name; gpio++) { + if (!gpio->num) { + ((RegisterGPIOMapping *)gpio)->num = 1; + } + if (!gpio->width) { + ((RegisterGPIOMapping *)gpio)->width = 1; + } + if (gpio->input) { + DeviceNamedGPIOHandlerOpaque gho = { + .name = gpio->name, + .dev = DEVICE(reg), + }; + qemu_irq irq; + + qdev_init_gpio_in_named(DEVICE(reg), register_gpio_handler, + gpio->name, gpio->num); + irq = qdev_get_gpio_in_named(DEVICE(reg), gpio->name, gpio->num); + qemu_irq_set_opaque(irq, g_memdup(&gho, sizeof(gho))); + } else { + qemu_irq *gpos = g_new0(qemu_irq, gpio->num); + + qdev_init_gpio_out_named(DEVICE(reg), gpos, gpio->name, gpio->num); + } + } } static inline void register_write_memory(void *opaque, hwaddr addr, @@ -231,6 +326,7 @@ void register_init_block32(DeviceState *owner, const RegisterAccessInfo *rae, .opaque = owner, }; register_init(r); + qdev_pass_all_gpios(DEVICE(r), owner); memory_region_init_io(&r->mem, OBJECT(owner), ops, r, r->access->name, sizeof(uint32_t)); diff --git a/include/hw/register.h b/include/hw/register.h index 6ac005c..4d284a9 100644 --- a/include/hw/register.h +++ b/include/hw/register.h @@ -13,11 +13,35 @@ #include "hw/qdev-core.h" #include "exec/memory.h" +#include "hw/irq.h" typedef struct RegisterInfo RegisterInfo; typedef struct RegisterAccessInfo RegisterAccessInfo; /** + * A register access error message + * @mask: Bits in the register the error applies to + * @reason: Reason why this access is an error + */ + +typedef struct RegisterAccessError { + uint64_t mask; + const char *reason; +} RegisterAccessError; + +#define REG_GPIO_POL_HIGH 0 +#define REG_GPIO_POL_LOW 1 + +typedef struct RegisterGPIOMapping { + const char *name; + uint8_t bit_pos; + bool input; + bool polarity; + uint8_t num; + uint8_t width; +} RegisterGPIOMapping; + +/** * Access description for a register that is part of guest accessible device * state. * @@ -61,6 +85,8 @@ struct RegisterAccessInfo { uint64_t (*post_read)(RegisterInfo *reg, uint64_t val); + const RegisterGPIOMapping *gpios; + struct { hwaddr addr; } decode; @@ -137,6 +163,17 @@ void register_reset(RegisterInfo *reg); void register_init(RegisterInfo *reg); /** + * Refresh GPIO outputs based on diff between old value register current value. + * GPIOs are refreshed for fields where the old value differs to the current + * value. + * + * @reg: Register to refresh GPIO outs + * @old_value: previous value of register + */ + +void register_refresh_gpios(RegisterInfo *reg, uint64_t old_value); + +/** * Memory API MMIO write handler that will write to a Register API register. * _be for big endian variant and _le for little endian. * @opaque: RegisterInfo to write to