mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
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: Andiry Xu <andiry.xu@amd.com> Tested-by: Jason Fan <jcfan@qca.qualcomm.com> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
This commit is contained in:
parent
f7a0d426f3
commit
f99298bfa7
2 changed files with 32 additions and 24 deletions
|
@ -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;
|
||||
|
||||
if (use_besl) {
|
||||
for (hird = 0; hird < 16; hird++) {
|
||||
if (xhci_besl_encoding[hird] >= u2del)
|
||||
u2del = HCS_U2_LATENCY(xhci->hcs_params3);
|
||||
field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
|
||||
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue