From patchwork Wed Jun 22 20:24:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Francis X-Patchwork-Id: 9193707 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 997626075F for ; Wed, 22 Jun 2016 20:28:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8756127FAC for ; Wed, 22 Jun 2016 20:28:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7A4F82840F; Wed, 22 Jun 2016 20:28:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 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.wl.linuxfoundation.org (Postfix) with ESMTPS id 959A527FAC for ; Wed, 22 Jun 2016 20:28:54 +0000 (UTC) Received: from localhost ([::1]:60673 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFolZ-0004tR-AA for patchwork-qemu-devel@patchwork.kernel.org; Wed, 22 Jun 2016 16:28:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60954) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFohN-000082-Vu for qemu-devel@nongnu.org; Wed, 22 Jun 2016 16:24:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bFohI-0003zS-60 for qemu-devel@nongnu.org; Wed, 22 Jun 2016 16:24:32 -0400 Received: from mail-sn1nam02on0074.outbound.protection.outlook.com ([104.47.36.74]:10444 helo=NAM02-SN1-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFohH-0003z7-UF for qemu-devel@nongnu.org; Wed, 22 Jun 2016 16:24:28 -0400 Received: from SN1NAM02FT025.eop-nam02.prod.protection.outlook.com (10.152.72.53) by SN1NAM02HT179.eop-nam02.prod.protection.outlook.com (10.152.72.66) with Microsoft SMTP Server (TLS) id 15.1.517.7; Wed, 22 Jun 2016 20:24:25 +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 SN1NAM02FT025.mail.protection.outlook.com (10.152.72.87) with Microsoft SMTP Server (TLS) id 15.1.523.9 via Frontend Transport; Wed, 22 Jun 2016 20:24:25 +0000 Received: from 172-16-1-203.xilinx.com ([172.16.1.203]:56820 helo=xsj-tvapsmtp02.xilinx.com) by xsj-tvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1bFohD-00077J-TL; Wed, 22 Jun 2016 13:24:24 -0700 Received: from [127.0.0.1] (port=37428 helo=tsj-smtp-dlp1.xlnx.xilinx.com) by xsj-tvapsmtp02.xilinx.com with esmtp (Exim 4.63) (envelope-from ) id 1bFohD-0004hn-RN; Wed, 22 Jun 2016 13:24:23 -0700 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 u5MKHqU8002095; Wed, 22 Jun 2016 13:17:52 -0700 Received: from [172.19.74.182] (port=37794 helo=xsjalistai50.xilinx.com) by xsj-tvapsmtp02 with esmtp (Exim 4.63) (envelope-from ) id 1bFohC-0004hk-Vy; Wed, 22 Jun 2016 13:24:23 -0700 From: Alistair Francis To: , Date: Wed, 22 Jun 2016 13:24:09 -0700 Message-ID: <9372ab2e4771de7eb61079d68e53a2cd71c9bdcf.1466626975.git.alistair.francis@xilinx.com> X-Mailer: git-send-email 2.7.4 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-22406.005 X-TM-AS-Result: No--15.913-7.0-31-10 X-imss-scan-details: No--15.913-7.0-31-10 X-TMASE-MatchedRID: 9JI9XV0mxemLwgJA7qJvFMnUT+eskUQPeFyzQYzPQ+TwkZ5FhgEMOvRm 0kmqtH+D32/yo9IXlhROMEQFWdYpZNnIY5r2VYXxWnQHHkRrIIUXig/OPxxJLp+QxLD3BYlHIE6 KlxNg++vILTvp5tPpJrPq7OlP/XzX0RCs70uuPqESEYfcJF0pRTduVyA0C7d231GU/N5W5BCtmH tlBrdfRgWHVpDaHf9ZGSbFsiI/QlQCg5cSwpvOU8g6fo0rxLVrbd6rGhWOAwS/wPtA9baOjy7qW YZqSpWH8sHMRs93VpLyHZFHzPfyf0ee/pUgUe3XUIhTTahb7dX0O7M3lSnTW8Ywygywao03B9S2 1iwproj1m6k2SGSmTIcR4xN9HQJ7HxPMjOKY7A8LbigRnpKlKT4yqD4LKu3A X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report: CIP:149.199.60.96; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7916002)(2980300002)(1109001)(1110001)(339900001)(189002)(199003)(92566002)(229853001)(7696003)(5890100001)(87936001)(85426001)(8936002)(81156014)(50226002)(9786002)(36756003)(33646002)(4326007)(6806005)(5003600100003)(7846002)(305945005)(86362001)(356003)(8676002)(5003940100001)(11100500001)(19580395003)(2906002)(105606002)(81166006)(19580405001)(2950100001)(586003)(106466001)(50466002)(64026002)(47776003)(76176999)(48376002)(118296001)(5001770100001)(77096005)(50986999)(71366001)(189998001)(107986001); DIR:OUT; SFP:1101; SCL:1; SRVR:SN1NAM02HT179; H:xsj-tvapsmtpgw01; FPR:; SPF:Fail; PTR:unknown-60-96.xilinx.com; MX:1; A:1; CAT:NONE; LANG:en; CAT:NONE; MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: 65b0f42e-a506-43d6-a4c6-08d39adb3436 X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:SN1NAM02HT179; X-Microsoft-Antispam-PRVS: <7ace0748c68441a5b7419144dac6cbc4@SN1NAM02HT179.eop-nam02.prod.protection.outlook.com> X-Exchange-Antispam-Report-Test: UriScan:(192813158149592)(21532816269658); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(13024025)(13018025)(13017025)(13015025)(13023025)(8121501046)(5005006)(3002001)(10201501046)(6055026); SRVR:SN1NAM02HT179; BCL:0; PCL:0; RULEID:; SRVR:SN1NAM02HT179; X-Forefront-PRVS: 0981815F2F X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Jun 2016 20:24:25.0353 (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: SN1NAM02HT179 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.36.74 Subject: [Qemu-devel] [PATCH v7 10/12] register: Add GPIO API X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , 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 Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- V6: - Don't use qdev_pass_all_gpios() as it doesn't seem to work V5 - Remove RegisterAccessError struct hw/core/register.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/hw/register.h | 27 ++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/hw/core/register.c b/hw/core/register.c index f32faac..476c5db 100644 --- a/hw/core/register.c +++ b/hw/core/register.c @@ -108,6 +108,7 @@ void register_write(RegisterInfo *reg, uint64_t val, uint64_t we, } register_write_val(reg, new_val); + register_refresh_gpios(reg, old_val, debug); if (ac->post_write) { ac->post_write(reg, new_val); @@ -147,23 +148,119 @@ uint64_t register_read(RegisterInfo *reg, const char* prefix, bool debug) void register_reset(RegisterInfo *reg) { g_assert(reg); + uint64_t old_val; if (!reg->data || !reg->access) { return; } + old_val = register_read_val(reg); + register_write_val(reg, reg->access->reset); + register_refresh_gpios(reg, old_val, false); +} + +void register_refresh_gpios(RegisterInfo *reg, uint64_t old_value, bool debug) +{ + 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_connector(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 (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); + qdev_pass_gpios(DEVICE(reg), reg->opaque, gpio->name); + } + } } void register_write_memory(void *opaque, hwaddr addr, diff --git a/include/hw/register.h b/include/hw/register.h index 3e4d1ae..112ca7b 100644 --- a/include/hw/register.h +++ b/include/hw/register.h @@ -13,11 +13,24 @@ #include "hw/qdev-core.h" #include "exec/memory.h" +#include "hw/irq.h" typedef struct RegisterInfo RegisterInfo; typedef struct RegisterAccessInfo RegisterAccessInfo; typedef struct RegisterInfoArray RegisterInfoArray; +#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. @@ -55,6 +68,8 @@ struct RegisterAccessInfo { uint64_t (*post_read)(RegisterInfo *reg, uint64_t val); hwaddr addr; + + const RegisterGPIOMapping *gpios; }; /** @@ -148,6 +163,18 @@ 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 + * @debug: Should the read operation debug information be printed? + */ + +void register_refresh_gpios(RegisterInfo *reg, uint64_t old_value, bool debug); + +/** * Memory API MMIO write handler that will write to a Register API register. * @opaque: RegisterInfo to write to * @addr: Address to write