git: 20b19982545e - main - usb: support SSP and SSPx2 xHCI

From: ShengYi Hung <aokblast_at_FreeBSD.org>
Date: Mon, 02 Nov 2026 03:02:54 UTC
The branch main has been updated by aokblast:

URL: https://cgit.FreeBSD.org/src/commit/?id=20b19982545eb96160a20d0224f4b074f5fcb9af

commit 20b19982545eb96160a20d0224f4b074f5fcb9af
Author:     ShengYi Hung <aokblast@FreeBSD.org>
AuthorDate: 2025-09-01 14:54:11 +0000
Commit:     ShengYi Hung <aokblast@FreeBSD.org>
CommitDate: 2026-11-02 03:02:11 +0000

    usb: support SSP and SSPx2 xHCI
    
    Only the default PSI IDs are supported, other controllers fall back to
    USB 3.0.  Record the speed IDs the controller has: the root hub BOS
    lists those, and a link without one uses the closest lower ID.
    
    Per xHCI 6.2.2, take the parent hub slot ID and port number of SS and
    SSP devices from the closest higher-rank hub.
    
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D52347
---
 sys/dev/usb/controller/xhci.c    | 305 ++++++++++++++++++++++++++++++++++-----
 sys/dev/usb/controller/xhci.h    |  14 ++
 sys/dev/usb/controller/xhcireg.h |  12 ++
 3 files changed, 294 insertions(+), 37 deletions(-)

diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index acc6eee525b0..3f3ab299647b 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -485,6 +485,60 @@ xhci_reset_controller(struct xhci_softc *sc)
 	return (0);
 }
 
+static bool
+xhci_parse_protocol(struct xhci_softc *sc, uint32_t eecp, uint32_t eec)
+{
+	enum usb_revision rev;
+	uint32_t val;
+	uint16_t psiv;
+	uint8_t minor;
+	uint8_t psic;
+	uint8_t i;
+
+	minor = XHCI_XECP_MINOR(eec);
+	psic = XHCI_XECP_PSIC_GET(XREAD4(sc, capa, eecp + 0x08));
+	psiv = XHCI_PSIV_BIT(XHCI_PS_SPEED_SS);
+	rev = USB_REV_3_0;
+
+	if (psic == 0) {
+		/*
+		 * The port revision only tells which speeds the port may
+		 * have, so be careful about what we claim for the bus.
+		 */
+		if (minor >= 0x10) {
+			psiv |= XHCI_PSIV_BIT(XHCI_PS_SPEED_SS_PLUS_GEN2);
+			rev = USB_REV_3_1;
+		}
+		if (minor >= 0x20) {
+			psiv |= XHCI_PSIV_BIT(XHCI_PS_SPEED_SS_PLUS_GEN1_x2) |
+			    XHCI_PSIV_BIT(XHCI_PS_SPEED_SS_PLUS_GEN2_x2);
+		}
+	}
+
+	for (i = 0; i != psic; i++) {
+		val = XREAD4(sc, capa, eecp + 0x10 + i * 4);
+		val &= ~(XHCI_XECP_PSI_RSVD | XHCI_XECP_PSI_LP);
+		switch (val) {
+		case 0x00050134:	/* 4: 5  Gbps Gen1x1 */
+			break;
+		case 0x000a0135:	/* 5: 10 Gbps Gen2x1 */
+		case 0x000a0136:	/* 6: 10 Gbps Gen1x2 (5G/lane x 2) */
+			rev = MAX(rev, USB_REV_3_1);
+			break;
+		case 0x00140137:	/* 7: 20 Gbps Gen2x2 (10G/lane x 2) */
+			rev = USB_REV_3_2;
+			break;
+		default:
+			return (false);
+		}
+		psiv |= XHCI_PSIV_BIT(XHCI_XECP_PSIV_GET(val));
+	}
+
+	sc->sc_ss_psiv |= psiv;
+	sc->sc_bus.usbrev = MAX(sc->sc_bus.usbrev, rev);
+	return (true);
+}
+
 usb_error_t
 xhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32)
 {
@@ -497,6 +551,7 @@ xhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32)
 
 	/* set the bus revision */
 	sc->sc_bus.usbrev = USB_REV_3_0;
