Commit 8023eff1 authored by Kai-Chuan Hsieh's avatar Kai-Chuan Hsieh Committed by Darren Hart

platform/x86: asus-wmi: Set specified XUSB2PR value for X550LB

The bluetooth adapter Atheros AR3012 can't be enumerated
and make the bluetooth function broken.

T:  Bus=02 Lev=01 Prnt=01 Port=05 Cnt=02 Dev#=  5 Spd=12  MxCh= 0
D:  Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=13d3 ProdID=3362 Rev=00.02
S:  Manufacturer=Atheros Communications
S:  Product=Bluetooth USB Host Controller
S:  SerialNumber=Alaska Day 2006
C:  #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
I:  If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
I:  If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb

The error is:

 usb 2-6: device not accepting address 7, error -62
 usb usb2-port6: unable to enumerate USB device

It is caused by adapter's connected port is mapped to xHC
controller, but the xHCI is not supported by the usb device.

The output of 'sudo lspci -nnxxx -s 00:14.0':

 00:14.0 USB controller [0c03]: Intel Corporation 8 Series USB xHCI HC [8086:9c31] (rev 04)
 00: 86 80 31 9c 06 04 90 02 04 30 03 0c 00 00 00 00
 10: 04 00 a0 f7 00 00 00 00 00 00 00 00 00 00 00 00
 20: 00 00 00 00 00 00 00 00 00 00 00 00 43 10 1f 20
 30: 00 00 00 00 70 00 00 00 00 00 00 00 0b 01 00 00
 40: fd 01 36 80 89 c6 0f 80 00 00 00 00 00 00 00 00
 50: 5f 2e ce 0f 00 00 00 00 00 00 00 00 00 00 00 00
 60: 30 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 70: 01 80 c2 c1 08 00 00 00 00 00 00 00 00 00 00 00
 80: 05 00 87 00 0c a0 e0 fe 00 00 00 00 a1 41 00 00
 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 a0: 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00
 b0: 0f 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00
 c0: 03 c0 30 00 00 00 00 00 03 0c 00 00 00 00 00 00
 d0: f9 01 00 00 f9 01 00 00 0f 00 00 00 0f 00 00 00
 e0: 00 08 00 00 00 00 00 00 00 00 00 00 d8 d8 00 00
 f0: 00 00 00 00 00 00 00 00 b1 0f 04 08 00 00 00 00

By referencing Intel Platform Controller Hub(PCH) datasheet,
the xHC USB 2.0 Port Routing(XUSB2PR) at offset 0xD0-0xD3h
decides the setting of mapping the port to EHCI controller or
xHC controller. And the port mapped to xHC will enable xHCI
during bus resume.

The setting of disabling bluetooth adapter's connected port is
0x000001D9. The value can be obtained by few times 1 bit flip
operation. The suited configuration should have the 'lsusb -t'
result with bluetooth using ehci:

/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/9p, 480M
    |__ Port 5: Dev 2, If 0, Class=Video, Driver=uvcvideo, 480M
    |__ Port 5: Dev 2, If 1, Class=Video, Driver=uvcvideo, 480M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
        |__ Port 6: Dev 3, If 0, Class=Wireless, Driver=btusb, 12M
        |__ Port 6: Dev 3, If 1, Class=Wireless, Driver=btusb, 12M
Signed-off-by: default avatarKai-Chuan Hsieh <kai.chiuan@gmail.com>
Acked-by: default avatarCorentin Chary <corentin.chary@gmail.com>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
[andy: resolve merge conflict in asus-wmi.h]
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
parent b4aca383
...@@ -116,6 +116,10 @@ static struct quirk_entry quirk_asus_ux303ub = { ...@@ -116,6 +116,10 @@ static struct quirk_entry quirk_asus_ux303ub = {
.wmi_backlight_native = true, .wmi_backlight_native = true,
}; };
static struct quirk_entry quirk_asus_x550lb = {
.xusb2pr = 0x01D9,
};
static int dmi_matched(const struct dmi_system_id *dmi) static int dmi_matched(const struct dmi_system_id *dmi)
{ {
quirks = dmi->driver_data; quirks = dmi->driver_data;
...@@ -398,6 +402,15 @@ static const struct dmi_system_id asus_quirks[] = { ...@@ -398,6 +402,15 @@ static const struct dmi_system_id asus_quirks[] = {
}, },
.driver_data = &quirk_asus_ux303ub, .driver_data = &quirk_asus_ux303ub,
}, },
{
.callback = dmi_matched,
.ident = "ASUSTeK COMPUTER INC. X550LB",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"),
},
.driver_data = &quirk_asus_x550lb,
},
{}, {},
}; };
......
...@@ -156,6 +156,9 @@ MODULE_LICENSE("GPL"); ...@@ -156,6 +156,9 @@ MODULE_LICENSE("GPL");
#define ASUS_FAN_CTRL_MANUAL 1 #define ASUS_FAN_CTRL_MANUAL 1
#define ASUS_FAN_CTRL_AUTO 2 #define ASUS_FAN_CTRL_AUTO 2
#define USB_INTEL_XUSB2PR 0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
struct bios_args { struct bios_args {
u32 arg0; u32 arg0;
u32 arg1; u32 arg1;
...@@ -1080,6 +1083,29 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus) ...@@ -1080,6 +1083,29 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
return result; return result;
} }
static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
{
struct pci_dev *xhci_pdev;
u32 orig_ports_available;
u32 ports_available = asus->driver->quirks->xusb2pr;
xhci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI,
NULL);
if (!xhci_pdev)
return;
pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
&orig_ports_available);
pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
cpu_to_le32(ports_available));
pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n",
orig_ports_available, ports_available);
}
/* /*
* Hwmon device * Hwmon device
*/ */
...@@ -2087,6 +2113,9 @@ static int asus_wmi_add(struct platform_device *pdev) ...@@ -2087,6 +2113,9 @@ static int asus_wmi_add(struct platform_device *pdev)
if (asus->driver->quirks->wmi_backlight_native) if (asus->driver->quirks->wmi_backlight_native)
acpi_video_set_dmi_backlight_type(acpi_backlight_native); acpi_video_set_dmi_backlight_type(acpi_backlight_native);
if (asus->driver->quirks->xusb2pr)
asus_wmi_set_xusb2pr(asus);
if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
err = asus_wmi_backlight_init(asus); err = asus_wmi_backlight_init(asus);
if (err && err != -ENODEV) if (err && err != -ENODEV)
......
...@@ -53,6 +53,7 @@ struct quirk_entry { ...@@ -53,6 +53,7 @@ struct quirk_entry {
* and let the ACPI interrupt to send out the key event. * and let the ACPI interrupt to send out the key event.
*/ */
int no_display_toggle; int no_display_toggle;
u32 xusb2pr;
bool (*i8042_filter)(unsigned char data, unsigned char str, bool (*i8042_filter)(unsigned char data, unsigned char str,
struct serio *serio); struct serio *serio);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment