diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2022-05-24 16:42:24 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2022-05-24 16:42:24 -0500 |
commit | 39348d2eb2f5b4ffe47b708240ed243d05c563c4 (patch) | |
tree | f3f97dc3a0c8714e93d2d4ac0a8463e92577d8aa /drivers/pci | |
parent | 086ab94321f48b4b7d37d12c78e6e1274f082eb7 (diff) | |
parent | e8aae154df6121167e5b4f156cfc2402e651d2b1 (diff) |
Merge branch 'remotes/lorenzo/pci/dwc'
- Return error instead of success if DMA mapping of MSI area fails (Jiantao
Zhang)
- Drop tegra194 MSI register save/restore, which is unnecessary since the
DWC core does it (Jisheng Zhang)
- Factor out qcom enable/disable resources code (Dmitry Baryshkov)
- Remove "snps,dw-pcie" from rockchip-dwc DT "compatible" property because
it's not fully compatible with rockchip (Peter Geis)
- Reset rockchip-dwc controller at probe (Peter Geis)
- Add rockchip-dwc INTx support (Peter Geis)
* remotes/lorenzo/pci/dwc:
PCI: rockchip-dwc: Add legacy interrupt support
PCI: rockchip-dwc: Reset core at driver probe
dt-bindings: PCI: Remove fallback from Rockchip DesignWare binding
PCI: qcom-ep: Move enable/disable resources code to common functions
PCI: tegra194: Remove unnecessary MSI enable reg save and restore
PCI: dwc: Fix setting error return on MSI DMA mapping failure
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-host.c | 3 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-dw-rockchip.c | 119 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-qcom-ep.c | 91 | ||||
-rw-r--r-- | drivers/pci/controller/dwc/pcie-tegra194.c | 9 |
4 files changed, 152 insertions, 70 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 2fa86f32d964..9979302532b7 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -396,7 +396,8 @@ int dw_pcie_host_init(struct pcie_port *pp) sizeof(pp->msi_msg), DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); - if (dma_mapping_error(pci->dev, pp->msi_data)) { + ret = dma_mapping_error(pci->dev, pp->msi_data); + if (ret) { dev_err(pci->dev, "Failed to map MSI data\n"); pp->msi_data = 0; goto err_free_msi; diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index c9b341e55cbb..8c5bb9d7cc36 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -10,9 +10,12 @@ #include <linux/clk.h> #include <linux/gpio/consumer.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -26,6 +29,7 @@ */ #define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val)) #define HIWORD_UPDATE_BIT(val) HIWORD_UPDATE(val, val) +#define HIWORD_DISABLE_BIT(val) HIWORD_UPDATE(val, ~val) #define to_rockchip_pcie(x) dev_get_drvdata((x)->dev) @@ -36,10 +40,12 @@ #define PCIE_LINKUP (PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP) #define PCIE_L0S_ENTRY 0x11 #define PCIE_CLIENT_GENERAL_CONTROL 0x0 +#define PCIE_CLIENT_INTR_STATUS_LEGACY 0x8 +#define PCIE_CLIENT_INTR_MASK_LEGACY 0x1c #define PCIE_CLIENT_GENERAL_DEBUG 0x104 -#define PCIE_CLIENT_HOT_RESET_CTRL 0x180 +#define PCIE_CLIENT_HOT_RESET_CTRL 0x180 #define PCIE_CLIENT_LTSSM_STATUS 0x300 -#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) +#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) #define PCIE_LTSSM_STATUS_MASK GENMASK(5, 0) struct rockchip_pcie { @@ -51,6 +57,7 @@ struct rockchip_pcie { struct reset_control *rst; struct gpio_desc *rst_gpio; struct regulator *vpcie3v3; + struct irq_domain *irq_domain; }; static int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip, @@ -65,6 +72,78 @@ static void rockchip_pcie_writel_apb(struct rockchip_pcie *rockchip, writel_relaxed(val, rockchip->apb_base + reg); } +static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc); + unsigned long reg, hwirq; + + chained_irq_enter(chip, desc); + + reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_LEGACY); + + for_each_set_bit(hwirq, ®, 4) + generic_handle_domain_irq(rockchip->irq_domain, hwirq); + + chained_irq_exit(chip, desc); +} + +static void rockchip_intx_mask(struct irq_data *data) +{ + rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data), + HIWORD_UPDATE_BIT(BIT(data->hwirq)), + PCIE_CLIENT_INTR_MASK_LEGACY); +}; + +static void rockchip_intx_unmask(struct irq_data *data) +{ + rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data), + HIWORD_DISABLE_BIT(BIT(data->hwirq)), + PCIE_CLIENT_INTR_MASK_LEGACY); +}; + +static struct irq_chip rockchip_intx_irq_chip = { + .name = "INTx", + .irq_mask = rockchip_intx_mask, + .irq_unmask = rockchip_intx_unmask, + .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, +}; + +static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &rockchip_intx_irq_chip, handle_level_irq); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops intx_domain_ops = { + .map = rockchip_pcie_intx_map, +}; + +static int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip) +{ + struct device *dev = rockchip->pci.dev; + struct device_node *intc; + + intc = of_get_child_by_name(dev->of_node, "legacy-interrupt-controller"); + if (!intc) { + dev_err(dev, "missing child interrupt-controller node\n"); + return -EINVAL; + } + + rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX, + &intx_domain_ops, rockchip); + of_node_put(intc); + if (!rockchip->irq_domain) { + dev_err(dev, "failed to get a INTx IRQ domain\n"); + return -EINVAL; + } + + return 0; +} + static void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip) { rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM, @@ -111,7 +190,20 @@ static int rockchip_pcie_host_init(struct pcie_port *pp) { struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); + struct device *dev = rockchip->pci.dev; u32 val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE); + int irq, ret; + + irq = of_irq_get_byname(dev->of_node, "legacy"); + if (irq < 0) + return irq; + + ret = rockchip_pcie_init_irq_domain(rockchip); + if (ret < 0) + dev_err(dev, "failed to init irq domain\n"); + + irq_set_chained_handler_and_data(irq, rockchip_pcie_legacy_int_handler, + rockchip); /* LTSSM enable control mode */ rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); @@ -152,6 +244,11 @@ static int rockchip_pcie_resource_get(struct platform_device *pdev, if (IS_ERR(rockchip->rst_gpio)) return PTR_ERR(rockchip->rst_gpio); + rockchip->rst = devm_reset_control_array_get_exclusive(&pdev->dev); + if (IS_ERR(rockchip->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rockchip->rst), + "failed to get reset lines\n"); + return 0; } @@ -182,18 +279,6 @@ static void rockchip_pcie_phy_deinit(struct rockchip_pcie *rockchip) phy_power_off(rockchip->phy); } -static int rockchip_pcie_reset_control_release(struct rockchip_pcie *rockchip) -{ - struct device *dev = rockchip->pci.dev; - - rockchip->rst = devm_reset_control_array_get_exclusive(dev); - if (IS_ERR(rockchip->rst)) - return dev_err_probe(dev, PTR_ERR(rockchip->rst), - "failed to get reset lines\n"); - - return reset_control_deassert(rockchip->rst); -} - static const struct dw_pcie_ops dw_pcie_ops = { .link_up = rockchip_pcie_link_up, .start_link = rockchip_pcie_start_link, @@ -222,6 +307,10 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (ret) return ret; + ret = reset_control_assert(rockchip->rst); + if (ret) + return ret; + /* DON'T MOVE ME: must be enable before PHY init */ rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3"); if (IS_ERR(rockchip->vpcie3v3)) { @@ -241,7 +330,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) if (ret) goto disable_regulator; - ret = rockchip_pcie_reset_control_release(rockchip); + ret = reset_control_deassert(rockchip->rst); if (ret) goto deinit_phy; diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index 6ce8eddf3a37..ec99116ad05c 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -223,11 +223,8 @@ static void qcom_pcie_dw_stop_link(struct dw_pcie *pci) disable_irq(pcie_ep->perst_irq); } -static int qcom_pcie_perst_deassert(struct dw_pcie *pci) +static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep) { - struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); - struct device *dev = pci->dev; - u32 val, offset; int ret; ret = clk_bulk_prepare_enable(ARRAY_SIZE(qcom_pcie_ep_clks), @@ -247,6 +244,38 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) if (ret) goto err_phy_exit; + return 0; + +err_phy_exit: + phy_exit(pcie_ep->phy); +err_disable_clk: + clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), + qcom_pcie_ep_clks); + + return ret; +} + +static void qcom_pcie_disable_resources(struct qcom_pcie_ep *pcie_ep) +{ + phy_power_off(pcie_ep->phy); + phy_exit(pcie_ep->phy); + clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), + qcom_pcie_ep_clks); +} + +static int qcom_pcie_perst_deassert(struct dw_pcie *pci) +{ + struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); + struct device *dev = pci->dev; + u32 val, offset; + int ret; + + ret = qcom_pcie_enable_resources(pcie_ep); + if (ret) { + dev_err(dev, "Failed to enable resources: %d\n", ret); + return ret; + } + /* Assert WAKE# to RC to indicate device is ready */ gpiod_set_value_cansleep(pcie_ep->wake, 1); usleep_range(WAKE_DELAY_US, WAKE_DELAY_US + 500); @@ -335,7 +364,7 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) ret = dw_pcie_ep_init_complete(&pcie_ep->pci.ep); if (ret) { dev_err(dev, "Failed to complete initialization: %d\n", ret); - goto err_phy_power_off; + goto err_disable_resources; } /* @@ -355,13 +384,8 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) return 0; -err_phy_power_off: - phy_power_off(pcie_ep->phy); -err_phy_exit: - phy_exit(pcie_ep->phy); -err_disable_clk: - clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); +err_disable_resources: + qcom_pcie_disable_resources(pcie_ep); return ret; } @@ -376,10 +400,7 @@ static void qcom_pcie_perst_assert(struct dw_pcie *pci) return; } - phy_power_off(pcie_ep->phy); - phy_exit(pcie_ep->phy); - clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); + qcom_pcie_disable_resources(pcie_ep); pcie_ep->link_status = QCOM_PCIE_EP_LINK_DISABLED; } @@ -643,43 +664,26 @@ static int qcom_pcie_ep_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_bulk_prepare_enable(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); - if (ret) + ret = qcom_pcie_enable_resources(pcie_ep); + if (ret) { + dev_err(dev, "Failed to enable resources: %d\n", ret); return ret; - - ret = qcom_pcie_ep_core_reset(pcie_ep); - if (ret) - goto err_disable_clk; - - ret = phy_init(pcie_ep->phy); - if (ret) - goto err_disable_clk; - - /* PHY needs to be powered on for dw_pcie_ep_init() */ - ret = phy_power_on(pcie_ep->phy); - if (ret) - goto err_phy_exit; + } ret = dw_pcie_ep_init(&pcie_ep->pci.ep); if (ret) { dev_err(dev, "Failed to initialize endpoint: %d\n", ret); - goto err_phy_power_off; + goto err_disable_resources; } ret = qcom_pcie_ep_enable_irq_resources(pdev, pcie_ep); if (ret) - goto err_phy_power_off; + goto err_disable_resources; return 0; -err_phy_power_off: - phy_power_off(pcie_ep->phy); -err_phy_exit: - phy_exit(pcie_ep->phy); -err_disable_clk: - clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); +err_disable_resources: + qcom_pcie_disable_resources(pcie_ep); return ret; } @@ -691,10 +695,7 @@ static int qcom_pcie_ep_remove(struct platform_device *pdev) if (pcie_ep->link_status == QCOM_PCIE_EP_LINK_DISABLED) return 0; - phy_power_off(pcie_ep->phy); - phy_exit(pcie_ep->phy); - clk_bulk_disable_unprepare(ARRAY_SIZE(qcom_pcie_ep_clks), - qcom_pcie_ep_clks); + qcom_pcie_disable_resources(pcie_ep); return 0; } diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index b1b5f836a806..cc2678490162 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -186,8 +186,6 @@ #define N_FTS_VAL 52 #define FTS_VAL 52 -#define PORT_LOGIC_MSI_CTRL_INT_0_EN 0x828 - #define GEN3_EQ_CONTROL_OFF 0x8a8 #define GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_SHIFT 8 #define GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC_MASK GENMASK(23, 8) @@ -2189,9 +2187,6 @@ static int tegra194_pcie_suspend_noirq(struct device *dev) if (!pcie->link_state) return 0; - /* Save MSI interrupt vector */ - pcie->msi_ctrl_int = dw_pcie_readl_dbi(&pcie->pci, - PORT_LOGIC_MSI_CTRL_INT_0_EN); tegra_pcie_downstream_dev_to_D0(pcie); tegra194_pcie_pme_turnoff(pcie); tegra_pcie_unconfig_controller(pcie); @@ -2223,10 +2218,6 @@ static int tegra194_pcie_resume_noirq(struct device *dev) if (ret < 0) goto fail_host_init; - /* Restore MSI interrupt vector */ - dw_pcie_writel_dbi(&pcie->pci, PORT_LOGIC_MSI_CTRL_INT_0_EN, - pcie->msi_ctrl_int); - return 0; fail_host_init: |