{"id":2175855,"url":"http://patchwork.ozlabs.org/api/1.0/patches/2175855/?format=json","project":{"id":14,"url":"http://patchwork.ozlabs.org/api/1.0/projects/14/?format=json","name":"QEMU Development","link_name":"qemu-devel","list_id":"qemu-devel.nongnu.org","list_email":"qemu-devel@nongnu.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20251219-aspeed-sgpio-v5-3-fd5593178144@google.com>","date":"2025-12-19T07:04:16","name":"[v5,3/6] hw/gpio/aspeed_sgpio: Implement SGPIO interrupt handling","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"bb9c68ac45e9203f88678aa78cdafaa99ec5251a","submitter":{"id":91652,"url":"http://patchwork.ozlabs.org/api/1.0/people/91652/?format=json","name":"Yubin Zou","email":"yubinz@google.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20251219-aspeed-sgpio-v5-3-fd5593178144@google.com/mbox/","series":[{"id":485958,"url":"http://patchwork.ozlabs.org/api/1.0/series/485958/?format=json","date":"2025-12-19T07:04:13","name":"hw/gpio/aspeed_sgpio: Add Aspeed Serial GPIO (SGPIO) controller model","version":5,"mbox":"http://patchwork.ozlabs.org/series/485958/mbox/"}],"check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2175855/checks/","tags":{},"headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256\n header.s=20230601 header.b=0d1Bn2j1;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4dXdqR40zrz1y3t\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 19 Dec 2025 18:06:11 +1100 (AEDT)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1vWUXh-0003rO-7h; Fri, 19 Dec 2025 02:04:49 -0500","from eggs.gnu.org ([2001:470:142:3::10])\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from\n <3C_lEaQYKCmIYUBINZGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--yubinz.bounces.google.com>)\n id 1vWUXf-0003qq-MN\n for qemu-devel@nongnu.org; Fri, 19 Dec 2025 02:04:47 -0500","from mail-pg1-x54a.google.com ([2607:f8b0:4864:20::54a])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from\n <3C_lEaQYKCmIYUBINZGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--yubinz.bounces.google.com>)\n id 1vWUXd-0001bX-Rn\n for qemu-devel@nongnu.org; Fri, 19 Dec 2025 02:04:47 -0500","by mail-pg1-x54a.google.com with SMTP id\n 41be03b00d2f7-b99763210e5so2702353a12.3\n for <qemu-devel@nongnu.org>; Thu, 18 Dec 2025 23:04:44 -0800 (PST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=google.com; s=20230601; t=1766127883; x=1766732683; darn=nongnu.org;\n h=cc:to:from:subject:message-id:references:mime-version:in-reply-to\n :date:from:to:cc:subject:date:message-id:reply-to;\n bh=UEXr5Jd09L+9AgjqhDamfCsOvdLjpKDjLgvtKDEVv/A=;\n b=0d1Bn2j186Hnv8ozG0gqwzQxcRHgtrfF1mM9sQYAnYZ1xxlSu3nB5kmYUNaErJH2gy\n bP6eLzRTZkaUISy1rCp3OeTRN53bGZsjkAecW8qn8T8IKaBpH5e+bZLK2QDXx4Nt44BA\n Bf1OdGuFOU5NsSD1IhiVx6p0OQN9a5zFiKJcseKh+0DAyGFcVB78YGfFXh/N9pWdy3kv\n 8Bjb0GTgIZ8ht92DOYkeA7wACgYZrXEOHsJP00qlWtFxnM2KZ7jxTwB/SDZ6jEUhtZqv\n Jte7/UoqujlCEaUmkZHA5wreDs+daSVgWqPP36SxaMPbYHXqh4jdL8OQE1TE5vtIAQk4\n FPkQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1766127883; x=1766732683;\n h=cc:to:from:subject:message-id:references:mime-version:in-reply-to\n :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;\n bh=UEXr5Jd09L+9AgjqhDamfCsOvdLjpKDjLgvtKDEVv/A=;\n b=tp3hAbNOE15aKSr+WUIE6K/2jptznjUOTZcCa7fKGKFb9iMDiEh6zDJSXpNs51e8XP\n msR8dcWtx90D3bMXigqJkxD5CweALPhYcoCGyCtOZMCgSDv2iMijwgLkvNzB2p5XPhcP\n DPYu5ps7r6I/j3jaUi8tVYm5Q/m0ezQEdSviDIUazfuGVApuyM1MjS5WCtKe1DxFT6bm\n lrzkpf2CrtCY8wkFMgcV7+Wiqsl2kBD4KXnq5F2yWzZJbo5NwHJl/xBFJfaqJdcSZPwj\n QC5uxOxb+1G/7WqZf1zkBkZ3Txv3JAEg4GCr6RqhjR2HN3TZbziOzuFlCf3K225mgRRX\n sueA==","X-Gm-Message-State":"AOJu0Yx/DiCXJpu2KclHBw/IS9Ct91ioVqfU/QrMf4cWgxepFgopYiGn\n xgsnv94UT7XfrOQ3MI55kf1WbYDCakQmWHqbIZdXFqnJ6HcvcTMOev5jPN1WJxweaPpeLav2f42\n yorS93hfy0KmGZlOF9vr7IeW2WVlYHFEDbijvH5OvZxgIrhWcFsw92uTYBij2t7ciuuod8daCgv\n LU4ync0fJbdQ0K05z4MDkhSmiEdCjAACmomRU=","X-Google-Smtp-Source":"\n AGHT+IFQQ9YZMoX0ZMrrP+p1npcnsCJjUs8Y262JyoJ75fqq4xrKIFdV5u3LRiZGW12xibCgVRtyqUfm0fo=","X-Received":"from dlah10.prod.google.com\n ([2002:a05:701b:260a:b0:11f:4424:33c4])\n (user=yubinz job=prod-delivery.src-stubby-dispatcher) by\n 2002:a05:7022:987:b0:11b:ca88:c4f7\n with SMTP id a92af1059eb24-12172309d60mr2088850c88.40.1766127883124; Thu, 18\n Dec 2025 23:04:43 -0800 (PST)","Date":"Fri, 19 Dec 2025 07:04:16 +0000","In-Reply-To":"<20251219-aspeed-sgpio-v5-0-fd5593178144@google.com>","Mime-Version":"1.0","References":"<20251219-aspeed-sgpio-v5-0-fd5593178144@google.com>","X-Mailer":"b4 0.14.2","Message-ID":"<20251219-aspeed-sgpio-v5-3-fd5593178144@google.com>","Subject":"[PATCH v5 3/6] hw/gpio/aspeed_sgpio: Implement SGPIO interrupt\n handling","From":"Yubin Zou <yubinz@google.com>","To":"qemu-devel@nongnu.org","Cc":"\" =?utf-8?q?C=C3=A9dric_Le_Goater?= \" <clg@kaod.org>,\n Peter Maydell <peter.maydell@linaro.org>,\n  Steven Lee <steven_lee@aspeedtech.com>, Troy Lee <leetroy@gmail.com>,\n  Jamin Lin <jamin_lin@aspeedtech.com>,\n Andrew Jeffery <andrew@codeconstruct.com.au>,  Joel Stanley <joel@jms.id.au>,\n Fabiano Rosas <farosas@suse.de>, Laurent Vivier <lvivier@redhat.com>,\n  Paolo Bonzini <pbonzini@redhat.com>,\n Kane-Chen-AS <kane_chen@aspeedtech.com>,\n  Nabih Estefan <nabihestefan@google.com>, qemu-arm@nongnu.org,\n  Yubin Zou <yubinz@google.com>","Content-Type":"text/plain; charset=\"utf-8\"","Received-SPF":"pass client-ip=2607:f8b0:4864:20::54a;\n envelope-from=3C_lEaQYKCmIYUBINZGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--yubinz.bounces.google.com;\n helo=mail-pg1-x54a.google.com","X-Spam_score_int":"-95","X-Spam_score":"-9.6","X-Spam_bar":"---------","X-Spam_report":"(-9.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-0.001,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001,\n USER_IN_DEF_DKIM_WL=-7.5 autolearn=unavailable autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"},"content":"The SGPIO controller can generate interrupts based on various pin state\nchanges, such as rising/falling edges or high/low levels. This change\nadds the necessary logic to detect these events, update the interrupt\nstatus registers, and signal the interrupt to the SoC.\n\nSigned-off-by: Yubin Zou <yubinz@google.com>\n---\n include/hw/gpio/aspeed_sgpio.h |   2 +\n hw/gpio/aspeed_sgpio.c         | 126 ++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 126 insertions(+), 2 deletions(-)","diff":"diff --git a/include/hw/gpio/aspeed_sgpio.h b/include/hw/gpio/aspeed_sgpio.h\nindex 60279a597c722f94fba406d60cb30a52ef9544bc..8a11a9998c013cb2e4be99690ecd7bcd9dcb5815 100644\n--- a/include/hw/gpio/aspeed_sgpio.h\n+++ b/include/hw/gpio/aspeed_sgpio.h\n@@ -58,7 +58,9 @@ struct AspeedSGPIOState {\n \n     /*< public >*/\n     MemoryRegion iomem;\n+    int pending;\n     qemu_irq irq;\n+    qemu_irq sgpios[ASPEED_SGPIO_MAX_PIN_PAIR];\n     uint32_t ctrl_regs[ASPEED_SGPIO_MAX_PIN_PAIR];\n     uint32_t int_regs[ASPEED_SGPIO_MAX_INT];\n };\ndiff --git a/hw/gpio/aspeed_sgpio.c b/hw/gpio/aspeed_sgpio.c\nindex 927c711cb3aef889c47c9a9156fe4241981c5efa..a058a3edcabd346a048e2b61740a3972a5e5a871 100644\n--- a/hw/gpio/aspeed_sgpio.c\n+++ b/hw/gpio/aspeed_sgpio.c\n@@ -12,9 +12,130 @@\n #include \"qemu/error-report.h\"\n #include \"qapi/error.h\"\n #include \"qapi/visitor.h\"\n+#include \"hw/irq.h\"\n #include \"hw/qdev-properties.h\"\n #include \"hw/gpio/aspeed_sgpio.h\"\n \n+/*\n+ *  For each set of gpios there are three sensitivity registers that control\n+ *  the interrupt trigger mode.\n+ *\n+ *  | 2 | 1 | 0 | trigger mode\n+ *  -----------------------------\n+ *  | 0 | 0 | 0 | falling-edge\n+ *  | 0 | 0 | 1 | rising-edge\n+ *  | 0 | 1 | 0 | level-low\n+ *  | 0 | 1 | 1 | level-high\n+ *  | 1 | X | X | dual-edge\n+ */\n+\n+/* GPIO Interrupt Triggers */\n+#define ASPEED_FALLING_EDGE 0\n+#define ASPEED_RISING_EDGE  1\n+#define ASPEED_LEVEL_LOW    2\n+#define ASPEED_LEVEL_HIGH   3\n+#define ASPEED_DUAL_EDGE    4\n+\n+static void aspeed_clear_irq(AspeedSGPIOState *s, int idx)\n+{\n+    uint32_t reg_index = idx / 32;\n+    uint32_t bit_index = idx % 32;\n+    uint32_t pending = extract32(s->int_regs[reg_index], bit_index, 1);\n+\n+    assert(s->pending >= pending);\n+\n+    /* No change to s->pending if pending is 0 */\n+    s->pending -= pending;\n+\n+    /*\n+     * The write acknowledged the interrupt regardless of whether it\n+     * was pending or not. The post-condition is that it mustn't be\n+     * pending. Unconditionally clear the status bit.\n+     */\n+    s->int_regs[reg_index] = deposit32(s->int_regs[reg_index], bit_index, 1, 0);\n+}\n+\n+static void aspeed_evaluate_irq(AspeedSGPIOState *s, int sgpio_prev_high,\n+                                int sgpio_curr_high, int idx)\n+{\n+    uint32_t ctrl = s->ctrl_regs[idx];\n+    uint32_t falling_edge = 0, rising_edge = 0;\n+    uint32_t int_trigger = SHARED_FIELD_EX32(ctrl, SGPIO_INT_TYPE);\n+    uint32_t int_enabled = SHARED_FIELD_EX32(ctrl, SGPIO_INT_EN);\n+    uint32_t reg_index = idx / 32;\n+    uint32_t bit_index = idx % 32;\n+\n+    if (!int_enabled) {\n+        return;\n+    }\n+\n+    /* Detect edges */\n+    if (sgpio_curr_high && !sgpio_prev_high) {\n+        rising_edge = 1;\n+    } else if (!sgpio_curr_high && sgpio_prev_high) {\n+        falling_edge = 1;\n+    }\n+\n+    if (((int_trigger == ASPEED_FALLING_EDGE)  && falling_edge)   ||\n+        ((int_trigger == ASPEED_RISING_EDGE)  && rising_edge)     ||\n+        ((int_trigger == ASPEED_LEVEL_LOW)  && !sgpio_curr_high)  ||\n+        ((int_trigger == ASPEED_LEVEL_HIGH)  && sgpio_curr_high)  ||\n+        ((int_trigger >= ASPEED_DUAL_EDGE)  && (rising_edge || falling_edge)))\n+    {\n+        s->int_regs[reg_index] = deposit32(s->int_regs[reg_index],\n+                                              bit_index, 1, 1);\n+        /* Trigger the VIC IRQ */\n+        s->pending++;\n+    }\n+}\n+\n+static void aspeed_sgpio_update(AspeedSGPIOState *s, uint32_t idx,\n+                                uint32_t value)\n+{\n+    uint32_t old = s->ctrl_regs[idx];\n+    uint32_t new = value;\n+    uint32_t diff = (old ^ new);\n+    if (diff) {\n+        /* If the interrupt clear bit is set */\n+        if (SHARED_FIELD_EX32(new, SGPIO_INT_STATUS)) {\n+            aspeed_clear_irq(s, idx);\n+            /* Clear the interrupt clear bit */\n+            new &= ~SGPIO_INT_STATUS_MASK;\n+        }\n+\n+        /* Update the control register. */\n+        s->ctrl_regs[idx] = new;\n+\n+        /* If the output value is changed */\n+        if (SHARED_FIELD_EX32(diff, SGPIO_SERIAL_OUT_VAL)) {\n+            /* ...trigger the line-state IRQ */\n+            qemu_set_irq(s->sgpios[idx], 1);\n+        }\n+\n+        /* If the input value is changed */\n+        if (SHARED_FIELD_EX32(diff, SGPIO_SERIAL_IN_VAL)) {\n+            aspeed_evaluate_irq(s,\n+                            SHARED_FIELD_EX32(old, SGPIO_SERIAL_IN_VAL),\n+                            SHARED_FIELD_EX32(new, SGPIO_SERIAL_IN_VAL),\n+                            idx);\n+        }\n+    }\n+    qemu_set_irq(s->irq, !!(s->pending));\n+}\n+\n+static uint64_t aspeed_sgpio_2700_read_int_status_reg(AspeedSGPIOState *s,\n+                                                      uint32_t reg)\n+{\n+    uint32_t idx = reg - R_SGPIO_INT_STATUS_0;\n+    if (idx >= ASPEED_SGPIO_MAX_INT) {\n+        qemu_log_mask(LOG_GUEST_ERROR,\n+                         \"%s: interrupt status index: %d, out of bounds\\n\",\n+                         __func__, idx);\n+        return 0;\n+    }\n+    return s->int_regs[idx];\n+}\n+\n static uint64_t aspeed_sgpio_2700_read_control_reg(AspeedSGPIOState *s,\n                                 uint32_t reg)\n {\n@@ -38,7 +159,7 @@ static void aspeed_sgpio_2700_write_control_reg(AspeedSGPIOState *s,\n                       __func__, idx);\n         return;\n     }\n-    s->ctrl_regs[idx] = data;\n+    aspeed_sgpio_update(s, idx, data);\n }\n \n static uint64_t aspeed_sgpio_2700_read(void *opaque, hwaddr offset,\n@@ -52,6 +173,7 @@ static uint64_t aspeed_sgpio_2700_read(void *opaque, hwaddr offset,\n \n     switch (reg) {\n     case R_SGPIO_INT_STATUS_0 ... R_SGPIO_INT_STATUS_7:\n+        value = aspeed_sgpio_2700_read_int_status_reg(s, reg);\n         break;\n     case R_SGPIO_0_CONTROL ... R_SGPIO_255_CONTROL:\n         value = aspeed_sgpio_2700_read_control_reg(s, reg);\n@@ -116,7 +238,7 @@ static void aspeed_sgpio_set_pin_level(AspeedSGPIOState *s, int pin, bool level)\n     } else {\n         value &= ~bit_mask;\n     }\n-    s->ctrl_regs[pin >> 1] = value;\n+    aspeed_sgpio_update(s, pin >> 1, value);\n }\n \n static void aspeed_sgpio_get_pin(Object *obj, Visitor *v, const char *name,\n","prefixes":["v5","3/6"]}