Commit 39348d2e authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
parents 086ab943 e8aae154
Loading
Loading
Loading
Loading
+1 −11
Original line number Diff line number Diff line
@@ -19,20 +19,10 @@ description: |+
allOf:
  - $ref: /schemas/pci/pci-bus.yaml#

# We need a select here so we don't match all nodes with 'snps,dw-pcie'
select:
  properties:
    compatible:
      contains:
        const: rockchip,rk3568-pcie
  required:
    - compatible

properties:
  compatible:
    items:
      - const: rockchip,rk3568-pcie
      - const: snps,dw-pcie

  reg:
    items:
@@ -110,7 +100,7 @@ examples:
        #size-cells = <2>;

        pcie3x2: pcie@fe280000 {
            compatible = "rockchip,rk3568-pcie", "snps,dw-pcie";
            compatible = "rockchip,rk3568-pcie";
            reg = <0x3 0xc0800000 0x0 0x390000>,
                  <0x0 0xfe280000 0x0 0x10000>,
                  <0x3 0x80000000 0x0 0x100000>;
+2 −1
Original line number Diff line number Diff line
@@ -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;
+104 −15
Original line number Diff line number Diff line
@@ -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,6 +40,8 @@
#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_LTSSM_STATUS	0x300
@@ -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, &reg, 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;

+46 −45
Original line number Diff line number Diff line
@@ -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;
}
+0 −9
Original line number Diff line number Diff line
@@ -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: