Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f99298bf authored by Andiry Xu's avatar Andiry Xu Committed by Sarah Sharp
Browse files

xHCI: BESL calculation based on USB2.0 LPM errata



The latest released errata for USB2.0 ECN LPM adds new fields to USB2.0
extension descriptor, defines two BESL values for device: baseline BESL
and deep BESL. Baseline BESL value communicates a nominal power savings
design point and the deep BESL value communicates a significant power
savings design point.

If device indicates BESL value, driver will use a value count in both
host BESL and device BESL. Use baseline BESL value as default.

Signed-off-by: default avatarAndiry Xu <andiry.xu@amd.com>
Tested-by: default avatarJason Fan <jcfan@qca.qualcomm.com>
Signed-off-by: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
parent f7a0d426
Loading
Loading
Loading
Loading
+27 −24
Original line number Diff line number Diff line
@@ -3614,26 +3614,38 @@ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
	3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};

/* Calculate HIRD/BESL for USB2 PORTPMSC*/
static int xhci_calculate_hird_besl(int u2del, bool use_besl)
static int xhci_calculate_hird_besl(struct xhci_hcd *xhci,
					struct usb_device *udev)
{
	int hird;
	int u2del, besl, besl_host;
	int besl_device = 0;
	u32 field;

	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
	field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);

	if (use_besl) {
		for (hird = 0; hird < 16; hird++) {
			if (xhci_besl_encoding[hird] >= u2del)
	if (field & USB_BESL_SUPPORT) {
		for (besl_host = 0; besl_host < 16; besl_host++) {
			if (xhci_besl_encoding[besl_host] >= u2del)
				break;
		}
		/* Use baseline BESL value as default */
		if (field & USB_BESL_BASELINE_VALID)
			besl_device = USB_GET_BESL_BASELINE(field);
		else if (field & USB_BESL_DEEP_VALID)
			besl_device = USB_GET_BESL_DEEP(field);
	} else {
		if (u2del <= 50)
			hird = 0;
			besl_host = 0;
		else
			hird = (u2del - 51) / 75 + 1;

		if (hird > 15)
			hird = 15;
			besl_host = (u2del - 51) / 75 + 1;
	}

	return hird;
	besl = besl_host + besl_device;
	if (besl > 15)
		besl = 15;

	return besl;
}

static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
@@ -3646,7 +3658,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
	u32		temp, dev_id;
	unsigned int	port_num;
	unsigned long	flags;
	int		u2del, hird;
	int		hird;
	int		ret;

	if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
@@ -3692,12 +3704,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
	 * HIRD or BESL shoule be used. See USB2.0 LPM errata.
	 */
	pm_addr = port_array[port_num] + 1;
	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
	if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
		hird = xhci_calculate_hird_besl(u2del, 1);
	else
		hird = xhci_calculate_hird_besl(u2del, 0);

	hird = xhci_calculate_hird_besl(xhci, udev);
	temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
	xhci_writel(xhci, temp, pm_addr);

@@ -3776,7 +3783,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
	u32		temp;
	unsigned int	port_num;
	unsigned long	flags;
	int		u2del, hird;
	int		hird;

	if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
			!udev->lpm_capable)
@@ -3799,11 +3806,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
	xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
			enable ? "enable" : "disable", port_num);

	u2del = HCS_U2_LATENCY(xhci->hcs_params3);
	if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
		hird = xhci_calculate_hird_besl(u2del, 1);
	else
		hird = xhci_calculate_hird_besl(u2del, 0);
	hird = xhci_calculate_hird_besl(xhci, udev);

	if (enable) {
		temp &= ~PORT_HIRD_MASK;
+5 −0
Original line number Diff line number Diff line
@@ -789,6 +789,11 @@ struct usb_ext_cap_descriptor { /* Link Power Management */
	__u8  bDevCapabilityType;
	__le32 bmAttributes;
#define USB_LPM_SUPPORT			(1 << 1)	/* supports LPM */
#define USB_BESL_SUPPORT		(1 << 2)	/* supports BESL */
#define USB_BESL_BASELINE_VALID		(1 << 3)	/* Baseline BESL valid*/
#define USB_BESL_DEEP_VALID		(1 << 4)	/* Deep BESL valid */
#define USB_GET_BESL_BASELINE(p)	(((p) & (0xf << 8)) >> 8)
#define USB_GET_BESL_DEEP(p)		(((p) & (0xf << 12)) >> 12)
} __attribute__((packed));

#define USB_DT_USB_EXT_CAP_SIZE	7