Improve suspend/resume support. Power off the associated power domain
authorkettenis <kettenis@openbsd.org>
Sun, 23 Jul 2023 11:49:17 +0000 (11:49 +0000)
committerkettenis <kettenis@openbsd.org>
Sun, 23 Jul 2023 11:49:17 +0000 (11:49 +0000)
during suspend and re-initialize the "dwc3" specific registers upon
resume.

ok patrick@

sys/dev/fdt/xhci_fdt.c

index 3c172bc..41ed4b6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: xhci_fdt.c,v 1.23 2023/04/03 01:55:00 dlg Exp $       */
+/*     $OpenBSD: xhci_fdt.c,v 1.24 2023/07/23 11:49:17 kettenis Exp $  */
 /*
  * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
  *
@@ -56,13 +56,15 @@ struct xhci_fdt_softc {
 
 int    xhci_fdt_match(struct device *, void *, void *);
 void   xhci_fdt_attach(struct device *, struct device *, void *);
+int    xhci_fdt_activate(struct device *, int);
 
 const struct cfattach xhci_fdt_ca = {
        sizeof(struct xhci_fdt_softc), xhci_fdt_match, xhci_fdt_attach, NULL,
-       xhci_activate
+       xhci_fdt_activate
 };
 
-int    xhci_cdns_init(struct xhci_fdt_softc *);
+int    xhci_cdns_attach(struct xhci_fdt_softc *);
+int    xhci_snps_attach(struct xhci_fdt_softc *);
 int    xhci_snps_init(struct xhci_fdt_softc *);
 void   xhci_init_phys(struct xhci_fdt_softc *);
 
@@ -139,9 +141,9 @@ xhci_fdt_attach(struct device *parent, struct device *self, void *aux)
         * functionality.
         */
        if (OF_is_compatible(sc->sc_node, "cdns,usb3"))
-               error = xhci_cdns_init(sc);
+               error = xhci_cdns_attach(sc);
        if (OF_is_compatible(sc->sc_node, "snps,dwc3"))
-               error = xhci_snps_init(sc);
+               error = xhci_snps_attach(sc);
        if (error) {
                printf(": can't initialize hardware\n");
                goto disestablish_ret;
@@ -170,6 +172,31 @@ unmap:
        bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
 }
 
+int
+xhci_fdt_activate(struct device *self, int act)
+{
+       struct xhci_fdt_softc *sc = (struct xhci_fdt_softc *)self;
+       int rv = 0;
+
+       switch (act) {
+       case DVACT_POWERDOWN:
+               rv = xhci_activate(self, act);
+               power_domain_disable(sc->sc_node);
+               break;
+       case DVACT_RESUME:
+               power_domain_enable(sc->sc_node);
+               if (OF_is_compatible(sc->sc_node, "snps,dwc3"))
+                       xhci_snps_init(sc);
+               rv = xhci_activate(self, act);
+               break;
+       default:
+               rv = xhci_activate(self, act);
+               break;
+       }
+
+       return rv;
+}
+
 /*
  * Cadence USB3 controller.
  */
@@ -183,7 +210,7 @@ unmap:
 #define  OTG_STS_XHCI_READY    (1 << 26)
 
 int
-xhci_cdns_init(struct xhci_fdt_softc *sc)
+xhci_cdns_attach(struct xhci_fdt_softc *sc)
 {
        uint32_t did, sts;
        int timo;
@@ -252,27 +279,33 @@ xhci_snps_ep_get_cookie(void *cookie, struct endpoint *ep)
 }
 
 int
-xhci_snps_init(struct xhci_fdt_softc *sc)
+xhci_snps_attach(struct xhci_fdt_softc *sc)
 {
-       char phy_type[16] = { 0 };
-       int node = sc->sc_node;
-       uint32_t reg;
-
        /*
         * On Apple hardware we need to reset the controller when we
         * see a new connection.
         */
-       if (OF_is_compatible(node, "apple,dwc3")) {
+       if (OF_is_compatible(sc->sc_node, "apple,dwc3")) {
                sc->sc_usb_controller_port.up_cookie = sc;
                sc->sc_usb_controller_port.up_connect = xhci_snps_connect;
                task_set(&sc->sc_snps_connect_task, xhci_snps_do_connect, sc);
 
-               sc->sc_ports.dp_node = node;
+               sc->sc_ports.dp_node = sc->sc_node;
                sc->sc_ports.dp_cookie = &sc->sc_usb_controller_port;
                sc->sc_ports.dp_ep_get_cookie = xhci_snps_ep_get_cookie;
                device_ports_register(&sc->sc_ports, EP_USB_CONTROLLER_PORT);
        }
 
+       return xhci_snps_init(sc);
+}
+
+int
+xhci_snps_init(struct xhci_fdt_softc *sc)
+{
+       char phy_type[16] = { 0 };
+       int node = sc->sc_node;
+       uint32_t reg;
+
        /* We don't support device mode, so always force host mode. */
        reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USB3_GCTL);
        reg &= ~USB3_GCTL_PRTCAPDIR_MASK;