diff options
Diffstat (limited to 'drivers/net/wwan/t7xx/t7xx_pci.c')
-rw-r--r-- | drivers/net/wwan/t7xx/t7xx_pci.c | 138 |
1 files changed, 113 insertions, 25 deletions
diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c index e0b1e7a616ca..8bf63f2dcbbf 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.c +++ b/drivers/net/wwan/t7xx/t7xx_pci.c @@ -32,7 +32,6 @@ #include <linux/pci.h> #include <linux/pm.h> #include <linux/pm_runtime.h> -#include <linux/pm_wakeup.h> #include <linux/spinlock.h> #include "t7xx_mhccif.h" @@ -41,6 +40,9 @@ #include "t7xx_pcie_mac.h" #include "t7xx_reg.h" #include "t7xx_state_monitor.h" +#include "t7xx_port_proxy.h" + +#define DRIVER_NAME "mtk_t7xx" #define T7XX_PCI_IREG_BASE 0 #define T7XX_PCI_EREG_BASE 2 @@ -48,7 +50,7 @@ #define T7XX_INIT_TIMEOUT 20 #define PM_SLEEP_DIS_TIMEOUT_MS 20 #define PM_ACK_TIMEOUT_MS 1500 -#define PM_AUTOSUSPEND_MS 20000 +#define PM_AUTOSUSPEND_MS 5000 #define PM_RESOURCE_POLL_TIMEOUT_US 10000 #define PM_RESOURCE_POLL_STEP_US 100 @@ -69,6 +71,7 @@ static ssize_t t7xx_mode_store(struct device *dev, { struct t7xx_pci_dev *t7xx_dev; struct pci_dev *pdev; + enum t7xx_mode mode; int index = 0; pdev = to_pci_dev(dev); @@ -76,12 +79,22 @@ static ssize_t t7xx_mode_store(struct device *dev, if (!t7xx_dev) return -ENODEV; + mode = READ_ONCE(t7xx_dev->mode); + index = sysfs_match_string(t7xx_mode_names, buf); + if (index == mode) + return -EBUSY; + if (index == T7XX_FASTBOOT_SWITCHING) { + if (mode == T7XX_FASTBOOT_DOWNLOAD) + return count; + WRITE_ONCE(t7xx_dev->mode, T7XX_FASTBOOT_SWITCHING); + pm_runtime_resume(dev); + t7xx_reset_device(t7xx_dev, FASTBOOT); } else if (index == T7XX_RESET) { - WRITE_ONCE(t7xx_dev->mode, T7XX_RESET); - t7xx_acpi_pldr_func(t7xx_dev); + pm_runtime_resume(dev); + t7xx_reset_device(t7xx_dev, PLDR); } return count; @@ -109,13 +122,58 @@ static ssize_t t7xx_mode_show(struct device *dev, static DEVICE_ATTR_RW(t7xx_mode); -static struct attribute *t7xx_mode_attr[] = { +static ssize_t t7xx_debug_ports_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct t7xx_pci_dev *t7xx_dev; + struct pci_dev *pdev; + bool show; + int ret; + + pdev = to_pci_dev(dev); + t7xx_dev = pci_get_drvdata(pdev); + if (!t7xx_dev) + return -ENODEV; + + ret = kstrtobool(buf, &show); + if (ret < 0) + return ret; + + t7xx_proxy_debug_ports_show(t7xx_dev, show); + WRITE_ONCE(t7xx_dev->debug_ports_show, show); + + return count; +}; + +static ssize_t t7xx_debug_ports_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct t7xx_pci_dev *t7xx_dev; + struct pci_dev *pdev; + bool show; + + pdev = to_pci_dev(dev); + t7xx_dev = pci_get_drvdata(pdev); + if (!t7xx_dev) + return -ENODEV; + + show = READ_ONCE(t7xx_dev->debug_ports_show); + + return sysfs_emit(buf, "%d\n", show); +} + +static DEVICE_ATTR_RW(t7xx_debug_ports); + +static struct attribute *t7xx_attr[] = { &dev_attr_t7xx_mode.attr, + &dev_attr_t7xx_debug_ports.attr, NULL }; -static const struct attribute_group t7xx_mode_attribute_group = { - .attrs = t7xx_mode_attr, +static const struct attribute_group t7xx_attribute_group = { + .attrs = t7xx_attr, }; void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode) @@ -446,7 +504,7 @@ static int t7xx_pcie_reinit(struct t7xx_pci_dev *t7xx_dev, bool is_d3) if (is_d3) { t7xx_mhccif_init(t7xx_dev); - return t7xx_pci_pm_reinit(t7xx_dev); + t7xx_pci_pm_reinit(t7xx_dev); } return 0; @@ -481,6 +539,33 @@ static int t7xx_send_fsm_command(struct t7xx_pci_dev *t7xx_dev, u32 event) return ret; } +int t7xx_pci_reprobe_early(struct t7xx_pci_dev *t7xx_dev) +{ + enum t7xx_mode mode = READ_ONCE(t7xx_dev->mode); + int ret; + + if (mode == T7XX_FASTBOOT_DOWNLOAD) + pm_runtime_put_noidle(&t7xx_dev->pdev->dev); + + ret = t7xx_send_fsm_command(t7xx_dev, FSM_CMD_STOP); + if (ret) + return ret; + + return 0; +} + +int t7xx_pci_reprobe(struct t7xx_pci_dev *t7xx_dev, bool boot) +{ + int ret; + + ret = t7xx_pcie_reinit(t7xx_dev, boot); + if (ret) + return ret; + + t7xx_clear_rgu_irq(t7xx_dev); + return t7xx_send_fsm_command(t7xx_dev, FSM_CMD_START); +} + static int __t7xx_pci_pm_resume(struct pci_dev *pdev, bool state_check) { struct t7xx_pci_dev *t7xx_dev; @@ -507,16 +592,11 @@ static int __t7xx_pci_pm_resume(struct pci_dev *pdev, bool state_check) if (prev_state == PM_RESUME_REG_STATE_L3 || (prev_state == PM_RESUME_REG_STATE_INIT && atr_reg_val == ATR_SRC_ADDR_INVALID)) { - ret = t7xx_send_fsm_command(t7xx_dev, FSM_CMD_STOP); + ret = t7xx_pci_reprobe_early(t7xx_dev); if (ret) return ret; - ret = t7xx_pcie_reinit(t7xx_dev, true); - if (ret) - return ret; - - t7xx_clear_rgu_irq(t7xx_dev); - return t7xx_send_fsm_command(t7xx_dev, FSM_CMD_START); + return t7xx_pci_reprobe(t7xx_dev, true); } if (prev_state == PM_RESUME_REG_STATE_EXP || @@ -754,6 +834,7 @@ static void t7xx_pci_infracfg_ao_calc(struct t7xx_pci_dev *t7xx_dev) static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct t7xx_pci_dev *t7xx_dev; + void __iomem *iomem; int ret; t7xx_dev = devm_kzalloc(&pdev->dev, sizeof(*t7xx_dev), GFP_KERNEL); @@ -769,12 +850,21 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); - ret = pcim_iomap_regions(pdev, BIT(T7XX_PCI_IREG_BASE) | BIT(T7XX_PCI_EREG_BASE), - pci_name(pdev)); + iomem = pcim_iomap_region(pdev, T7XX_PCI_IREG_BASE, DRIVER_NAME); + ret = PTR_ERR_OR_ZERO(iomem); if (ret) { - dev_err(&pdev->dev, "Could not request BARs: %d\n", ret); + dev_err(&pdev->dev, "Could not request IREG BAR: %d\n", ret); return -ENOMEM; } + IREG_BASE(t7xx_dev) = iomem; + + iomem = pcim_iomap_region(pdev, T7XX_PCI_EREG_BASE, DRIVER_NAME); + ret = PTR_ERR_OR_ZERO(iomem); + if (ret) { + dev_err(&pdev->dev, "Could not request EREG BAR: %d\n", ret); + return -ENOMEM; + } + t7xx_dev->base_addr.pcie_ext_reg_base = iomem; ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); if (ret) { @@ -788,9 +878,6 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } - IREG_BASE(t7xx_dev) = pcim_iomap_table(pdev)[T7XX_PCI_IREG_BASE]; - t7xx_dev->base_addr.pcie_ext_reg_base = pcim_iomap_table(pdev)[T7XX_PCI_EREG_BASE]; - ret = t7xx_pci_pm_init(t7xx_dev); if (ret) return ret; @@ -806,7 +893,7 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) t7xx_pcie_mac_interrupts_dis(t7xx_dev); ret = sysfs_create_group(&t7xx_dev->pdev->dev.kobj, - &t7xx_mode_attribute_group); + &t7xx_attribute_group); if (ret) goto err_md_exit; @@ -822,7 +909,7 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_remove_group: sysfs_remove_group(&t7xx_dev->pdev->dev.kobj, - &t7xx_mode_attribute_group); + &t7xx_attribute_group); err_md_exit: t7xx_md_exit(t7xx_dev); @@ -837,7 +924,7 @@ static void t7xx_pci_remove(struct pci_dev *pdev) t7xx_dev = pci_get_drvdata(pdev); sysfs_remove_group(&t7xx_dev->pdev->dev.kobj, - &t7xx_mode_attribute_group); + &t7xx_attribute_group); t7xx_md_exit(t7xx_dev); for (i = 0; i < EXT_INT_NUM; i++) { @@ -852,12 +939,13 @@ static void t7xx_pci_remove(struct pci_dev *pdev) static const struct pci_device_id t7xx_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x4d75) }, + { PCI_DEVICE(0x14c0, 0x4d75) }, // Dell DW5933e { } }; MODULE_DEVICE_TABLE(pci, t7xx_pci_table); static struct pci_driver t7xx_pci_driver = { - .name = "mtk_t7xx", + .name = DRIVER_NAME, .id_table = t7xx_pci_table, .probe = t7xx_pci_probe, .remove = t7xx_pci_remove, |