+	sc->sc_ss_psiv = XHCI_PSIV_BIT(XHCI_PS_SPEED_SS);
 
 	/* set up the bus struct */
 	sc->sc_bus.methods = &xhci_bus_methods;
@@ -642,6 +697,7 @@ xhci_get_xecp(struct xhci_softc *sc)
 	uint32_t eec;
 	uint32_t eecp;
 	bool first = true;
+	bool default_psi = true;
 
 	hccp1 = XREAD4(sc, capa, XHCI_HCCPARAMS1);
 
@@ -686,6 +742,9 @@ xhci_get_xecp(struct xhci_softc *sc)
 				break;
 			case XHCI_ID_PROTOCOLS:
 				printf("PROTO");
+				if (XHCI_XECP_MAJOR(eec) == 0x03 &&
+				    !xhci_parse_protocol(sc, eecp, eec))
+					default_psi = false;
 				break;
 			case XHCI_ID_POWER_MGMT:
 				printf("POWER");
@@ -714,6 +773,13 @@ xhci_get_xecp(struct xhci_softc *sc)
 		first = false;
 	}
 	printf(">\n");
+
+	if (!default_psi) {
+		device_printf(sc->sc_bus.parent,
+		    "xECP: not support non-default mapping, fallback to usb 3.0\n");
+		sc->sc_bus.usbrev = USB_REV_3_0;
+		sc->sc_ss_psiv = XHCI_PSIV_BIT(XHCI_PS_SPEED_SS);
+	}
 }
 
 static void
@@ -2531,6 +2597,9 @@ xhci_configure_endpoint(struct usb_device *udev,
 
 		switch (udev->speed) {
 		case USB_SPEED_SUPER:
+		case USB_SPEED_SUPER_PLUS:
+		case USB_SPEED_SUPER_PLUS_X2:
+		case USB_SPEED_SUPER_PLUS_GEN2_X2:
 			if (mult > 3)
 				mult = 3;
 			temp |= XHCI_EPCTX_0_MULT_SET(mult - 1);
@@ -2650,6 +2719,67 @@ xhci_configure_endpoint_by_xfer(struct usb_xfer *xfer)
 	    xfer->max_frame_size, xfer->endpoint->ep_mode));
 }
 
+static uint8_t
+xhci_ss_psiv(struct xhci_softc *sc, enum usb_dev_speed speed)
+{
+	switch (speed) {
+	case USB_SPEED_SUPER_PLUS_GEN2_X2:
+		if (sc->sc_ss_psiv &
+		    XHCI_PSIV_BIT(XHCI_PS_SPEED_SS_PLUS_GEN2_x2))
+			return (XHCI_PS_SPEED_SS_PLUS_GEN2_x2);
+		/* FALLTHROUGH */
+	case USB_SPEED_SUPER_PLUS:
+		if (sc->sc_ss_psiv & XHCI_PSIV_BIT(XHCI_PS_SPEED_SS_PLUS_GEN2))
+			return (XHCI_PS_SPEED_SS_PLUS_GEN2);
+		/* FALLTHROUGH */
+	case USB_SPEED_SUPER_PLUS_X2:
+		if (sc->sc_ss_psiv &
+		    XHCI_PSIV_BIT(XHCI_PS_SPEED_SS_PLUS_GEN1_x2))
+			return (XHCI_PS_SPEED_SS_PLUS_GEN1_x2);
+		/* FALLTHROUGH */
+	default:
+		return (XHCI_PS_SPEED_SS);
+	}
+}
+
+static enum usb_dev_speed
+xhci_ss_highest(struct xhci_softc *sc)
+{
+	switch (xhci_ss_psiv(sc, USB_SPEED_SUPER_PLUS_GEN2_X2)) {
+	case XHCI_PS_SPEED_SS_PLUS_GEN2_x2:
+		return (USB_SPEED_SUPER_PLUS_GEN2_X2);
+	case XHCI_PS_SPEED_SS_PLUS_GEN2:
+		return (USB_SPEED_SUPER_PLUS);
+	case XHCI_PS_SPEED_SS_PLUS_GEN1_x2:
+		return (USB_SPEED_SUPER_PLUS_X2);
+	default:
+		return (USB_SPEED_SUPER);
+	}
+}
+
+static struct usb_device *
+xhci_ss_parent_hub(struct xhci_softc *sc, struct usb_device *udev,
+    uint8_t *port_no)
+{
+	struct usb_device *adev = udev;
+	struct usb_device *hubdev = udev->parent_hub;
+
+	if (udev->speed >= xhci_ss_highest(sc))
+		return (NULL);
+
+	for (; hubdev != NULL && hubdev->parent_hub != NULL;
+	    hubdev = hubdev->parent_hub) {
+		if (hubdev->hub->ports[adev->port_index].ss_speed_unknown)
+			return (NULL);
+		if (hubdev->speed > udev->speed) {
+			*port_no = adev->port_no;
+			return (hubdev);
+		}
+		adev = hubdev;
+	}
+	return (NULL);
+}
+
 static usb_error_t
 xhci_configure_device(struct usb_device *udev)
 {
@@ -2664,6 +2794,7 @@ xhci_configure_device(struct usb_device *udev)
 	uint8_t is_hub;
 	uint8_t index;
 	uint8_t depth;
+	uint8_t port_no;
 
 	index = udev->controller_slot_id;
 
@@ -2737,13 +2868,12 @@ xhci_configure_device(struct usb_device *udev)
 		}
 		break;
 	default:
