git: 16d92e92ca12 - main - amdgpio: Suspend routine

From: Aymeric Wibo <obiwac_at_FreeBSD.org>
Date: Fri, 09 Oct 2026 22:07:29 UTC
The branch main has been updated by obiwac:

URL: https://cgit.FreeBSD.org/src/commit/?id=16d92e92ca12c9772d921346c34f1ef87998c662

commit 16d92e92ca12c9772d921346c34f1ef87998c662
Author:     Aymeric Wibo <obiwac@FreeBSD.org>
AuthorDate: 2026-02-25 09:28:20 +0000
Commit:     Aymeric Wibo <obiwac@FreeBSD.org>
CommitDate: 2026-10-09 22:07:02 +0000

    amdgpio: Suspend routine
    
    Mask all interrupts when suspending and warn when there are unserviced
    interrupts which might block entry to S0i3.
    
    In the future we won't want to mask wake interrupts.
    
    Once we can actually make use of GPIO interrupts on x86, we'll also want
    to unmask relevant pins when resuming.
    
    Reviewed by:    aokblast, avg
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D51589
---
 sys/dev/amdgpio/amdgpio.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/sys/dev/amdgpio/amdgpio.c b/sys/dev/amdgpio/amdgpio.c
index 20589ff71b0b..5cfddfaa338e 100644
--- a/sys/dev/amdgpio/amdgpio.c
+++ b/sys/dev/amdgpio/amdgpio.c
@@ -536,11 +536,59 @@ amdgpio_detach(device_t dev)
 	return (0);
 }
 
+static int
+amdgpio_suspend(device_t dev)
+{
+	struct amdgpio_softc *sc = device_get_softc(dev);
+	uint32_t reg;
+	size_t i;
+	int pin, off;
+
+	AMDGPIO_LOCK(sc);
+
+	for (i = 0; i < AMD_GPIO_PINS_EXPOSED; i++) {
+		pin = kernzp_pins[i].pin_num;
+		off = AMDGPIO_PIN_REGISTER(pin);
+
+		reg = amdgpio_read_4(sc, off);
+		if ((reg & UNSERVICED_INTERRUPT_MASK) != 0)
+			device_printf(dev, "unserviced interrupt on pin %d!\n",
+			    pin);
+		/*
+		 * "Service" interrupt and mask.  In the future we should only
+		 * mask non-wake interrupts (see WAKE_CNTRL_OFF_S0I3 &c).
+		 *
+		 * (From BKDG) write 1 to interrupt & wake status registers to
+		 * clear them.  We can do this by just writing back to them.
+		 */
+		reg &= ~(1 << INTERRUPT_MASK_OFF);
+		reg &= ~(1 << INTERRUPT_ENABLE_OFF);
+		amdgpio_write_4(sc, off, reg);
+	}
+
+	amdgpio_eoi_locked(sc);
+	AMDGPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+amdgpio_resume(device_t dev)
+{
+	/*
+	 * XXX Will have to resume properly once we're actually able to use
+	 * amdgpio for interrupts.
+	 */
+	return (0);
+}
+
 static device_method_t amdgpio_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe, amdgpio_probe),
 	DEVMETHOD(device_attach, amdgpio_attach),
 	DEVMETHOD(device_detach, amdgpio_detach),
+	DEVMETHOD(device_suspend, amdgpio_suspend),
+	DEVMETHOD(device_resume, amdgpio_resume),
 
 	/* GPIO protocol */
 	DEVMETHOD(gpio_get_bus, amdgpio_get_bus),