diff options
author | Andiry Xu <andiry.xu@amd.com> | 2011-12-12 03:45:28 -0500 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2012-03-12 12:31:24 -0400 |
commit | f99298bfa7c42da8d27c2b42050941471c0866ab (patch) | |
tree | 3e41bfc8effe612b9626ea2011e6b37b9bc6b0d5 /drivers/usb/host/xhci.c | |
parent | f7a0d426f3e7ec321b8037238b6426566df36edb (diff) |
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>
Diffstat (limited to 'drivers/usb/host/xhci.c')
-rw-r--r-- | drivers/usb/host/xhci.c | 51 |
1 files changed, 27 insertions, 24 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index a629ad860329..262400c10075 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -3614,26 +3614,38 @@ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000, | |||
3614 | 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000}; | 3614 | 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000}; |
3615 | 3615 | ||
3616 | /* Calculate HIRD/BESL for USB2 PORTPMSC*/ | 3616 | /* Calculate HIRD/BESL for USB2 PORTPMSC*/ |
3617 | static int xhci_calculate_hird_besl(int u2del, bool use_besl) | 3617 | static int xhci_calculate_hird_besl(struct xhci_hcd *xhci, |
3618 | struct usb_device *udev) | ||
3618 | { | 3619 | { |
3619 | int hird; | 3620 | int u2del, besl, besl_host; |
3621 | int besl_device = 0; | ||
3622 | u32 field; | ||
3623 | |||
3624 | u2del = HCS_U2_LATENCY(xhci->hcs_params3); | ||
3625 | field = le32_to_cpu(udev->bos->ext_cap->bmAttributes); | ||
3620 | 3626 | ||
3621 | if (use_besl) { | 3627 | if (field & USB_BESL_SUPPORT) { |
3622 | for (hird = 0; hird < 16; hird++) { | 3628 | for (besl_host = 0; besl_host < 16; besl_host++) { |
3623 | if (xhci_besl_encoding[hird] >= u2del) | 3629 | if (xhci_besl_encoding[besl_host] >= u2del) |
3624 | break; | 3630 | break; |
3625 | } | 3631 | } |
3632 | /* Use baseline BESL value as default */ | ||
3633 | if (field & USB_BESL_BASELINE_VALID) | ||
3634 | besl_device = USB_GET_BESL_BASELINE(field); | ||
3635 | else if (field & USB_BESL_DEEP_VALID) | ||
3636 | besl_device = USB_GET_BESL_DEEP(field); | ||
3626 | } else { | 3637 | } else { |
3627 | if (u2del <= 50) | 3638 | if (u2del <= 50) |
3628 | hird = 0; | 3639 | besl_host = 0; |
3629 | else | 3640 | else |
3630 | hird = (u2del - 51) / 75 + 1; | 3641 | besl_host = (u2del - 51) / 75 + 1; |
3631 | |||
3632 | if (hird > 15) | ||
3633 | hird = 15; | ||
3634 | } | 3642 | } |
3635 | 3643 | ||
3636 | return hird; | 3644 | besl = besl_host + besl_device; |
3645 | if (besl > 15) | ||
3646 | besl = 15; | ||
3647 | |||
3648 | return besl; | ||
3637 | } | 3649 | } |
3638 | 3650 | ||
3639 | static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, | 3651 | 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 | u32 temp, dev_id; | 3658 | u32 temp, dev_id; |
3647 | unsigned int port_num; | 3659 | unsigned int port_num; |
3648 | unsigned long flags; | 3660 | unsigned long flags; |
3649 | int u2del, hird; | 3661 | int hird; |
3650 | int ret; | 3662 | int ret; |
3651 | 3663 | ||
3652 | if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || | 3664 | 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 | * HIRD or BESL shoule be used. See USB2.0 LPM errata. | 3704 | * HIRD or BESL shoule be used. See USB2.0 LPM errata. |
3693 | */ | 3705 | */ |
3694 | pm_addr = port_array[port_num] + 1; | 3706 | pm_addr = port_array[port_num] + 1; |
3695 | u2del = HCS_U2_LATENCY(xhci->hcs_params3); | 3707 | hird = xhci_calculate_hird_besl(xhci, udev); |
3696 | if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2)) | ||
3697 | hird = xhci_calculate_hird_besl(u2del, 1); | ||
3698 | else | ||
3699 | hird = xhci_calculate_hird_besl(u2del, 0); | ||
3700 | |||
3701 | temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); | 3708 | temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); |
3702 | xhci_writel(xhci, temp, pm_addr); | 3709 | xhci_writel(xhci, temp, pm_addr); |
3703 | 3710 | ||
@@ -3776,7 +3783,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, | |||
3776 | u32 temp; | 3783 | u32 temp; |
3777 | unsigned int port_num; | 3784 | unsigned int port_num; |
3778 | unsigned long flags; | 3785 | unsigned long flags; |
3779 | int u2del, hird; | 3786 | int hird; |
3780 | 3787 | ||
3781 | if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support || | 3788 | if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support || |
3782 | !udev->lpm_capable) | 3789 | !udev->lpm_capable) |
@@ -3799,11 +3806,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, | |||
3799 | xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n", | 3806 | xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n", |
3800 | enable ? "enable" : "disable", port_num); | 3807 | enable ? "enable" : "disable", port_num); |
3801 | 3808 | ||
3802 | u2del = HCS_U2_LATENCY(xhci->hcs_params3); | 3809 | hird = xhci_calculate_hird_besl(xhci, udev); |
3803 | if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2)) | ||
3804 | hird = xhci_calculate_hird_besl(u2del, 1); | ||
3805 | else | ||
3806 | hird = xhci_calculate_hird_besl(u2del, 0); | ||
3807 | 3810 | ||
3808 | if (enable) { | 3811 | if (enable) { |
3809 | temp &= ~PORT_HIRD_MASK; | 3812 | temp &= ~PORT_HIRD_MASK; |