-		temp |= XHCI_SCTX_0_SPEED_SET(4);
+		temp |= XHCI_SCTX_0_SPEED_SET(xhci_ss_psiv(sc, udev->speed));
 		break;
 	}
 
 	is_hub = sc->sc_hw.devs[index].nports != 0 &&
-	    (udev->speed == USB_SPEED_SUPER ||
-	    udev->speed == USB_SPEED_HIGH);
+	    (udev->speed >= USB_SPEED_HIGH);
 
 	if (is_hub)
 		temp |= XHCI_SCTX_0_HUB_SET(1);
@@ -2779,6 +2909,23 @@ xhci_configure_device(struct usb_device *udev)
 			    udev->hs_port_no);
 		}
 		break;
+	case USB_SPEED_SUPER:
+	case USB_SPEED_SUPER_PLUS:
+	case USB_SPEED_SUPER_PLUS_X2:
+	case USB_SPEED_SUPER_PLUS_GEN2_X2:
+		/*
+		 * Per xHCI 1.2 ยง6.2.2 the parent hub slot ID and port number
+		 * of a SS/SSP device identify the hub which isolates it, that
+		 * is the closest higher rank hub. They must be zero if there
+		 * is none. The root hub has no slot and never qualifies.
+		 */
+		hubdev = xhci_ss_parent_hub(sc, udev, &port_no);
+		if (hubdev != NULL) {
+			temp |= XHCI_SCTX_2_TT_HUB_SID_SET(
+			    hubdev->controller_slot_id);
+			temp |= XHCI_SCTX_2_TT_PORT_NUM_SET(port_no);
+		}
+		break;
 	default:
 		break;
 	}
@@ -3277,39 +3424,95 @@ struct usb_device_descriptor xhci_devd =
 	.bNumConfigurations = 1,		/* # of configurations */
 };
 
+/* The capabilities every root HUB BOS descriptor starts with */
+#define	XHCI_BOSD_COMMON(desc, ncaps)					\
+	.bosd = {							\
+		.bLength = sizeof(desc.bosd),				\
+		.bDescriptorType = UDESC_BOS,				\
+		HSETW(.wTotalLength, sizeof(desc)),			\
+		.bNumDeviceCaps = (ncaps),				\
+	},								\
+	.usb2extd = {							\
+		.bLength = sizeof(desc.usb2extd),			\
+		.bDescriptorType = UDESC_DEVICE_CAPABILITY,		\
+		.bDevCapabilityType = 2,				\
+		.bmAttributes[0] = 2,					\
+	},								\
+	.usbdcd = {							\
+		.bLength = sizeof(desc.usbdcd),				\
+		.bDescriptorType = UDESC_DEVICE_CAPABILITY,		\
+		.bDevCapabilityType = 3,				\
+		.bmAttributes = 0, /* XXX */				\
+		HSETW(.wSpeedsSupported, 0x000C),			\
+		.bFunctionalitySupport = 8,				\
+		.bU1DevExitLat = 255,	/* dummy - not used */		\
+		.wU2DevExitLat = { 0x00, 0x08 },			\
+	},								\
+	.cidd = {							\
+		.bLength = sizeof(desc.cidd),				\
+		.bDescriptorType = UDESC_DEVICE_CAPABILITY,		\
+		.bDevCapabilityType = 4,				\
+		.bReserved = 0,						\
+		.bContainerID = 0, /* XXX */				\
+	}
+
 static const
