From nobody Tue Nov 11 01:37:59 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1560848086; cv=none; d=zoho.com; s=zohoarc; b=fMVv09tjw2cfXxGvzIzdj51SW7ik+ZnfrQ6NPudMdDTpYMq6TSfx7bMpTRm0jA98c0H2XTGnvbJ4huDFaGvXOo4ROjIKIaRdyIVdw8g2RZY3TmIPIE4J6yvwFLC6OVcHYXM4Cy7JG9IfV34kz+lHI6J6VnBVETtuZdzNim4IYl4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560848086; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=mdUkH0AQ2Dq97eB4HInfbNdrgzJt+qLoMa8f0uSxtlk=; b=aOF04Tx11aQP8yZ8LIsn1DrmrZH8uBiogFnoI0V7BgWScUBQvmJzAI03By3yYLyS+BYupWjCYyZRf6KR9wJRO79vqfb6rvW7BPQQzvpeOsd81WjCTtvUqCvlov23ukeNU9+p/oG/5mN4vvjEYGjW+NUhboxwBQGJA0uADMln264= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560848086576164.34432775999335; Tue, 18 Jun 2019 01:54:46 -0700 (PDT) Received: from localhost ([::1]:54906 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hd9t7-0000xw-F8 for importer@patchew.org; Tue, 18 Jun 2019 04:54:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45129) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hd9qv-0007Bh-TU for qemu-devel@nongnu.org; Tue, 18 Jun 2019 04:52:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hd9qr-0000os-Vf for qemu-devel@nongnu.org; Tue, 18 Jun 2019 04:52:29 -0400 Received: from mail-pg1-x52e.google.com ([2607:f8b0:4864:20::52e]:45440) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hd9qg-0000fU-AU; Tue, 18 Jun 2019 04:52:16 -0400 Received: by mail-pg1-x52e.google.com with SMTP id s21so7287454pga.12; Tue, 18 Jun 2019 01:52:14 -0700 (PDT) Received: from rashmica.home.majoof.com ([43.245.162.131]) by smtp.gmail.com with ESMTPSA id p7sm27032616pfp.131.2019.06.18.01.52.09 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 18 Jun 2019 01:52:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mdUkH0AQ2Dq97eB4HInfbNdrgzJt+qLoMa8f0uSxtlk=; b=euiuSMQr1BDn1/QAIPmJdH7ClA1KwK++80ZbiPG3T1rpk497sMR322bK2a5tTvO7Pt hzMQRFGvk22u2+Lm9A505ng5RQJp0yW22CozrBJwcfB36PaO7K3nRzLcqC4HzKulwEw1 8cCDFNlbt2iguOlWl4Hoxx5eLWLahHJEETjU0D+7CBVtGk9IdQTWOyktBGIWfLnOfOR2 eusBRzT5Hei5dn/UmppP2XFCfxdAX/Xoq/f+Lq0nRHiEdCCNxJieH9bXac+OX9kh+axN XY4vq4kHtj1VkHMJRjyiHZVAcP7XKHVQ3xU/WIp0ABuZ1SBt/jsxxgsSEAms8jrAy200 /Ckw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mdUkH0AQ2Dq97eB4HInfbNdrgzJt+qLoMa8f0uSxtlk=; b=PHzTE+1NvBidGqwzJjOjD8L9zgvXwse0MSA5X1eMt08uNsGMiPKeO2su9es+ryiZIZ QZWC62GxYTo4v6FFeBlRZLRe1Ixmgv/Z3T6sRZjcQaBzwyi7Q1EM67tyGMt7AXTLM99X WJifSDSzGtEUrgSybY0ot7Uiid33SWL9qxms0NL65jhN0FL8bWksyQvS/zXac091GTOB d9LcHmZZk/cn0EW5eeUczVF9RNMw8neU196T0MGpYd/veO/SVLh5EiH35hbfiYAtN3IM N+nDHng3Ennmpslgbvel51urcs42BtXzvNOnP/7JEJaVKOfi3pBhiVfZ9SFWnityDP5P xEWg== X-Gm-Message-State: APjAAAUcTztXj4zz63qMXQLXdiA5P0WPj3fjqf+O4pwfCzMJibWsFe+/ Rb+BjuxclX5fR0utIB/GGwKRYLLb X-Google-Smtp-Source: APXvYqz2IjB6vhlNe3v8a+xMIT5OgiHJGmvSdwo5fNBL3LzO3uUzRYvNZOf6F/bqMQcFmOjP39TT+A== X-Received: by 2002:a62:1d8f:: with SMTP id d137mr35962315pfd.207.1560847932596; Tue, 18 Jun 2019 01:52:12 -0700 (PDT) From: Rashmica Gupta To: qemu-arm@nongnu.org Date: Tue, 18 Jun 2019 18:51:53 +1000 Message-Id: <20190618085154.21498-2-rashmica.g@gmail.com> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190618085154.21498-1-rashmica.g@gmail.com> References: <20190618085154.21498-1-rashmica.g@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::52e Subject: [Qemu-devel] [PATCH 1/2] hw/gpio: Add basic Aspeed GPIO model X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: andrew@aj.id.au, clg@kaod.org, qemu-devel@nongnu.org, Rashmica Gupta , joel@jms.id.au Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Add in details for GPIO controller for AST 2400 and 2500 Signed-off-by: Rashmica Gupta --- hw/gpio/Makefile.objs | 1 + hw/gpio/aspeed_gpio.c | 869 ++++++++++++++++++++++++++++++++++ include/hw/gpio/aspeed_gpio.h | 76 +++ 3 files changed, 946 insertions(+) create mode 100644 hw/gpio/aspeed_gpio.c create mode 100644 include/hw/gpio/aspeed_gpio.h diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs index e5da0cb54f..d305b3b24b 100644 --- a/hw/gpio/Makefile.objs +++ b/hw/gpio/Makefile.objs @@ -9,3 +9,4 @@ obj-$(CONFIG_OMAP) +=3D omap_gpio.o obj-$(CONFIG_IMX) +=3D imx_gpio.o obj-$(CONFIG_RASPI) +=3D bcm2835_gpio.o obj-$(CONFIG_NRF51_SOC) +=3D nrf51_gpio.o +obj-$(CONFIG_ASPEED_SOC) +=3D aspeed_gpio.o diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c new file mode 100644 index 0000000000..d84dd69255 --- /dev/null +++ b/hw/gpio/aspeed_gpio.c @@ -0,0 +1,869 @@ +/* + * ASPEED GPIO Controller + * + * Copyright (C) 2017-2019 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + * + * + * This models the ast2400 and ast2500 GPIO controllers. + * + * GPIO pins are arranged in groups of 8 pins labeled A,B,..,Y,Z,AA,AB,AC. + * (Note that the ast2400 controller only goes up to group AB). + * A set has four groups (except set AC which only has one) and is + * referred to by the groups it is composed of (eg ABCD,EFGH,...,YZAAAB). + * Each set is accessed and controlled by a bank of 14 registers. + * + * These registers operate on a per pin level where each bit in the regist= er + * corresponds to a pin, except for the command source registers. The comm= and + * source registers operate on a per group level where bits 24, 16, 8 and 0 + * correspond to each group in the set. + * + * eg. registers for set ABCD: + * |D7...D0|C7...C0|B7...B0|A7...A0| <- GPIOs + * |31...24|23...16|15....8|7.....0| <- bit position + * + * Note that there are a couple of groups that only have 4 pins. + + * There are three ways that this model deviates from the behaviour of the + * actual controller: + * (1) There are three debounce registers which aren't modeled and so the = per + * set debounce setting registers don't affect anything. + * + * (2) The only control source driving the GPIO pins in the model is the A= RM + * model (as there currently aren't models for the LPC or Coprocessor [TOD= O]). + * + * (3) None of the registers in the model are reset tolerant. [TODO] + * + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/gpio/aspeed_gpio.h" +#include "include/hw/misc/aspeed_scu.h" +#include "qapi/error.h" +#include "qapi/visitor.h" + +#define ASPEED_GPIOS_PER_REG 32 + +/* GPIO Source Types */ +#define ASPEED_CMD_SRC_MASK 0x01010101 +#define ASPEED_SOURCE_ARM 0 +#define ASPEED_SOURCE_LPC 1 +#define ASPEED_SOURCE_COPROCESSOR 2 +#define ASPEED_SOURCE_RESERVED 3 + +/* GPIO Interrupt Triggers */ +#define ASPEED_FALLING_EDGE 0 +#define ASPEED_RISING_EDGE 1 +#define ASPEED_LEVEL_LOW 2 +#define ASPEED_LEVEL_HIGH 3 +#define ASPEED_DUAL_EDGE 4 + +/* GPIO Register Address Offsets */ +#define GPIO_ABCD_DATA_VALUE 0x000 +#define GPIO_ABCD_DIRECTION 0x004 +#define GPIO_ABCD_INT_ENABLE 0x008 +#define GPIO_ABCD_INT_SENS_0 0x00C +#define GPIO_ABCD_INT_SENS_1 0x010 +#define GPIO_ABCD_INT_SENS_2 0x014 +#define GPIO_ABCD_INT_STATUS 0x018 +#define GPIO_ABCD_RESET_TOLERANT 0x01C +#define GPIO_EFGH_DATA_VALUE 0x020 +#define GPIO_EFGH_DIRECTION 0x024 +#define GPIO_EFGH_INT_ENABLE 0x028 +#define GPIO_EFGH_INT_SENS_0 0x02C +#define GPIO_EFGH_INT_SENS_1 0x030 +#define GPIO_EFGH_INT_SENS_2 0x034 +#define GPIO_EFGH_INT_STATUS 0x038 +#define GPIO_EFGH_RESET_TOL 0x03C +#define GPIO_ABCD_DEBOUNCE_1 0x040 +#define GPIO_ABCD_DEBOUNCE_2 0x044 +#define GPIO_EFGH_DEBOUNCE_1 0x048 +#define GPIO_EFGH_DEBOUNCE_2 0x04C +#define GPIO_DEBOUNCE_TIME_1 0x050 +#define GPIO_DEBOUNCE_TIME_2 0x054 +#define GPIO_DEBOUNCE_TIME_3 0x058 +#define GPIO_ABCD_COMMAND_SRC_0 0x060 +#define GPIO_ABCD_COMMAND_SRC_1 0x064 +#define GPIO_EFGH_COMMAND_SRC_0 0x068 +#define GPIO_EFGH_COMMAND_SRC_1 0x06C +#define GPIO_IJKL_DATA_VALUE 0x070 +#define GPIO_IJKL_DIRECTION 0x074 +#define GPIO_MNOP_DATA_VALUE 0x078 +#define GPIO_MNOP_DIRECTION 0x07C +#define GPIO_QRST_DATA_VALUE 0x080 +#define GPIO_QRST_DIRECTION 0x084 +#define GPIO_UVWX_DATA_VALUE 0x088 +#define GPIO_UWVX_DIRECTION 0x08C +#define GPIO_IJKL_COMMAND_SRC_0 0x090 +#define GPIO_IJKL_COMMAND_SRC_1 0x094 +#define GPIO_IJKL_INT_ENABLE 0x098 +#define GPIO_IJKL_INT_SENS_0 0x09C +#define GPIO_IJKL_INT_SENS_1 0x0A0 +#define GPIO_IJKL_INT_SENS_2 0x0A4 +#define GPIO_IJKL_INT_STATUS 0x0A8 +#define GPIO_IJKL_RESET_TOLERANT 0x0AC +#define GPIO_IJKL_DEBOUNCE_1 0x0B0 +#define GPIO_IJKL_DEBOUNCE_2 0x0B4 +#define GPIO_IJKL_INPUT_MASK 0x0B8 +#define GPIO_ABCD_DATA_READ 0x0C0 +#define GPIO_EFGH_DATA_READ 0x0C4 +#define GPIO_IJKL_DATA_READ 0x0C8 +#define GPIO_MNOP_DATA_READ 0x0CC +#define GPIO_QRST_DATA_READ 0x0D0 +#define GPIO_UVWX_DATA_READ 0x0D4 +#define GPIO_YZAAAB_DATA_READ 0x0D8 +#define GPIO_AC_DATA_READ 0x0DC +#define GPIO_MNOP_COMMAND_SRC_0 0x0E0 +#define GPIO_MNOP_COMMAND_SRC_1 0x0E4 +#define GPIO_MNOP_INT_ENABLE 0x0E8 +#define GPIO_MNOP_INT_SENS_0 0x0EC +#define GPIO_MNOP_INT_SENS_1 0x0F0 +#define GPIO_MNOP_INT_SENS_2 0x0F4 +#define GPIO_MNOP_INT_STATUS 0x0F8 +#define GPIO_MNOP_RESET_TOLERANT 0x0FC +#define GPIO_MNOP_DEBOUNCE_1 0x100 +#define GPIO_MNOP_DEBOUNCE_2 0x104 +#define GPIO_MNOP_INPUT_MASK 0x108 +#define GPIO_QRST_COMMAND_SRC_0 0x110 +#define GPIO_QRST_COMMAND_SRC_1 0x114 +#define GPIO_QRST_INT_ENABLE 0x118 +#define GPIO_QRST_INT_SENS_0 0x11C +#define GPIO_QRST_INT_SENS_1 0x120 +#define GPIO_QRST_INT_SENS_2 0x124 +#define GPIO_QRST_INT_STATUS 0x128 +#define GPIO_QRST_RESET_TOLERANT 0x12C +#define GPIO_QRST_DEBOUNCE_1 0x130 +#define GPIO_QRST_DEBOUNCE_2 0x134 +#define GPIO_QRST_INPUT_MASK 0x138 +#define GPIO_UVWX_COMMAND_SRC_0 0x140 +#define GPIO_UVWX_COMMAND_SRC_1 0x144 +#define GPIO_UVWX_INT_ENABLE 0x148 +#define GPIO_UVWX_INT_SENS_0 0x14C +#define GPIO_UVWX_INT_SENS_1 0x150 +#define GPIO_UVWX_INT_SENS_2 0x154 +#define GPIO_UVWX_INT_STATUS 0x158 +#define GPIO_UVWX_RESET_TOLERANT 0x15C +#define GPIO_UVWX_DEBOUNCE_1 0x160 +#define GPIO_UVWX_DEBOUNCE_2 0x164 +#define GPIO_UVWX_INPUT_MASK 0x168 +#define GPIO_YZAAAB_COMMAND_SRC_0 0x170 +#define GPIO_YZAAAB_COMMAND_SRC_1 0x174 +#define GPIO_YZAAAB_INT_ENABLE 0x178 +#define GPIO_YZAAAB_INT_SENS_0 0x17C +#define GPIO_YZAAAB_INT_SENS_1 0x180 +#define GPIO_YZAAAB_INT_SENS_2 0x184 +#define GPIO_YZAAAB_INT_STATUS 0x188 +#define GPIO_YZAAAB_RESET_TOLERANT 0x18C +#define GPIO_YZAAAB_DEBOUNCE_1 0x190 +#define GPIO_YZAAAB_DEBOUNCE_2 0x194 +#define GPIO_YZAAAB_INPUT_MASK 0x198 +#define GPIO_AC_COMMAND_SRC_0 0x1A0 +#define GPIO_AC_COMMAND_SRC_1 0x1A4 +#define GPIO_AC_INT_ENABLE 0x1A8 +#define GPIO_AC_INT_SENS_0 0x1AC +#define GPIO_AC_INT_SENS_1 0x1B0 +#define GPIO_AC_INT_SENS_2 0x1B4 +#define GPIO_AC_INT_STATUS 0x1B8 +#define GPIO_AC_RESET_TOLERANT 0x1BC +#define GPIO_AC_DEBOUNCE_1 0x1C0 +#define GPIO_AC_DEBOUNCE_2 0x1C4 +#define GPIO_AC_INPUT_MASK 0x1C8 +#define GPIO_ABCD_INPUT_MASK 0x1D0 +#define GPIO_EFGH_INPUT_MASK 0x1D4 +#define GPIO_YZAAAB_DATA_VALUE 0x1E0 +#define GPIO_YZAAAB_DIRECTION 0x1E4 +#define GPIO_AC_DATA_VALUE 0x1E8 +#define GPIO_AC_DIRECTION 0x1EC + +struct AspeedGPIO { + uint16_t set_idx; + uint32_t (*get)(GPIORegs *regs); + void (*set)(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val); +}; + +static int aspeed_evaluate_irq(GPIORegs *regs, int prev_value_high, int bi= t) +{ + uint32_t falling_edge =3D 0, rising_edge =3D 0; + uint32_t int_trigger =3D extract32(regs->int_sens_0, bit, 1) + | extract32(regs->int_sens_1, bit, 1) << 1 + | extract32(regs->int_sens_2, bit, 1) << 2 ; + uint32_t curr_pin_high =3D extract32(regs->data_value, bit, 1); + + /* Detect edges */ + if (curr_pin_high && !prev_value_high) { + rising_edge =3D 1; + } else if (!curr_pin_high && prev_value_high) { + falling_edge =3D 1; + } + + if (((int_trigger =3D=3D ASPEED_FALLING_EDGE) && falling_edge) || + ((int_trigger =3D=3D ASPEED_RISING_EDGE) && rising_edge) || + ((int_trigger =3D=3D ASPEED_LEVEL_LOW) && !curr_pin_high) || + ((int_trigger =3D=3D ASPEED_LEVEL_HIGH) && curr_pin_high) || + ((int_trigger >=3D ASPEED_DUAL_EDGE) && (rising_edge || falling_e= dge))) + { + regs->int_status =3D deposit32(regs->int_status, bit, 1, 1); + return 1; + } + return 0; +} + +static void aspeed_gpio_update(AspeedGPIOState *s, GPIORegs *regs) +{ + uint32_t input_mask =3D regs->input_mask; + uint32_t direction =3D regs->direction; + uint32_t old =3D regs->data_value; + uint32_t new =3D regs->data_read; + uint32_t diff; + int bit; + + diff =3D old ^ new; + if (!diff) { + return; + } + + if (!direction) { + return; + } + + for (bit =3D 0; bit < ASPEED_GPIOS_PER_REG; bit++) { + uint32_t mask =3D 1 << bit; + /* If the bit needs to be updated... */ + if (!(diff & mask)) { + continue; + } + /* ...and corresponds to an output pin...*/ + if (!(direction & mask)) { + continue; + } + /* ...and isn't masked... */ + if (input_mask & mask) { + continue; + } + /* ... then update it*/ + if (mask & new) { + regs->data_value |=3D mask; + } else { + regs->data_value &=3D ~mask; + } + + if (aspeed_evaluate_irq(regs, old & mask, bit)) { + qemu_set_irq(s->output[bit], 1); + } + } +} + +static uint32_t aspeed_adjust_pin(AspeedGPIOState *s, uint32_t pin) +{ + if (pin >=3D s->ctrl->gap) { + pin +=3D 4; + } + + return pin; +} + +static uint32_t aspeed_get_set_idx_from_pin(AspeedGPIOState *s, uint32_t p= in) +{ + /* + * For most pins, dividing by 32 gets the set index. + * + * However the 2500 has a 4 pin gap in group AB and the 2400 has a 4 p= in + * gap in group Y (and only four pins in AB but this is the last group= so + * it doesn't matter). + */ + return aspeed_adjust_pin(s, pin) >> 5; +} + +static bool aspeed_gpio_get_pin_level(AspeedGPIOState *s, uint32_t pin) +{ + uint32_t reg_val; + uint32_t mask =3D 1 << (pin); + uint32_t set_idx =3D aspeed_get_set_idx_from_pin(s, pin); + + reg_val =3D s->sets[set_idx].data_value; + + return !!(reg_val & mask); +} + +static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, uint32_t pin, + bool level) +{ + uint32_t mask =3D 1 << (pin); + uint32_t set_idx =3D aspeed_get_set_idx_from_pin(s, pin); + + if (level) { + s->sets[set_idx].data_read |=3D mask; + } else { + s->sets[set_idx].data_read &=3D !mask; + } + + aspeed_gpio_update(s, &s->sets[set_idx]); +} + +/* + * | src_1 | src_2 | source | + * |-----------------------------| + * | 0 | 0 | ARM | + * | 0 | 1 | LPC | + * | 1 | 0 | Coprocessor| + * | 1 | 1 | Reserved | + * + * Once the source of a set is programmed, corresponding bits in the + * data_value, direction, interrupt [enable, sens[0-2]], reset_tol and + * debounce registers can only be written by the source. + * + * Source is ARM by default + * only bits 24, 16, 8, and 0 can be set + * + * we don't currently have a model for the LPC or Coprocessor + */ +static uint32_t update_value_control_source(GPIORegs *regs, uint32_t old_v= alue, + uint32_t value) +{ + int i; + int cmd_source; + + /* assume the source is always ARM for now */ + int source =3D ASPEED_SOURCE_ARM; + + uint32_t new_value =3D 0; + + /* for each group in set */ + for (i =3D 0; i < ASPEED_GPIOS_PER_REG; i +=3D 8) { + cmd_source =3D extract32(regs->cmd_source_0, i, 1) + | (extract32(regs->cmd_source_1, i, 1) << 1); + + if (source =3D=3D cmd_source) { + new_value |=3D (0xff << i) & value; + } else { + new_value |=3D (0xff << i) & old_value; + } + } + return new_value; +} + +/* Reader helper functions */ +static uint32_t read_direction(GPIORegs *regs) +{ + return regs->direction; +} + +static uint32_t read_data_value(GPIORegs *regs) +{ + return regs->data_value; +} + +static uint32_t read_int_enable(GPIORegs *regs) +{ + return regs->int_enable; +} + +static uint32_t read_int_sens_0(GPIORegs *regs) +{ + return regs->int_sens_0; +} + +static uint32_t read_int_sens_1(GPIORegs *regs) +{ + return regs->int_sens_1; +} + +static uint32_t read_int_sens_2(GPIORegs *regs) +{ + return regs->int_sens_2; +} + +static uint32_t read_int_status(GPIORegs *regs) +{ + return regs->int_status; +} + +static uint32_t read_reset_tol(GPIORegs *regs) +{ + return regs->reset_tol; +} + +static uint32_t read_debounce_1(GPIORegs *regs) +{ + return regs->debounce_1; +} + +static uint32_t read_debounce_2(GPIORegs *regs) +{ + return regs->debounce_2; +} + +static uint32_t read_cmd_source_0(GPIORegs *regs) +{ + return regs->cmd_source_0; +} + +static uint32_t read_cmd_source_1(GPIORegs *regs) +{ + return regs->cmd_source_1; +} + +static uint32_t read_data(GPIORegs *regs) +{ + return regs->data_read; +} + +static uint32_t read_input_mask(GPIORegs *regs) +{ + return regs->input_mask; +} + +/* Write helper functions */ + +static void _write_data_value(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + val &=3D props->output | ~props->input; + regs->data_read =3D update_value_control_source(regs, regs->data_read,= val); + aspeed_gpio_update(s, regs); +} + +static void _write_direction(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + val &=3D props->output | ~props->input; + regs->direction =3D update_value_control_source(regs, regs->direction,= val); + aspeed_gpio_update(s, regs); +} + +static void _write_int_enable(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->int_enable =3D update_value_control_source(regs, regs->int_enabl= e, val); + aspeed_gpio_update(s, regs); +} + +static void _write_int_sens_0(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->int_sens_0 =3D update_value_control_source(regs, regs->int_sens_= 0, val); + aspeed_gpio_update(s, regs); +} + +static void _write_int_sens_1(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->int_sens_1 =3D update_value_control_source(regs, regs->int_sens_= 1, val); + aspeed_gpio_update(s, regs); +} + +static void _write_int_sens_2(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->int_sens_2 =3D update_value_control_source(regs, regs->int_sens_= 2, val); + aspeed_gpio_update(s, regs); +} + +static void _write_int_status(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->int_status =3D val; + aspeed_gpio_update(s, regs); +} + +static void _write_reset_tol(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->reset_tol =3D update_value_control_source(regs, regs->reset_tol,= val); +} + +static void _write_debounce_1(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->debounce_1 =3D update_value_control_source(regs, regs->debounce_= 1, val); +} + +static void _write_debounce_2(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->debounce_2 =3D update_value_control_source(regs, regs->debounce_= 2, val); +} + +static void _write_cmd_source_0(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->cmd_source_0 =3D val & ASPEED_CMD_SRC_MASK; +} + +static void _write_cmd_source_1(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->cmd_source_1 =3D val & ASPEED_CMD_SRC_MASK; +} + +/* + * feeds into interrupt generation + * 0: read from data value reg will be updated + * 1: read from data value reg will not be updated + */ +static void _write_input_mask(AspeedGPIOState *s, GPIORegs *regs, + GPIOSetProperties *props, uint32_t val) +{ + regs->input_mask =3D val & props->input; + aspeed_gpio_update(s, regs); +} + +static const struct AspeedGPIO gpios[0x1f0] =3D { + /* Set ABCD */ + [GPIO_ABCD_DATA_VALUE] =3D {0, read_data_value, _write_data_value}, + [GPIO_ABCD_DIRECTION] =3D {0, read_direction, _write_direction}, + [GPIO_ABCD_INT_ENABLE] =3D {0, read_int_enable, _write_int_enable}, + [GPIO_ABCD_INT_SENS_0] =3D {0, read_int_sens_0, _write_int_sens_0}, + [GPIO_ABCD_INT_SENS_1] =3D {0, read_int_sens_1, _write_int_sens_1}, + [GPIO_ABCD_INT_SENS_2] =3D {0, read_int_sens_2, _write_int_sens_2}, + [GPIO_ABCD_INT_STATUS] =3D {0, read_int_status, _write_int_status}, + [GPIO_ABCD_RESET_TOLERANT] =3D {0, read_reset_tol, _write_reset_tol}, + [GPIO_ABCD_DEBOUNCE_1] =3D {0, read_debounce_1, _write_debounce_1}, + [GPIO_ABCD_DEBOUNCE_2] =3D {0, read_debounce_2, _write_debounce_2}, + [GPIO_ABCD_COMMAND_SRC_0] =3D {0, read_cmd_source_0, _write_cmd_source= _0}, + [GPIO_ABCD_COMMAND_SRC_1] =3D {0, read_cmd_source_1, _write_cmd_source= _1}, + [GPIO_ABCD_DATA_READ] =3D {0, read_data, NULL}, + [GPIO_ABCD_INPUT_MASK] =3D {0, read_input_mask, _write_input_mask}, + /* Set EFGH */ + [GPIO_EFGH_DATA_VALUE] =3D {1, read_data_value, _write_data_value}, + [GPIO_EFGH_DIRECTION] =3D {1, read_direction, _write_direction }, + [GPIO_EFGH_INT_ENABLE] =3D {1, read_int_enable, _write_int_enable}, + [GPIO_EFGH_INT_SENS_0] =3D {1, read_int_sens_0, _write_int_sens_0}, + [GPIO_EFGH_INT_SENS_1] =3D {1, read_int_sens_1, _write_int_sens_1}, + [GPIO_EFGH_INT_SENS_2] =3D {1, read_int_sens_2, _write_int_sens_2}, + [GPIO_EFGH_INT_STATUS] =3D {1, read_int_status, _write_int_status}, + [GPIO_EFGH_RESET_TOL] =3D {1, read_reset_tol, _write_reset_tol}, + [GPIO_EFGH_DEBOUNCE_1] =3D {1, read_debounce_1, _write_debounce_1}, + [GPIO_EFGH_DEBOUNCE_2] =3D {1, read_debounce_2, _write_debounce_2}, + [GPIO_EFGH_COMMAND_SRC_0] =3D {1, read_cmd_source_0, _write_cmd_sourc= e_0}, + [GPIO_EFGH_COMMAND_SRC_1] =3D {1, read_cmd_source_1, _write_cmd_sourc= e_1}, + [GPIO_EFGH_DATA_READ] =3D {1, read_data, NULL}, + [GPIO_EFGH_INPUT_MASK] =3D {1, read_input_mask, _write_input_mask}, + /* Set IJKL */ + [GPIO_IJKL_DATA_VALUE] =3D {2, read_data_value, _write_data_value}, + [GPIO_IJKL_DIRECTION] =3D {2, read_direction, _write_direction}, + [GPIO_IJKL_INT_ENABLE] =3D {2, read_int_enable, _write_int_enable}, + [GPIO_IJKL_INT_SENS_0] =3D {2, read_int_sens_0, _write_int_sens_0}, + [GPIO_IJKL_INT_SENS_1] =3D {2, read_int_sens_1, _write_int_sens_1}, + [GPIO_IJKL_INT_SENS_2] =3D {2, read_int_sens_2, _write_int_sens_2}, + [GPIO_IJKL_INT_STATUS] =3D {2, read_int_status, _write_int_status}, + [GPIO_IJKL_RESET_TOLERANT] =3D {2, read_reset_tol, _write_reset_tol}, + [GPIO_IJKL_DEBOUNCE_1] =3D {2, read_debounce_1, _write_debounce_1}, + [GPIO_IJKL_DEBOUNCE_2] =3D {2, read_debounce_2, _write_debounce_2}, + [GPIO_IJKL_COMMAND_SRC_0] =3D {2, read_cmd_source_0, _write_cmd_source= _0}, + [GPIO_IJKL_COMMAND_SRC_1] =3D {2, read_cmd_source_1, _write_cmd_source= _1}, + [GPIO_IJKL_DATA_READ] =3D {2, read_data, NULL}, + [GPIO_IJKL_INPUT_MASK] =3D {2, read_input_mask, _write_input_mask}, + /* Set MNOP */ + [GPIO_MNOP_DATA_VALUE] =3D {3, read_data_value, _write_data_value}, + [GPIO_MNOP_DIRECTION] =3D {3, read_direction, _write_direction}, + [GPIO_MNOP_INT_ENABLE] =3D {3, read_int_enable, _write_int_enable}, + [GPIO_MNOP_INT_SENS_0] =3D {3, read_int_sens_0, _write_int_sens_0}, + [GPIO_MNOP_INT_SENS_1] =3D {3, read_int_sens_1, _write_int_sens_1}, + [GPIO_MNOP_INT_SENS_2] =3D {3, read_int_sens_2, _write_int_sens_2}, + [GPIO_MNOP_INT_STATUS] =3D {3, read_int_status, _write_int_status}, + [GPIO_MNOP_RESET_TOLERANT] =3D {3, read_reset_tol, _write_reset_tol}, + [GPIO_MNOP_DEBOUNCE_1] =3D {3, read_debounce_1, _write_debounce_1}, + [GPIO_MNOP_DEBOUNCE_2] =3D {3, read_debounce_2, _write_debounce_2}, + [GPIO_MNOP_COMMAND_SRC_0] =3D {3, read_cmd_source_0, _write_cmd_source= _0}, + [GPIO_MNOP_COMMAND_SRC_1] =3D {3, read_cmd_source_1, _write_cmd_source= _1}, + [GPIO_MNOP_DATA_READ] =3D {3, read_data, NULL}, + [GPIO_MNOP_INPUT_MASK] =3D {3, read_input_mask, _write_input_mask}, + /* Set QRST */ + [GPIO_QRST_DATA_VALUE] =3D {4, read_data_value, _write_data_value}, + [GPIO_QRST_DIRECTION] =3D {4, read_direction, _write_direction}, + [GPIO_QRST_INT_ENABLE] =3D {4, read_int_enable, _write_int_enable}, + [GPIO_QRST_INT_SENS_0] =3D {4, read_int_sens_0, _write_int_sens_0}, + [GPIO_QRST_INT_SENS_1] =3D {4, read_int_sens_1, _write_int_sens_1}, + [GPIO_QRST_INT_SENS_2] =3D {4, read_int_sens_2, _write_int_sens_2}, + [GPIO_QRST_INT_STATUS] =3D {4, read_int_status, _write_int_status}, + [GPIO_QRST_RESET_TOLERANT] =3D {4, read_reset_tol, _write_reset_tol}, + [GPIO_QRST_DEBOUNCE_1] =3D {4, read_debounce_1, _write_debounce_1}, + [GPIO_QRST_DEBOUNCE_2] =3D {4, read_debounce_2, _write_debounce_2}, + [GPIO_QRST_COMMAND_SRC_0] =3D {4, read_cmd_source_0, _write_cmd_source= _0}, + [GPIO_QRST_COMMAND_SRC_1] =3D {4, read_cmd_source_1, _write_cmd_source= _1}, + [GPIO_QRST_DATA_READ] =3D {4, read_data, NULL}, + [GPIO_QRST_INPUT_MASK] =3D {4, read_input_mask, _write_input_mask}, + /* Set UVWX */ + [GPIO_UVWX_DATA_VALUE] =3D {5, read_data_value, _write_data_value}, + [GPIO_UWVX_DIRECTION] =3D {5, read_direction, _write_direction}, + [GPIO_UVWX_INT_ENABLE] =3D {5, read_int_enable, _write_int_enable}, + [GPIO_UVWX_INT_SENS_0] =3D {5, read_int_sens_0, _write_int_sens_0}, + [GPIO_UVWX_INT_SENS_1] =3D {5, read_int_sens_1, _write_int_sens_1}, + [GPIO_UVWX_INT_SENS_2] =3D {5, read_int_sens_2, _write_int_sens_2}, + [GPIO_UVWX_INT_STATUS] =3D {5, read_int_status, _write_int_status}, + [GPIO_UVWX_RESET_TOLERANT] =3D {5, read_reset_tol, _write_reset_tol}, + [GPIO_UVWX_DEBOUNCE_1] =3D {5, read_debounce_1, _write_debounce_1}, + [GPIO_UVWX_DEBOUNCE_2] =3D {5, read_debounce_2, _write_debounce_2}, + [GPIO_UVWX_COMMAND_SRC_0] =3D {5, read_cmd_source_0, _write_cmd_source= _0}, + [GPIO_UVWX_COMMAND_SRC_1] =3D {5, read_cmd_source_1, _write_cmd_source= _1}, + [GPIO_UVWX_DATA_READ] =3D {5, read_data, NULL}, + [GPIO_UVWX_INPUT_MASK] =3D {5, read_input_mask, _write_input_mask}, + /* Set YZAAAB */ + [GPIO_YZAAAB_DATA_VALUE] =3D {6, read_data_value, _write_data_value}, + [GPIO_YZAAAB_DIRECTION] =3D {6, read_direction, _write_direction}, + [GPIO_YZAAAB_INT_ENABLE] =3D {6, read_int_enable, _write_int_enable}, + [GPIO_YZAAAB_INT_SENS_0] =3D {6, read_int_sens_0, _write_int_sens_0}, + [GPIO_YZAAAB_INT_SENS_1] =3D {6, read_int_sens_1, _write_int_sens_1}, + [GPIO_YZAAAB_INT_SENS_2] =3D {6, read_int_sens_2, _write_int_sens_2}, + [GPIO_YZAAAB_INT_STATUS] =3D {6, read_int_status, _write_int_status}, + [GPIO_YZAAAB_RESET_TOLERANT] =3D {6, read_reset_tol, _write_reset_tol}, + [GPIO_YZAAAB_DEBOUNCE_1] =3D {6, read_debounce_1, _write_debounce_1}, + [GPIO_YZAAAB_DEBOUNCE_2] =3D {6, read_debounce_2, _write_debounce_2}, + [GPIO_YZAAAB_COMMAND_SRC_0] =3D {6, read_cmd_source_0, _write_cmd_sour= ce_0}, + [GPIO_YZAAAB_COMMAND_SRC_1] =3D {6, read_cmd_source_1, _write_cmd_sour= ce_1}, + [GPIO_YZAAAB_DATA_READ] =3D {6, read_data, NULL}, + [GPIO_YZAAAB_INPUT_MASK] =3D {6, read_input_mask, _write_input_mask}, + /* Set AC */ + [GPIO_AC_DATA_VALUE] =3D {7, read_data_value, _write_data_value}, + [GPIO_AC_DIRECTION] =3D {7, read_direction, _write_direction}, + [GPIO_AC_INT_ENABLE] =3D {7, read_int_enable, _write_int_enable}, + [GPIO_AC_INT_SENS_0] =3D {7, read_int_sens_0, _write_int_sens_0}, + [GPIO_AC_INT_SENS_1] =3D {7, read_int_sens_1, _write_int_sens_1}, + [GPIO_AC_INT_SENS_2] =3D {7, read_int_sens_2, _write_int_sens_2}, + [GPIO_AC_INT_STATUS] =3D {7, read_int_status, _write_int_status}, + [GPIO_AC_RESET_TOLERANT] =3D {7, read_reset_tol, _write_reset_tol}, + [GPIO_AC_DEBOUNCE_1] =3D {7, read_debounce_1, _write_debounce_1}, + [GPIO_AC_DEBOUNCE_2] =3D {7, read_debounce_2, _write_debounce_2}, + [GPIO_AC_COMMAND_SRC_0] =3D {7, read_cmd_source_0, _write_cmd_source_0= }, + [GPIO_AC_COMMAND_SRC_1] =3D {7, read_cmd_source_1, _write_cmd_source_1= }, + [GPIO_AC_DATA_READ] =3D {7, read_data, NULL}, + [GPIO_AC_INPUT_MASK] =3D {7, read_input_mask, _write_input_mask}, + /* Debounce registers */ + [GPIO_DEBOUNCE_TIME_1] =3D {-1, NULL, NULL}, +}; + +static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t siz= e) +{ + AspeedGPIOState *s =3D ASPEED_GPIO(opaque); + uint32_t val =3D 0; + + if (size !=3D 4) { + return 0; + } + + if (gpios[offset].get =3D=3D NULL) { + qemu_log_mask(LOG_GUEST_ERROR, "no getter for offset %lx", offset); + return 0; + } + + val =3D gpios[offset].get(&s->sets[gpios[offset].set_idx]); + return (uint64_t) val; +} + +static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, + uint32_t size) +{ + AspeedGPIOState *s =3D ASPEED_GPIO(opaque); + GPIOSetProperties *props =3D &s->ctrl->props[gpios[offset].set_idx]; + + if (gpios[offset].set =3D=3D NULL) { + qemu_log_mask(LOG_GUEST_ERROR, "no setter for offset %lx", offset); + return; + } + + uint32_t mask =3D props->input | props->output; + + gpios[offset].set(s, &s->sets[gpios[offset].set_idx], + props, data & mask); +} + +static void aspeed_gpio_get_pin(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + int pin =3D 0xfff; + bool level =3D true; + char group[3]; + AspeedGPIOState *s =3D ASPEED_GPIO(obj); + if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) !=3D 2) { + qemu_log_mask(LOG_GUEST_ERROR, "error reading %s", name); + return; + } + level =3D aspeed_gpio_get_pin_level(s, pin); + visit_type_bool(v, name, &level, errp); +} + +static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + Error *local_err =3D NULL; + bool level; + int pin =3D 0xfff; + char group[3]; + AspeedGPIOState *s =3D ASPEED_GPIO(obj); + visit_type_bool(v, name, &level, &local_err); + if (sscanf(name, "gpio%2[A-Z]%1d", group, &pin) !=3D 2) { + qemu_log_mask(LOG_GUEST_ERROR, "error reading %s", name); + return; + } + aspeed_gpio_set_pin_level(s, pin, level); +} + + +/* Setup functions */ +static const MemoryRegionOps aspeed_gpio_ops =3D { + .read =3D aspeed_gpio_read, + .write =3D aspeed_gpio_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid.min_access_size =3D 4, + .valid.max_access_size =3D 4, +}; + +static void aspeed_gpio_reset(DeviceState *dev) +{ + struct AspeedGPIOState *s =3D ASPEED_GPIO(dev); + + /* TODO: respect the reset tolerance registers */ + memset(s->sets, 0, sizeof(s->sets)); +} + +static void aspeed_gpio_realize(DeviceState *dev, Error **errp) +{ + AspeedGPIOState *s =3D ASPEED_GPIO(dev); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(dev); + + sysbus_init_irq(sbd, &s->irq); + + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s, + TYPE_ASPEED_GPIO, 0x1000); + + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription vmstate_gpio_regs =3D { + .name =3D TYPE_ASPEED_GPIO"/regs", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32(data_value, GPIORegs), + VMSTATE_UINT32(data_read, GPIORegs), + VMSTATE_UINT32(direction, GPIORegs), + VMSTATE_UINT32(int_enable, GPIORegs), + VMSTATE_UINT32(int_sens_0, GPIORegs), + VMSTATE_UINT32(int_sens_1, GPIORegs), + VMSTATE_UINT32(int_sens_2, GPIORegs), + VMSTATE_UINT32(int_status, GPIORegs), + VMSTATE_UINT32(reset_tol, GPIORegs), + VMSTATE_UINT32(cmd_source_0, GPIORegs), + VMSTATE_UINT32(cmd_source_1, GPIORegs), + VMSTATE_UINT32(debounce_1, GPIORegs), + VMSTATE_UINT32(debounce_2, GPIORegs), + VMSTATE_UINT32(input_mask, GPIORegs), + VMSTATE_END_OF_LIST(), + } +}; +static const VMStateDescription vmstate_aspeed_gpio =3D { + .name =3D TYPE_ASPEED_GPIO, + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(sets, AspeedGPIOState, ASPEED_GPIO_MAX_NR_SET= S, + 1, vmstate_gpio_regs, GPIORegs), + VMSTATE_END_OF_LIST(), + } +}; + +static void aspeed_gpio_init(Object *obj) +{ + AspeedGPIOState *s =3D ASPEED_GPIO(obj); + AspeedGPIOClass *agc =3D ASPEED_GPIO_GET_CLASS(s); + int pin; + + s->ctrl =3D agc->ctrl; + + for (pin =3D 0; pin < agc->ctrl->nr_gpio_pins; pin++) { + char *name; + int set_idx =3D aspeed_get_set_idx_from_pin(s, pin); + int _pin =3D aspeed_adjust_pin(s, pin); + int pin_idx =3D _pin - (set_idx * 32); + int group_idx =3D pin_idx >> 3; + + name =3D g_strdup_printf("gpio%s%d", + agc->ctrl->props[set_idx].set[group_idx], + pin_idx % 8); + object_property_add(obj, name, "bool", + aspeed_gpio_get_pin, + aspeed_gpio_set_pin, + NULL, NULL, NULL); + } +} + +static void aspeed_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + AspeedGPIOClass *agc =3D ASPEED_GPIO_CLASS(klass); + + dc->realize =3D aspeed_gpio_realize; + dc->reset =3D aspeed_gpio_reset; + dc->desc =3D "Aspeed GPIO Controller"; + dc->vmsd =3D &vmstate_aspeed_gpio; + agc->ctrl =3D data; +} + +static GPIOSetProperties ast2400_set_props[] =3D { + [0] =3D {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} }, + [1] =3D {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} }, + [2] =3D {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} }, + [3] =3D {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} }, + [4] =3D {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} }, + [5] =3D {0xffffffff, 0x0000ffff, {"U", "V", "W", "X"} }, + [6] =3D {0x0000000f, 0x0fffff0f, {"Y", "Z", "AA", "AB"} }, +}; + +static GPIOSetProperties ast2500_set_props[] =3D { + [0] =3D {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} }, + [1] =3D {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} }, + [2] =3D {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} }, + [3] =3D {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} }, + [4] =3D {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} }, + [5] =3D {0xffffffff, 0x0000ffff, {"U", "V", "W", "X"} }, + [6] =3D {0xffffff0f, 0x0fffff0f, {"Y", "Z", "AA", "AB"} }, + [7] =3D {0x000000ff, 0x000000ff, {"AC"} }, +}; + +static AspeedGPIOController controllers[] =3D { + { + .name =3D TYPE_ASPEED_GPIO "-ast2500", + .props =3D ast2500_set_props, + .nr_gpio_pins =3D 228, + .nr_gpio_sets =3D 8, + .gap =3D 220, + }, { + .name =3D TYPE_ASPEED_GPIO "-ast2400", + .props =3D ast2400_set_props, + .nr_gpio_pins =3D 216, + .nr_gpio_sets =3D 7, + .gap =3D 196, + } +}; + +static const TypeInfo aspeed_gpio_info =3D { + .name =3D TYPE_ASPEED_GPIO, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(AspeedGPIOState), + .class_size =3D sizeof(AspeedGPIOClass), + .instance_init =3D aspeed_gpio_init, + .abstract =3D true, +}; + +static void aspeed_gpio_register_types(void) +{ + int i; + + type_register_static(&aspeed_gpio_info); + for (i =3D 0; i < ARRAY_SIZE(controllers); i++) { + TypeInfo t =3D { + .name =3D controllers[i].name, + .parent =3D TYPE_ASPEED_GPIO, + .class_init =3D aspeed_gpio_class_init, + .class_data =3D (void *)&controllers[i], + }; + type_register(&t); + }; +} + +type_init(aspeed_gpio_register_types); diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h new file mode 100644 index 0000000000..97a84a5da1 --- /dev/null +++ b/include/hw/gpio/aspeed_gpio.h @@ -0,0 +1,76 @@ +/* + * ASPEED GPIO Controller + * + * Copyright (C) 2017-2018 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#ifndef ASPEED_GPIO_H +#define ASPEED_GPIO_H + +#include "hw/sysbus.h" + +#define TYPE_ASPEED_GPIO "aspeed.gpio" +#define ASPEED_GPIO(obj) OBJECT_CHECK(AspeedGPIOState, (obj), TYPE_ASPEED_= GPIO) +#define ASPEED_GPIO_CLASS(klass) \ + OBJECT_CLASS_CHECK(AspeedGPIOClass, (klass), TYPE_ASPEED_GPIO) +#define ASPEED_GPIO_GET_CLASS(obj) \ + OBJECT_GET_CLASS(AspeedGPIOClass, (obj), TYPE_ASPEED_GPIO) + +#define ASPEED_GPIO_MAX_NR_SETS 8 +#define ASPEED_REGS_PER_BANK 14 +#define ASPEED_GPIO_MAX_NR_REGS (ASPEED_REGS_PER_BANK * ASPEED_GPIO_MAX_NR= _SETS) +#define ASPEED_GPIO_NR_PINS 228 + +typedef struct GPIORegs GPIORegs; +typedef const struct GPIOSetProperties { + uint32_t input; + uint32_t output; + char set[4][3]; +} GPIOSetProperties; + +typedef const struct AspeedGPIOController { + const char *name; + GPIOSetProperties *props; + uint32_t nr_gpio_pins; + uint32_t nr_gpio_sets; + uint32_t gap; +} AspeedGPIOController; + +typedef struct AspeedGPIOClass { + SysBusDevice parent_obj; + AspeedGPIOController *ctrl; +} AspeedGPIOClass; + +typedef struct AspeedGPIOState { + /* */ + SysBusDevice parent; + + /*< public >*/ + MemoryRegion iomem; + qemu_irq output[ASPEED_GPIO_NR_PINS]; + qemu_irq irq; + AspeedGPIOController *ctrl; + +/* Parallel GPIO Registers */ + struct GPIORegs { + uint32_t data_value; /* Reflects pin values */ + uint32_t data_read; /* Contains last value written to data value */ + uint32_t direction; + uint32_t int_enable; + uint32_t int_sens_0; + uint32_t int_sens_1; + uint32_t int_sens_2; + uint32_t int_status; + uint32_t reset_tol; + uint32_t cmd_source_0; + uint32_t cmd_source_1; + uint32_t debounce_1; + uint32_t debounce_2; + uint32_t input_mask; + } sets[ASPEED_GPIO_MAX_NR_SETS]; +} AspeedGPIOState; + +#endif /* _ASPEED_GPIO_H_ */ --=20 2.17.2 From nobody Tue Nov 11 01:37:59 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1560848044; cv=none; d=zoho.com; s=zohoarc; b=Q/LD9tGMiVg5J5zY59gnei6WqnzaSHRm9/70HmomrtFrdMCwRsF7li3XQZWFcTqGxso8IpzOHn9d3XDoa5l/kZ9IXZf0r19ULIQ55zH+LJ9/XAgbQ7UIVHAkh9QhWp7MmN8Ih+1p2MbGwVt1cvRBi60KpPspgLN2m4Nxo81sT0I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1560848044; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=E7RZnL+vY/V37+EcuN6Eh+i0O5QdDnRjk1ExQ99addY=; b=JCH9p1WbxCjwp/Z9DTZwslPNb9K/jMfjvXft0Q37JPFk+sfIafZ3UmDYpPZrXps0oq+kl8vQnDsqyr//AHL0qo+FEL++/0JSl2WR+vno70QFbxdhejY0K1Zb7N54PKCORz+7+NFLVFsoHSX12G3YXVrkK3O8jclDmo4gjUc8ljU= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1560848044422327.98697665245106; Tue, 18 Jun 2019 01:54:04 -0700 (PDT) Received: from localhost ([::1]:54900 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hd9sO-0008N6-AP for importer@patchew.org; Tue, 18 Jun 2019 04:54:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45097) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hd9qs-0007AA-14 for qemu-devel@nongnu.org; Tue, 18 Jun 2019 04:52:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hd9qq-0000na-2K for qemu-devel@nongnu.org; Tue, 18 Jun 2019 04:52:25 -0400 Received: from mail-pl1-x641.google.com ([2607:f8b0:4864:20::641]:46295) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hd9qk-0000i6-1n; Tue, 18 Jun 2019 04:52:18 -0400 Received: by mail-pl1-x641.google.com with SMTP id e5so5402511pls.13; Tue, 18 Jun 2019 01:52:16 -0700 (PDT) Received: from rashmica.home.majoof.com ([43.245.162.131]) by smtp.gmail.com with ESMTPSA id p7sm27032616pfp.131.2019.06.18.01.52.12 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 18 Jun 2019 01:52:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=E7RZnL+vY/V37+EcuN6Eh+i0O5QdDnRjk1ExQ99addY=; b=RBGzZ3GdDUpBtU0cP3Re8FcE19uFVuCcxCCSjkmTpqFVPvIG2c44I8hr1CiZK7Z+t4 rlJqVdIng79LzSfk/FLaqHCqVWtqhBVdZpHEE8PhKuPb2sOAQ5pe5PBc5VFwJS2BwVg0 Hr8hHsUKxDsgKhTCDd3teNMTr2CgVSKvDm6cZqXdhisVkXnkpM3Bq3PWyE+OlqoBZWUJ 2lbwEoHjGkv1osFI+MFcUG2/mHYu8B7px0VfEHJQu9ffhC1DUKHGHP8xDiOhHhz7YjBm fLenypUbKslqXP/PLZ5jp6DHUO5OKjYdp06m284DP2RrQrtSAtRr7gvz/kjggpZgnPgb EnpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=E7RZnL+vY/V37+EcuN6Eh+i0O5QdDnRjk1ExQ99addY=; b=Oo6T3bM9UGTqH3Fo22acVdDgd1hOgQSmybU/4MBfM11XzBqmSd1nPZhymQ3lpu7jeY /33Zoc0/z4XEAa4LUHrLJ0so8p0MQEd/E1hrNYaPMNU0rSMSp3PGUCIlFeLZ4mu5nd6z 5tUxLVz89BZ/pSbp7V8IYatsTOSpLeeVMB8ABe8JhJxzvXt41OcwZIoF2A0RwEpDOBIi kYz0N+nj+DzKcbW4vFjjj5Gg4pIuucCLSWhvNza0d31tnhHBEFxkgTWOp0jpsyLHl+vx 0dmmmXGJFfwZmjCG7XoPfX7x1VVKAg8zwGJdNnOjx9GN7HNMdLfSzTCKz6f+QCh9INfZ sA2w== X-Gm-Message-State: APjAAAWYAbq606BM3jQkkxv56ZRvani77Ph79031wE5nJifr6dKFpNdG bn/daKYQAlebyi4gCIvzOIph9zI0 X-Google-Smtp-Source: APXvYqw4AQNRM5U29WZAuL7vBWpIdWDzvv16a8wPsx/Mfr+cd+CU2cxHATmIoOPne8xELVoxUC70Pw== X-Received: by 2002:a17:902:7d8d:: with SMTP id a13mr222978plm.98.1560847935802; Tue, 18 Jun 2019 01:52:15 -0700 (PDT) From: Rashmica Gupta To: qemu-arm@nongnu.org Date: Tue, 18 Jun 2019 18:51:54 +1000 Message-Id: <20190618085154.21498-3-rashmica.g@gmail.com> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190618085154.21498-1-rashmica.g@gmail.com> References: <20190618085154.21498-1-rashmica.g@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::641 Subject: [Qemu-devel] [PATCH 2/2] aspeed: add a GPIO controller to the SoC X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: andrew@aj.id.au, clg@kaod.org, qemu-devel@nongnu.org, Rashmica Gupta , joel@jms.id.au Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Rashmica Gupta --- hw/arm/aspeed_soc.c | 17 +++++++++++++++++ include/hw/arm/aspeed_soc.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 1cc98b9f40..8583869acf 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -23,6 +23,7 @@ #include "net/net.h" =20 #define ASPEED_SOC_IOMEM_SIZE 0x00200000 +#define ASPEED_SOC_GPIO_BASE 0x1E780000 =20 static const hwaddr aspeed_soc_ast2400_memmap[] =3D { [ASPEED_IOMEM] =3D 0x1E600000, @@ -120,6 +121,7 @@ static const AspeedSoCInfo aspeed_socs[] =3D { .spis_num =3D 1, .fmc_typename =3D "aspeed.smc.fmc", .spi_typename =3D aspeed_soc_ast2400_typenames, + .gpio_typename =3D "aspeed.gpio-ast2400", .wdts_num =3D 2, .irqmap =3D aspeed_soc_ast2400_irqmap, .memmap =3D aspeed_soc_ast2400_memmap, @@ -131,6 +133,7 @@ static const AspeedSoCInfo aspeed_socs[] =3D { .spis_num =3D 1, .fmc_typename =3D "aspeed.smc.fmc", .spi_typename =3D aspeed_soc_ast2400_typenames, + .gpio_typename =3D "aspeed.gpio-ast2400", .wdts_num =3D 2, .irqmap =3D aspeed_soc_ast2400_irqmap, .memmap =3D aspeed_soc_ast2400_memmap, @@ -142,6 +145,7 @@ static const AspeedSoCInfo aspeed_socs[] =3D { .spis_num =3D 1, .fmc_typename =3D "aspeed.smc.fmc", .spi_typename =3D aspeed_soc_ast2400_typenames, + .gpio_typename =3D "aspeed.gpio-ast2400", .wdts_num =3D 2, .irqmap =3D aspeed_soc_ast2400_irqmap, .memmap =3D aspeed_soc_ast2400_memmap, @@ -153,6 +157,7 @@ static const AspeedSoCInfo aspeed_socs[] =3D { .spis_num =3D 2, .fmc_typename =3D "aspeed.smc.ast2500-fmc", .spi_typename =3D aspeed_soc_ast2500_typenames, + .gpio_typename =3D "aspeed.gpio-ast2500", .wdts_num =3D 3, .irqmap =3D aspeed_soc_ast2500_irqmap, .memmap =3D aspeed_soc_ast2500_memmap, @@ -225,6 +230,8 @@ static void aspeed_soc_init(Object *obj) =20 sysbus_init_child_obj(obj, "ftgmac100", OBJECT(&s->ftgmac100), sizeof(s->ftgmac100), TYPE_FTGMAC100); + sysbus_init_child_obj(obj, "gpio", OBJECT(&s->gpio), sizeof(s->gpio), + sc->info->gpio_typename); } =20 static void aspeed_soc_realize(DeviceState *dev, Error **errp) @@ -366,6 +373,16 @@ static void aspeed_soc_realize(DeviceState *dev, Error= **errp) sc->info->memmap[ASPEED_ETH1]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0, aspeed_soc_get_irq(s, ASPEED_ETH1)); + + /* GPIO */ + object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, ASPEED_SOC_GPIO_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, + qdev_get_gpio_in(DEVICE(&s->vic), 20)); } =20 static void aspeed_soc_class_init(ObjectClass *oc, void *data) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 88b901d5df..28ff2bedb4 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -20,6 +20,7 @@ #include "hw/ssi/aspeed_smc.h" #include "hw/watchdog/wdt_aspeed.h" #include "hw/net/ftgmac100.h" +#include "hw/gpio/aspeed_gpio.h" =20 #define ASPEED_SPIS_NUM 2 #define ASPEED_WDTS_NUM 3 @@ -40,6 +41,7 @@ typedef struct AspeedSoCState { AspeedSDMCState sdmc; AspeedWDTState wdt[ASPEED_WDTS_NUM]; FTGMAC100State ftgmac100; + AspeedGPIOState gpio; } AspeedSoCState; =20 #define TYPE_ASPEED_SOC "aspeed-soc" @@ -53,6 +55,7 @@ typedef struct AspeedSoCInfo { int spis_num; const char *fmc_typename; const char **spi_typename; + const char *gpio_typename; int wdts_num; const int *irqmap; const hwaddr *memmap; --=20 2.17.2