> Date: Wed, 15 Sep 2021 17:29:39 +0200 (CEST)
> From: Mark Kettenis <[email protected]>
>
> 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.
This diff is now in snapshots, so instead of applying the diff and
build your own kernel, you can just upgrade to the latest snapshot.
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);
> + }
> + }
> + }
> }
>
>