提交 f99298bf 编写于 作者: A Andiry Xu 提交者: Sarah Sharp

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: NAndiry Xu <andiry.xu@amd.com>
Tested-by: NJason Fan <jcfan@qca.qualcomm.com>
Signed-off-by: NSarah Sharp <sarah.a.sharp@linux.intel.com>
上级 f7a0d426
...@@ -3614,26 +3614,38 @@ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000, ...@@ -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}; 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};
/* Calculate HIRD/BESL for USB2 PORTPMSC*/ /* 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) { if (field & USB_BESL_SUPPORT) {
for (hird = 0; hird < 16; hird++) { for (besl_host = 0; besl_host < 16; besl_host++) {
if (xhci_besl_encoding[hird] >= u2del) if (xhci_besl_encoding[besl_host] >= u2del)
break; 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 { } else {
if (u2del <= 50) if (u2del <= 50)
hird = 0; besl_host = 0;
else else
hird = (u2del - 51) / 75 + 1; besl_host = (u2del - 51) / 75 + 1;
if (hird > 15)
hird = 15;
} }
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, 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, ...@@ -3646,7 +3658,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
u32 temp, dev_id; u32 temp, dev_id;
unsigned int port_num; unsigned int port_num;
unsigned long flags; unsigned long flags;
int u2del, hird; int hird;
int ret; int ret;
if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
...@@ -3692,12 +3704,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, ...@@ -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. * HIRD or BESL shoule be used. See USB2.0 LPM errata.
*/ */
pm_addr = port_array[port_num] + 1; pm_addr = port_array[port_num] + 1;
u2del = HCS_U2_LATENCY(xhci->hcs_params3); hird = xhci_calculate_hird_besl(xhci, udev);
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);
temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
xhci_writel(xhci, temp, pm_addr); xhci_writel(xhci, temp, pm_addr);
...@@ -3776,7 +3783,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, ...@@ -3776,7 +3783,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
u32 temp; u32 temp;
unsigned int port_num; unsigned int port_num;
unsigned long flags; unsigned long flags;
int u2del, hird; int hird;
if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support || if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
!udev->lpm_capable) !udev->lpm_capable)
...@@ -3799,11 +3806,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, ...@@ -3799,11 +3806,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n", xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
enable ? "enable" : "disable", port_num); enable ? "enable" : "disable", port_num);
u2del = HCS_U2_LATENCY(xhci->hcs_params3); hird = xhci_calculate_hird_besl(xhci, udev);
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);
if (enable) { if (enable) {
temp &= ~PORT_HIRD_MASK; temp &= ~PORT_HIRD_MASK;
......
...@@ -789,6 +789,11 @@ struct usb_ext_cap_descriptor { /* Link Power Management */ ...@@ -789,6 +789,11 @@ struct usb_ext_cap_descriptor { /* Link Power Management */
__u8 bDevCapabilityType; __u8 bDevCapabilityType;
__le32 bmAttributes; __le32 bmAttributes;
#define USB_LPM_SUPPORT (1 << 1) /* supports LPM */ #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)); } __attribute__((packed));
#define USB_DT_USB_EXT_CAP_SIZE 7 #define USB_DT_USB_EXT_CAP_SIZE 7
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册