The diff below is a preliminary diff to fix a suspend/resume issue on
recent Thinkpads.  This needs testing on a wider range of laptops to
make sure it doesn't break things.  The diff also puts some
information in dmesg that will help me improve things in the future.

So, if you have a laptop where pchgpio(4) attaches *and* supports S3
suspen/resume, please apply this diff, do a suspend/resume cycle and
send me a dmesg collected after that suspend/resume cycle.

Thanks,

Mark


Index: dev/acpi/pchgpio.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/pchgpio.c,v
retrieving revision 1.5
diff -u -p -r1.5 pchgpio.c
--- dev/acpi/pchgpio.c  30 Aug 2021 18:40:19 -0000      1.5
+++ dev/acpi/pchgpio.c  15 Sep 2021 15:16:52 -0000
@@ -28,12 +28,13 @@
 
 #define PCHGPIO_MAXCOM         4
 
-#define PCHGPIO_CONF_TXSTATE   0x00000001
-#define PCHGPIO_CONF_RXSTATE   0x00000002
-#define PCHGPIO_CONF_RXINV     0x00800000
-#define PCHGPIO_CONF_RXEV_EDGE 0x02000000
-#define PCHGPIO_CONF_RXEV_ZERO 0x04000000
-#define PCHGPIO_CONF_RXEV_MASK 0x06000000
+#define PCHGPIO_CONF_TXSTATE           0x00000001
+#define PCHGPIO_CONF_RXSTATE           0x00000002
+#define PCHGPIO_CONF_RXINV             0x00800000
+#define PCHGPIO_CONF_RXEV_EDGE         0x02000000
+#define PCHGPIO_CONF_RXEV_ZERO         0x04000000
+#define PCHGPIO_CONF_RXEV_MASK         0x06000000
+#define PCHGPIO_CONF_PADRSTCFG_MASK    0xc0000000
 
 #define PCHGPIO_PADBAR         0x00c
 
@@ -59,6 +60,11 @@ struct pchgpio_match {
        const struct pchgpio_device *device;
 };
 
+struct pchgpio_pincfg {
+       uint32_t        pad_cfg_dw0;
+       uint32_t        pad_cfg_dw1;
+};
+
 struct pchgpio_intrhand {
        int (*ih_func)(void *);
        void *ih_arg;
@@ -80,6 +86,7 @@ struct pchgpio_softc {
        int sc_padsize;
 
        int sc_npins;
+       struct pchgpio_pincfg *sc_pin_cfg;
        struct pchgpio_intrhand *sc_pin_ih;
 
        struct acpi_gpio sc_gpio;
@@ -87,9 +94,11 @@ struct pchgpio_softc {
 
 int    pchgpio_match(struct device *, void *, void *);
 void   pchgpio_attach(struct device *, struct device *, void *);
+int    pchgpio_activate(struct device *, int);
 
 struct cfattach pchgpio_ca = {
-       sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach
+       sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach,
+       NULL, pchgpio_activate
 };
 
 struct cfdriver pchgpio_cd = {
@@ -170,6 +179,8 @@ int pchgpio_read_pin(void *, int);
 void   pchgpio_write_pin(void *, int, int);
 void   pchgpio_intr_establish(void *, int, int, int (*)(void *), void *);
 int    pchgpio_intr(void *);
+void   pchgpio_save(struct pchgpio_softc *);
+void   pchgpio_restore(struct pchgpio_softc *);
 
 int
 pchgpio_match(struct device *parent, void *match, void *aux)
@@ -240,6 +251,8 @@ pchgpio_attach(struct device *parent, st
 
        sc->sc_padsize = sc->sc_device->pad_size;
        sc->sc_npins = sc->sc_device->npins;
+       sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg),
+           M_DEVBUF, M_WAITOK);
        sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih),
            M_DEVBUF, M_WAITOK | M_ZERO);
 
@@ -263,11 +276,48 @@ pchgpio_attach(struct device *parent, st
 
 unmap:
        free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih));
+       free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg));
        for (i = 0; i < sc->sc_naddr; i++)
                bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i],
                    aaa->aaa_size[i]);
 }
 
