From nobody Mon Feb 9 02:27:53 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 165345790493091.38620219640984; Tue, 24 May 2022 22:51:44 -0700 (PDT) Received: from localhost ([::1]:55660 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ntjvj-0006B2-GC for importer@patchew.org; Wed, 25 May 2022 01:51:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50334) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ntjgF-0000dS-N8; Wed, 25 May 2022 01:35:35 -0400 Received: from twspam01.aspeedtech.com ([211.20.114.71]:12563) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ntjgD-0003st-3O; Wed, 25 May 2022 01:35:35 -0400 Received: from mail.aspeedtech.com ([192.168.0.24]) by twspam01.aspeedtech.com with ESMTP id 24P5Khgs022846; Wed, 25 May 2022 13:20:44 +0800 (GMT-8) (envelope-from jamin_lin@aspeedtech.com) Received: from localhost.localdomain (192.168.70.123) by TWMBX02.aspeed.com (192.168.0.24) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 25 May 2022 13:34:48 +0800 From: Jamin Lin To: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , Peter Maydell , Andrew Jeffery , Joel Stanley , "open list:ASPEED BMCs" , "open list:All patches CC here" CC: , , Subject: [PATCH v2 3/4] hw/gpio support GPIO index mode for write operation. Date: Wed, 25 May 2022 13:34:43 +0800 Message-ID: <20220525053444.27228-4-jamin_lin@aspeedtech.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220525053444.27228-1-jamin_lin@aspeedtech.com> References: <20220525053444.27228-1-jamin_lin@aspeedtech.com> MIME-Version: 1.0 X-Originating-IP: [192.168.70.123] X-ClientProxiedBy: TWMBX02.aspeed.com (192.168.0.24) To TWMBX02.aspeed.com (192.168.0.24) X-DNSRBL: X-MAIL: twspam01.aspeedtech.com 24P5Khgs022846 Received-SPF: pass (zohomail.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; Received-SPF: pass client-ip=211.20.114.71; envelope-from=jamin_lin@aspeedtech.com; helo=twspam01.aspeedtech.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZM-MESSAGEID: 1653457905689100001 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" It did not support GPIO index mode for read operation. Signed-off-by: Jamin Lin Reviewed-by: C=C3=A9dric Le Goater --- hw/gpio/aspeed_gpio.c | 168 ++++++++++++++++++++++++++++++++++ include/hw/gpio/aspeed_gpio.h | 14 +++ 2 files changed, 182 insertions(+) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 5138fe812b..c834bf19f5 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -16,6 +16,7 @@ #include "hw/irq.h" #include "migration/vmstate.h" #include "trace.h" +#include "hw/registerfields.h" =20 #define GPIOS_PER_GROUP 8 =20 @@ -204,6 +205,28 @@ #define GPIO_1_8V_MEM_SIZE 0x1D8 #define GPIO_1_8V_REG_ARRAY_SIZE (GPIO_1_8V_MEM_SIZE >> 2) =20 +/* + * GPIO index mode support + * It only supports write operation + */ +REG32(GPIO_INDEX_REG, 0x2AC) + FIELD(GPIO_INDEX_REG, NUMBER, 0, 8) + FIELD(GPIO_INDEX_REG, COMMAND, 12, 1) + FIELD(GPIO_INDEX_REG, TYPE, 16, 4) + FIELD(GPIO_INDEX_REG, DATA_VALUE, 20, 1) + FIELD(GPIO_INDEX_REG, DIRECTION, 20, 1) + FIELD(GPIO_INDEX_REG, INT_ENABLE, 20, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_0, 21, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_1, 22, 1) + FIELD(GPIO_INDEX_REG, INT_SENS_2, 23, 1) + FIELD(GPIO_INDEX_REG, INT_STATUS, 24, 1) + FIELD(GPIO_INDEX_REG, DEBOUNCE_1, 20, 1) + FIELD(GPIO_INDEX_REG, DEBOUNCE_2, 21, 1) + FIELD(GPIO_INDEX_REG, RESET_TOLERANT, 20, 1) + FIELD(GPIO_INDEX_REG, COMMAND_SRC_0, 20, 1) + FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1) + FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1) + static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpi= o) { uint32_t falling_edge =3D 0, rising_edge =3D 0; @@ -596,6 +619,144 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr= offset, uint32_t size) return value; } =20 +static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset, + uint64_t data, uint32_t si= ze) +{ + + AspeedGPIOState *s =3D ASPEED_GPIO(opaque); + AspeedGPIOClass *agc =3D ASPEED_GPIO_GET_CLASS(s); + const GPIOSetProperties *props; + GPIOSets *set; + uint32_t reg_idx_number =3D FIELD_EX32(data, GPIO_INDEX_REG, NUMBER); + uint32_t reg_idx_type =3D FIELD_EX32(data, GPIO_INDEX_REG, TYPE); + uint32_t reg_idx_command =3D FIELD_EX32(data, GPIO_INDEX_REG, COMMAND); + uint32_t set_idx =3D reg_idx_number / ASPEED_GPIOS_PER_SET; + uint32_t pin_idx =3D reg_idx_number % ASPEED_GPIOS_PER_SET; + uint32_t group_idx =3D pin_idx / GPIOS_PER_GROUP; + uint32_t reg_value =3D 0; + uint32_t cleared; + + set =3D &s->sets[set_idx]; + props =3D &agc->props[set_idx]; + + if (reg_idx_command) + qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" PRIx64 "data 0x%" + PRIx64 "index mode wrong command 0x%x\n", + __func__, offset, data, reg_idx_command); + + switch (reg_idx_type) { + case gpio_reg_idx_data: + reg_value =3D set->data_read; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DATA_VALUE)= ); + reg_value &=3D props->output; + reg_value =3D update_value_control_source(set, set->data_value, + reg_value); + set->data_read =3D reg_value; + aspeed_gpio_update(s, set, reg_value); + return; + case gpio_reg_idx_direction: + reg_value =3D set->direction; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DIRECTION)); + /* + * where data is the value attempted to be written to the pin: + * pin type | input mask | output mask | expected value + * ------------------------------------------------------------ + * bidirectional | 1 | 1 | data + * input only | 1 | 0 | 0 + * output only | 0 | 1 | 1 + * no pin | 0 | 0 | 0 + * + * which is captured by: + * data =3D ( data | ~input) & output; + */ + reg_value =3D (reg_value | ~props->input) & props->output; + set->direction =3D update_value_control_source(set, set->direction, + reg_value); + break; + case gpio_reg_idx_interrupt: + reg_value =3D set->int_enable; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_ENABLE)= ); + set->int_enable =3D update_value_control_source(set, set->int_enab= le, + reg_value); + reg_value =3D set->int_sens_0; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_0)= ); + set->int_sens_0 =3D update_value_control_source(set, set->int_sens= _0, + reg_value); + reg_value =3D set->int_sens_1; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_1)= ); + set->int_sens_1 =3D update_value_control_source(set, set->int_sens= _1, + reg_value); + reg_value =3D set->int_sens_2; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2)= ); + set->int_sens_2 =3D update_value_control_source(set, set->int_sens= _2, + reg_value); + /* set interrupt status */ + reg_value =3D set->int_status; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)= ); + cleared =3D ctpop32(reg_value & set->int_status); + if (s->pending && cleared) { + assert(s->pending >=3D cleared); + s->pending -=3D cleared; + } + set->int_status &=3D ~reg_value; + break; + case gpio_reg_idx_debounce: + reg_value =3D set->debounce_1; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_1)= ); + set->debounce_1 =3D update_value_control_source(set, set->debounce= _1, + reg_value); + reg_value =3D set->debounce_2; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, DEBOUNCE_2)= ); + set->debounce_2 =3D update_value_control_source(set, set->debounce= _2, + reg_value); + return; + case gpio_reg_idx_tolerance: + reg_value =3D set->reset_tol; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, RESET_TOLER= ANT)); + set->reset_tol =3D update_value_control_source(set, set->reset_tol, + reg_value); + return; + case gpio_reg_idx_cmd_src: + reg_value =3D set->cmd_source_0; + reg_value =3D deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC= _0)); + set->cmd_source_0 =3D reg_value & ASPEED_CMD_SRC_MASK; + reg_value =3D set->cmd_source_1; + reg_value =3D deposit32(reg_value, GPIOS_PER_GROUP * group_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, COMMAND_SRC= _1)); + set->cmd_source_1 =3D reg_value & ASPEED_CMD_SRC_MASK; + return; + case gpio_reg_idx_input_mask: + reg_value =3D set->input_mask; + reg_value =3D deposit32(reg_value, pin_idx, 1, + FIELD_EX32(data, GPIO_INDEX_REG, INPUT_MASK)= ); + /* + * feeds into interrupt generation + * 0: read from data value reg will be updated + * 1: read from data value reg will not be updated + */ + set->input_mask =3D reg_value & props->input; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: offset 0x%" PRIx64 "data 0x%" + PRIx64 "index mode wrong type 0x%x\n", + __func__, offset, data, reg_idx_type); + return; + } + aspeed_gpio_update(s, set, set->data_value); + return; +} + static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, uint32_t size) { @@ -610,6 +771,13 @@ static void aspeed_gpio_write(void *opaque, hwaddr off= set, uint64_t data, trace_aspeed_gpio_write(offset, data); =20 idx =3D offset >> 2; + + /* check gpio index mode */ + if (idx =3D=3D R_GPIO_INDEX_REG) { + aspeed_gpio_write_index_mode(opaque, offset, data, size); + return; + } + if (idx >=3D GPIO_DEBOUNCE_TIME_1 && idx <=3D GPIO_DEBOUNCE_TIME_3) { idx -=3D GPIO_DEBOUNCE_TIME_1; s->debounce_regs[idx] =3D (uint32_t) data; diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h index 6dee3cd438..41b36524d0 100644 --- a/include/hw/gpio/aspeed_gpio.h +++ b/include/hw/gpio/aspeed_gpio.h @@ -50,6 +50,20 @@ enum GPIORegType { gpio_reg_input_mask, }; =20 +/* GPIO index mode */ +enum GPIORegIndexType { + gpio_reg_idx_data =3D 0, + gpio_reg_idx_direction, + gpio_reg_idx_interrupt, + gpio_reg_idx_debounce, + gpio_reg_idx_tolerance, + gpio_reg_idx_cmd_src, + gpio_reg_idx_input_mask, + gpio_reg_idx_reserved, + gpio_reg_idx_new_w_cmd_src, + gpio_reg_idx_new_r_cmd_src, +}; + typedef struct AspeedGPIOReg { uint16_t set_idx; enum GPIORegType type; --=20 2.17.1