-struct xhci_bos_desc xhci_bosd = {
-	.bosd = {
-		.bLength = sizeof(xhci_bosd.bosd),
-		.bDescriptorType = UDESC_BOS,
-		HSETW(.wTotalLength, sizeof(xhci_bosd)),
-		.bNumDeviceCaps = 3,
-	},
-	.usb2extd = {
-		.bLength = sizeof(xhci_bosd.usb2extd),
-		.bDescriptorType = 1,
-		.bDevCapabilityType = 2,
-		.bmAttributes[0] = 2,
-	},
-	.usbdcd = {
-		.bLength = sizeof(xhci_bosd.usbdcd),
+struct xhci_bos_desc xhci_30_bosd = {
+	XHCI_BOSD_COMMON(xhci_30_bosd, 3),
+};
+
+static const
+struct xhci_ssp_bos_desc xhci_ssp_bosd = {
+	XHCI_BOSD_COMMON(xhci_ssp_bosd, 4),
+	.ssplus = {
 		.bDescriptorType = UDESC_DEVICE_CAPABILITY,
-		.bDevCapabilityType = 3,
-		.bmAttributes = 0, /* XXX */
-		HSETW(.wSpeedsSupported, 0x000C),
-		.bFunctionalitySupport = 8,
-		.bU1DevExitLat = 255,	/* dummy - not used */
-		.wU2DevExitLat = { 0x00, 0x08 },
-	},
-	.cidd = {
-		.bLength = sizeof(xhci_bosd.cidd),
-		.bDescriptorType = 1,
-		.bDevCapabilityType = 4,
+		.bDevCapabilityType = USB_DEVCAP_SUPERSPEED_PLUS,
 		.bReserved = 0,
-		.bContainerID = 0, /* XXX */
+		.wFunctionalitySupport = {0x04, 0x11}, /* SSID 4, Rx: 1, Tx: 1 */
+		.wReserved = {0},
+	},
+	.caps = {
+		/* The speed is per lane */
+		[0] = {0x34, 0x00, 0x05, 0x00}, /* 4: 5   Gbps Gen1x1, Rx */
+		[1] = {0xb4, 0x00, 0x05, 0x00}, /* 4: 5   Gbps Gen1x1, Tx */
+		[2] = {0x35, 0x40, 0x0a, 0x00}, /* 5: 10  Gbps Gen2x1, Rx */
+		[3] = {0xb5, 0x40, 0x0a, 0x00}, /* 5: 10  Gbps Gen2x1, Tx */
+		[4] = {0x36, 0x40, 0x05, 0x00}, /* 6: 5   Gbps Gen1x2, Rx */
+		[5] = {0xb6, 0x40, 0x05, 0x00}, /* 6: 5   Gbps Gen1x2, Tx */
+		[6] = {0x37, 0x40, 0x0a, 0x00}, /* 7: 10  Gbps Gen2x2, Rx */
+		[7] = {0xb7, 0x40, 0x0a, 0x00}, /* 7: 10  Gbps Gen2x2, Tx */
 	},
 };
 
+static uint16_t
+xhci_ssp_bos_build(struct xhci_softc *sc)
+{
+	struct xhci_ssp_bos_desc *bos = &sc->sc_hub_desc.ssp_bos;
+	uint16_t len;
+	uint8_t i;
+	uint8_t n;
+
+	*bos = xhci_ssp_bosd;
+
+	for (i = n = 0; i != nitems(bos->caps); i += 2) {
+		if ((sc->sc_ss_psiv & XHCI_PSIV_BIT(USB_DEVCAP_SSPLUS_SSID_GET(
+		    UGETDW(xhci_ssp_bosd.caps[i])))) == 0)
+			continue;
+		memcpy(bos->caps[n], xhci_ssp_bosd.caps[i],
+		    2 * sizeof(bos->caps[0]));
+		n += 2;
+	}
+
+	len = offsetof(struct xhci_ssp_bos_desc, caps) +
+	    n * sizeof(bos->caps[0]);
+	USETW(bos->bosd.wTotalLength, len);
+	bos->ssplus.bLength = sizeof(bos->ssplus) + n * sizeof(bos->caps[0]);
+	USETDW(bos->ssplus.bmAttributes, USB_DEVCAP_SSPLUS_SSAC_SET(n - 1) |
+	    USB_DEVCAP_SSPLUS_SSIC_SET((n / 2) - 1));
+
+	return (len);
+}
+
 static const
 struct xhci_config_desc xhci_confd = {
 	.confd = {
@@ -3404,8 +3607,18 @@ xhci_roothub_exec(struct usb_device *udev,
 				err = USB_ERR_IOERROR;
 				goto done;
 			}
+			sc->sc_hub_desc.devd = xhci_devd;
+			switch (sc->sc_bus.usbrev) {
+			case USB_REV_3_2:
+				USETW(sc->sc_hub_desc.devd.bcdUSB, 0x0320);
+				break;
+			case USB_REV_3_1:
+				USETW(sc->sc_hub_desc.devd.bcdUSB, 0x0310);
+				break;
+			default:
+				break;
+			}
 			len = sizeof(xhci_devd);
-			ptr = (const void *)&xhci_devd;
 			break;
 
 		case UDESC_BOS:
@@ -3413,8 +3626,12 @@ xhci_roothub_exec(struct usb_device *udev,
 				err = USB_ERR_IOERROR;
 				goto done;
 			}
-			len = sizeof(xhci_bosd);
-			ptr = (const void *)&xhci_bosd;
+			if (sc->sc_bus.usbrev < USB_REV_3_1) {
+				len = sizeof(xhci_30_bosd);
+				ptr = (const void *)&xhci_30_bosd;
+			} else {
+				len = xhci_ssp_bos_build(sc);
+			}
 			break;
 
 		case UDESC_CONFIG:
@@ -3609,8 +3826,9 @@ xhci_roothub_exec(struct usb_device *udev,
 	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
 		DPRINTFN(9, "UR_GET_STATUS i=%d\n", index);
 
-		if ((index < 1) ||
-		    (index > sc->sc_noport)) {
+		if ((index < 1) || (index > sc->sc_noport) ||
+		    (value != 0 && value != 2) ||
+		    (value == 2 && sc->sc_bus.usbrev < USB_REV_3_1)) {
 			err = USB_ERR_IOERROR;
 			goto done;
 		}
@@ -3650,6 +3868,18 @@ xhci_roothub_exec(struct usb_device *udev,
 #endif
 		USETW(sc->sc_hub_desc.ps.wPortStatus, i);
 
+		if (value == 2) {
+			/*
+			 * Only the default mapping gets here, where the speed
+			 * ID tells the lane count, which is zero based.
+			 */
+			i = XHCI_PS_SPEED_GET(v);
+			j = (i == XHCI_PS_SPEED_SS_PLUS_GEN1_x2 ||
+			    i == XHCI_PS_SPEED_SS_PLUS_GEN2_x2) ? 1 : 0;
+			USETDW(sc->sc_hub_desc.ext_ps.dwExtPortStatus,
+			    i | (i << 4) | (j << 8) | (j << 12));
+		}
+
 		i = 0;
 		if (v & XHCI_PS_CSC)
 			i |= UPS_C_CONNECT_STATUS;
@@ -3667,7 +3897,8 @@ xhci_roothub_exec(struct usb_device *udev,
 			i |= UPS_C_PORT_CONFIG_ERROR;
 
 		USETW(sc->sc_hub_desc.ps.wPortChange, i);
-		len = sizeof(sc->sc_hub_desc.ps);
+		len = (value == 2) ? sizeof(sc->sc_hub_desc.ext_ps) :
+		    sizeof(sc->sc_hub_desc.ps);
 		break;
 
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
@@ -4441,7 +4672,7 @@ xhci_device_state_change(struct usb_device *udev)
 	DPRINTF("\n");
 
 	if (usb_get_device_state(udev) == USB_STATE_CONFIGURED) {
-		err = uhub_query_info(udev, &sc->sc_hw.devs[index].nports, 
+		err = uhub_query_info(udev, &sc->sc_hw.devs[index].nports,
 		    &sc->sc_hw.devs[index].tt);
 		if (err != 0)
 			sc->sc_hw.devs[index].nports = 0;
diff --git a/sys/dev/usb/controller/xhci.h b/sys/dev/usb/controller/xhci.h
index c2e6cde8ad77..9a84243eb8f5 100644
--- a/sys/dev/usb/controller/xhci.h
+++ b/sys/dev/usb/controller/xhci.h
@@ -478,10 +478,22 @@ struct xhci_bos_desc {
 	struct usb_devcap_container_id_descriptor cidd;
 } __packed;
 
+struct xhci_ssp_bos_desc {
+	struct usb_bos_descriptor		bosd;
+	struct usb_devcap_usb2ext_descriptor	usb2extd;
+	struct usb_devcap_ss_descriptor		usbdcd;
+	struct usb_devcap_container_id_descriptor cidd;
+	struct usb_devcap_ss_plus_descriptor_header ssplus;
+	uDWord caps[8];
+} __packed;
+
 union xhci_hub_desc {
 	struct usb_status		stat;
 	struct usb_port_status		ps;
 	struct usb_hub_ss_descriptor	hubd;
+	struct usb_ext_status		ext_ps;
+	struct usb_device_descriptor	devd;
+	struct xhci_ssp_bos_desc	ssp_bos;
 	uint8_t				temp[128];
 };
 
@@ -548,6 +560,8 @@ struct xhci_softc {
 	uint8_t			sc_command_ccs;
 	/* number of XHCI device slots */
 	uint8_t			sc_noslot;
+	/* Enhanced SuperSpeed speed IDs of the controller, see XHCI_PSIV_BIT */
+	uint16_t		sc_ss_psiv;
 	/* number of ports on root HUB */
 	uint8_t			sc_noport;
 	/* root HUB device configuration */
diff --git a/sys/dev/usb/controller/xhcireg.h b/sys/dev/usb/controller/xhcireg.h
index c4f62586a0d0..ac6c7393ab49 100644
--- a/sys/dev/usb/controller/xhcireg.h
+++ b/sys/dev/usb/controller/xhcireg.h
@@ -127,6 +127,9 @@
 #define	XHCI_PS_SPEED_LOW	0x2			/* Low Speed USB */
 #define	XHCI_PS_SPEED_HIGH	0x3			/* High Speed USB */
 #define	XHCI_PS_SPEED_SS	0x4			/* Super Speed USB */
+#define	XHCI_PS_SPEED_SS_PLUS_GEN2	0x5			/* Super Speed Plus Gen2x1 */
+#define	XHCI_PS_SPEED_SS_PLUS_GEN1_x2	0x6			/* Super Speed Plus Gen1x2 */
+#define	XHCI_PS_SPEED_SS_PLUS_GEN2_x2	0x7			/* Super Speed Plus Gen2x2 */
 #define	XHCI_PS_PIC_GET(x)	(((x) >> 14) & 0x3)	/* RW - port indicator */
 #define	XHCI_PS_PIC_SET(x)	(((x) & 0x3) << 14)	/* RW - port indicator */
 #define	XHCI_PS_LWS		0x00010000	/* RW - port link state write strobe */
@@ -195,9 +198,18 @@
 /* XHCI legacy support */
 #define	XHCI_XECP_ID(x)		((x) & 0xFF)
 #define	XHCI_XECP_NEXT(x)	(((x) >> 8) & 0xFF)
+#define	XHCI_XECP_MAJOR(x)	(((x) >> 24) & 0xFF)
+#define	XHCI_XECP_MINOR(x)	(((x) >> 16) & 0xFF)
 #define	XHCI_XECP_BIOS_SEM	0x0002
 #define	XHCI_XECP_OS_SEM	0x0003
 
+/* Support protocol */
+#define XHCI_XECP_PSIC_GET(x)   (((x) >> 28) & 0x0F)
+#define XHCI_XECP_PSI_RSVD	0x00003E00
+#define XHCI_XECP_PSI_LP	0x0000C000
+#define XHCI_XECP_PSIV_GET(x)	((x) & 0x0F)
+#define XHCI_PSIV_BIT(x)	(1U << (x))
+
 /* XHCI capability ID's */
 #define	XHCI_ID_USB_LEGACY	0x0001
 #define	XHCI_ID_PROTOCOLS	0x0002