+int
+pchgpio_activate(struct device *self, int act)
+{
+       struct pchgpio_softc *sc = (struct pchgpio_softc *)self;
+//     int i, j;
+
+       switch (act) {
+       case DVACT_SUSPEND:
+               printf("%s: suspend\n", sc->sc_dev.dv_xname);
+#if 0
+               for (i = 0; i < 4; i++) {
+                       for (j = 0; j < 0xc00; j += 4) {
+                               printf("%04x: 0x%08x\n", j,
+                                   bus_space_read_4(sc->sc_memt[i], 
sc->sc_memh[i], j));
+                       }
+               }
+#endif
+               pchgpio_save(sc);
+               break;
+       case DVACT_RESUME:
+               printf("%s: resume\n", sc->sc_dev.dv_xname);
+#if 0
+               for (i = 0; i < 4; i++) {
+                       for (j = 0; j < 0xc00; j += 4) {
+                               printf("%04x: 0x%08x\n", j,
+                                   bus_space_read_4(sc->sc_memt[i], 
sc->sc_memh[i], j));
+                       }
+               }
+#endif
+               pchgpio_restore(sc);
+               break;
+       }
+
+       return 0;
+}
+
 const struct pchgpio_group *
 pchgpio_find_group(struct pchgpio_softc *sc, int pin)
 {
@@ -403,4 +453,74 @@ pchgpio_intr(void *arg)
        }
 
        return handled;
+}
+
+void
+pchgpio_save(struct pchgpio_softc *sc)
+{
+       int gpiobase, group, bit, pin, pad;
+       uint16_t base, limit;
+       uint8_t bank, bar;
+
+       for (group = 0; group < sc->sc_device->ngroups; group++) {
+               bar = sc->sc_device->groups[group].bar;
+               bank = sc->sc_device->groups[group].bank;
+               base = sc->sc_device->groups[group].base;
+               limit = sc->sc_device->groups[group].limit;
+               gpiobase = sc->sc_device->groups[group].gpiobase;
+
+               for (bit = 0; bit <= (limit - base); bit++) {
+                       pin = gpiobase + bit;
+                       pad = base + bit - sc->sc_padbase[bar];
+
+                       sc->sc_pin_cfg[pin].pad_cfg_dw0 =
+                           bus_space_read_4(sc->sc_memt[bar],
+                               sc->sc_memh[bar],
+                               sc->sc_padbar[bar] + pad * sc->sc_padsize);
+                       sc->sc_pin_cfg[pin].pad_cfg_dw1 =
+                           bus_space_read_4(sc->sc_memt[bar],
+                               sc->sc_memh[bar],
+                               sc->sc_padbar[bar] + pad * sc->sc_padsize + 4);
+               }
+       }
+}
+
+void
+pchgpio_restore(struct pchgpio_softc *sc)
+{
+       int gpiobase, group, bit, pin, pad;
+       uint32_t pad_cfg_dw0, pad_cfg_dw1;
+       uint16_t base, limit;
+       uint8_t bank, bar;
+
+       for (group = 0; group < sc->sc_device->ngroups; group++) {
+               bar = sc->sc_device->groups[group].bar;
+               bank = sc->sc_device->groups[group].bank;
+               base = sc->sc_device->groups[group].base;
+               limit = sc->sc_device->groups[group].limit;
+               gpiobase = sc->sc_device->groups[group].gpiobase;
+
+               for (bit = 0; bit <= (limit - base); bit++) {
+                       pin = gpiobase + bit;
+                       pad = base + bit - sc->sc_padbase[bar];
+
+                       pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar],
+                           sc->sc_memh[bar], sc->sc_padbar[bar] + pad * 
sc->sc_padsize);
+                       pad_cfg_dw1 = bus_space_read_4(sc->sc_memt[bar],
+                           sc->sc_memh[bar], sc->sc_padbar[bar] + pad * 
sc->sc_padsize + 4);
+                       if (pad_cfg_dw0 != sc->sc_pin_cfg[pin].pad_cfg_dw0)
+                               printf("bar %d bank %d bit %d pad %d: dw0 
0x%08x -> 0x%08x\n", bar, bank, bit, pad, sc->sc_pin_cfg[pin].pad_cfg_dw0, 
pad_cfg_dw0);
+                       if (pad_cfg_dw1 != sc->sc_pin_cfg[pin].pad_cfg_dw1)
+                               printf("bar %d bank %d bit %d pad %d: dw1 
0x%08x -> 0x%08x\n", bar, bank, bit, pad, sc->sc_pin_cfg[pin].pad_cfg_dw1, 
pad_cfg_dw1);
+
+                       /* XXX */
+                       if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & 
PCHGPIO_CONF_PADRSTCFG_MASK) !=
+                           (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK)) {
+                               bus_space_write_4(sc->sc_memt[bar],
+                                   sc->sc_memh[bar],
+                                   sc->sc_padbar[bar] + pad * sc->sc_padsize,
+                                   sc->sc_pin_cfg[pin].pad_cfg_dw0);
+                       }
+               }
+       }
 }

Reply via email to