15448bc2aSJonas Dreßler /* 25448bc2aSJonas Dreßler * NXP Wireless LAN device driver: PCIE and platform specific quirks 35448bc2aSJonas Dreßler * 45448bc2aSJonas Dreßler * This software file (the "File") is distributed by NXP 55448bc2aSJonas Dreßler * under the terms of the GNU General Public License Version 2, June 1991 65448bc2aSJonas Dreßler * (the "License"). You may use, redistribute and/or modify this File in 75448bc2aSJonas Dreßler * accordance with the terms and conditions of the License, a copy of which 85448bc2aSJonas Dreßler * is available by writing to the Free Software Foundation, Inc., 95448bc2aSJonas Dreßler * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 105448bc2aSJonas Dreßler * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 115448bc2aSJonas Dreßler * 125448bc2aSJonas Dreßler * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 135448bc2aSJonas Dreßler * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 145448bc2aSJonas Dreßler * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 155448bc2aSJonas Dreßler * this warranty disclaimer. 165448bc2aSJonas Dreßler */ 175448bc2aSJonas Dreßler 185448bc2aSJonas Dreßler #include <linux/dmi.h> 195448bc2aSJonas Dreßler 205448bc2aSJonas Dreßler #include "pcie_quirks.h" 215448bc2aSJonas Dreßler 225448bc2aSJonas Dreßler /* quirk table based on DMI matching */ 235448bc2aSJonas Dreßler static const struct dmi_system_id mwifiex_quirk_table[] = { 24*a847666aSTsuchiya Yuto { 25*a847666aSTsuchiya Yuto .ident = "Surface Pro 4", 26*a847666aSTsuchiya Yuto .matches = { 27*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 28*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), 29*a847666aSTsuchiya Yuto }, 30*a847666aSTsuchiya Yuto .driver_data = (void *)QUIRK_FW_RST_D3COLD, 31*a847666aSTsuchiya Yuto }, 32*a847666aSTsuchiya Yuto { 33*a847666aSTsuchiya Yuto .ident = "Surface Pro 5", 34*a847666aSTsuchiya Yuto .matches = { 35*a847666aSTsuchiya Yuto /* match for SKU here due to generic product name "Surface Pro" */ 36*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 37*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), 38*a847666aSTsuchiya Yuto }, 39*a847666aSTsuchiya Yuto .driver_data = (void *)QUIRK_FW_RST_D3COLD, 40*a847666aSTsuchiya Yuto }, 41*a847666aSTsuchiya Yuto { 42*a847666aSTsuchiya Yuto .ident = "Surface Pro 5 (LTE)", 43*a847666aSTsuchiya Yuto .matches = { 44*a847666aSTsuchiya Yuto /* match for SKU here due to generic product name "Surface Pro" */ 45*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 46*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), 47*a847666aSTsuchiya Yuto }, 48*a847666aSTsuchiya Yuto .driver_data = (void *)QUIRK_FW_RST_D3COLD, 49*a847666aSTsuchiya Yuto }, 50*a847666aSTsuchiya Yuto { 51*a847666aSTsuchiya Yuto .ident = "Surface Pro 6", 52*a847666aSTsuchiya Yuto .matches = { 53*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 54*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), 55*a847666aSTsuchiya Yuto }, 56*a847666aSTsuchiya Yuto .driver_data = (void *)QUIRK_FW_RST_D3COLD, 57*a847666aSTsuchiya Yuto }, 58*a847666aSTsuchiya Yuto { 59*a847666aSTsuchiya Yuto .ident = "Surface Book 1", 60*a847666aSTsuchiya Yuto .matches = { 61*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 62*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), 63*a847666aSTsuchiya Yuto }, 64*a847666aSTsuchiya Yuto .driver_data = (void *)QUIRK_FW_RST_D3COLD, 65*a847666aSTsuchiya Yuto }, 66*a847666aSTsuchiya Yuto { 67*a847666aSTsuchiya Yuto .ident = "Surface Book 2", 68*a847666aSTsuchiya Yuto .matches = { 69*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 70*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), 71*a847666aSTsuchiya Yuto }, 72*a847666aSTsuchiya Yuto .driver_data = (void *)QUIRK_FW_RST_D3COLD, 73*a847666aSTsuchiya Yuto }, 74*a847666aSTsuchiya Yuto { 75*a847666aSTsuchiya Yuto .ident = "Surface Laptop 1", 76*a847666aSTsuchiya Yuto .matches = { 77*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 78*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), 79*a847666aSTsuchiya Yuto }, 80*a847666aSTsuchiya Yuto .driver_data = (void *)QUIRK_FW_RST_D3COLD, 81*a847666aSTsuchiya Yuto }, 82*a847666aSTsuchiya Yuto { 83*a847666aSTsuchiya Yuto .ident = "Surface Laptop 2", 84*a847666aSTsuchiya Yuto .matches = { 85*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 86*a847666aSTsuchiya Yuto DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), 87*a847666aSTsuchiya Yuto }, 88*a847666aSTsuchiya Yuto .driver_data = (void *)QUIRK_FW_RST_D3COLD, 89*a847666aSTsuchiya Yuto }, 905448bc2aSJonas Dreßler {} 915448bc2aSJonas Dreßler }; 925448bc2aSJonas Dreßler 935448bc2aSJonas Dreßler void mwifiex_initialize_quirks(struct pcie_service_card *card) 945448bc2aSJonas Dreßler { 955448bc2aSJonas Dreßler struct pci_dev *pdev = card->dev; 965448bc2aSJonas Dreßler const struct dmi_system_id *dmi_id; 975448bc2aSJonas Dreßler 985448bc2aSJonas Dreßler dmi_id = dmi_first_match(mwifiex_quirk_table); 995448bc2aSJonas Dreßler if (dmi_id) 1005448bc2aSJonas Dreßler card->quirks = (uintptr_t)dmi_id->driver_data; 1015448bc2aSJonas Dreßler 1025448bc2aSJonas Dreßler if (!card->quirks) 1035448bc2aSJonas Dreßler dev_info(&pdev->dev, "no quirks enabled\n"); 104*a847666aSTsuchiya Yuto if (card->quirks & QUIRK_FW_RST_D3COLD) 105*a847666aSTsuchiya Yuto dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); 106*a847666aSTsuchiya Yuto } 107*a847666aSTsuchiya Yuto 108*a847666aSTsuchiya Yuto static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) 109*a847666aSTsuchiya Yuto { 110*a847666aSTsuchiya Yuto dev_info(&pdev->dev, "putting into D3cold...\n"); 111*a847666aSTsuchiya Yuto 112*a847666aSTsuchiya Yuto pci_save_state(pdev); 113*a847666aSTsuchiya Yuto if (pci_is_enabled(pdev)) 114*a847666aSTsuchiya Yuto pci_disable_device(pdev); 115*a847666aSTsuchiya Yuto pci_set_power_state(pdev, PCI_D3cold); 116*a847666aSTsuchiya Yuto } 117*a847666aSTsuchiya Yuto 118*a847666aSTsuchiya Yuto static int mwifiex_pcie_set_power_d0(struct pci_dev *pdev) 119*a847666aSTsuchiya Yuto { 120*a847666aSTsuchiya Yuto int ret; 121*a847666aSTsuchiya Yuto 122*a847666aSTsuchiya Yuto dev_info(&pdev->dev, "putting into D0...\n"); 123*a847666aSTsuchiya Yuto 124*a847666aSTsuchiya Yuto pci_set_power_state(pdev, PCI_D0); 125*a847666aSTsuchiya Yuto ret = pci_enable_device(pdev); 126*a847666aSTsuchiya Yuto if (ret) { 127*a847666aSTsuchiya Yuto dev_err(&pdev->dev, "pci_enable_device failed\n"); 128*a847666aSTsuchiya Yuto return ret; 129*a847666aSTsuchiya Yuto } 130*a847666aSTsuchiya Yuto pci_restore_state(pdev); 131*a847666aSTsuchiya Yuto 132*a847666aSTsuchiya Yuto return 0; 133*a847666aSTsuchiya Yuto } 134*a847666aSTsuchiya Yuto 135*a847666aSTsuchiya Yuto int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev) 136*a847666aSTsuchiya Yuto { 137*a847666aSTsuchiya Yuto struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); 138*a847666aSTsuchiya Yuto int ret; 139*a847666aSTsuchiya Yuto 140*a847666aSTsuchiya Yuto /* Power-cycle (put into D3cold then D0) */ 141*a847666aSTsuchiya Yuto dev_info(&pdev->dev, "Using reset_d3cold quirk to perform FW reset\n"); 142*a847666aSTsuchiya Yuto 143*a847666aSTsuchiya Yuto /* We need to perform power-cycle also for bridge of wifi because 144*a847666aSTsuchiya Yuto * on some devices (e.g. Surface Book 1), the OS for some reasons 145*a847666aSTsuchiya Yuto * can't know the real power state of the bridge. 146*a847666aSTsuchiya Yuto * When tried to power-cycle only wifi, the reset failed with the 147*a847666aSTsuchiya Yuto * following dmesg log: 148*a847666aSTsuchiya Yuto * "Cannot transition to power state D0 for parent in D3hot". 149*a847666aSTsuchiya Yuto */ 150*a847666aSTsuchiya Yuto mwifiex_pcie_set_power_d3cold(pdev); 151*a847666aSTsuchiya Yuto mwifiex_pcie_set_power_d3cold(parent_pdev); 152*a847666aSTsuchiya Yuto 153*a847666aSTsuchiya Yuto ret = mwifiex_pcie_set_power_d0(parent_pdev); 154*a847666aSTsuchiya Yuto if (ret) 155*a847666aSTsuchiya Yuto return ret; 156*a847666aSTsuchiya Yuto ret = mwifiex_pcie_set_power_d0(pdev); 157*a847666aSTsuchiya Yuto if (ret) 158*a847666aSTsuchiya Yuto return ret; 159*a847666aSTsuchiya Yuto 160*a847666aSTsuchiya Yuto return 0; 1615448bc2aSJonas Dreßler } 162