Merge branch 'remotes/lorenzo/pci/qcom'
- Move qcom driver to bulk clock API (Bjorn Andersson) - Add Qualcomm QCS404 PCIe controller support (Bjorn Andersson) - Ensure Qualcomm PERST is asserted for at least 100ms (Niklas Cassel) * remotes/lorenzo/pci/qcom: PCI: qcom: Ensure that PERST is asserted for at least 100 ms PCI: qcom: Add QCS404 PCIe controller support dt-bindings: PCI: qcom: Add QCS404 to the binding PCI: qcom: Use clk bulk API for 2.4.0 controllers
This commit is contained in:
commit
757410bd97
|
@ -10,6 +10,7 @@
|
||||||
- "qcom,pcie-msm8996" for msm8996 or apq8096
|
- "qcom,pcie-msm8996" for msm8996 or apq8096
|
||||||
- "qcom,pcie-ipq4019" for ipq4019
|
- "qcom,pcie-ipq4019" for ipq4019
|
||||||
- "qcom,pcie-ipq8074" for ipq8074
|
- "qcom,pcie-ipq8074" for ipq8074
|
||||||
|
- "qcom,pcie-qcs404" for qcs404
|
||||||
|
|
||||||
- reg:
|
- reg:
|
||||||
Usage: required
|
Usage: required
|
||||||
|
@ -116,6 +117,15 @@
|
||||||
- "ahb" AHB clock
|
- "ahb" AHB clock
|
||||||
- "aux" Auxiliary clock
|
- "aux" Auxiliary clock
|
||||||
|
|
||||||
|
- clock-names:
|
||||||
|
Usage: required for qcs404
|
||||||
|
Value type: <stringlist>
|
||||||
|
Definition: Should contain the following entries
|
||||||
|
- "iface" AHB clock
|
||||||
|
- "aux" Auxiliary clock
|
||||||
|
- "master_bus" AXI Master clock
|
||||||
|
- "slave_bus" AXI Slave clock
|
||||||
|
|
||||||
- resets:
|
- resets:
|
||||||
Usage: required
|
Usage: required
|
||||||
Value type: <prop-encoded-array>
|
Value type: <prop-encoded-array>
|
||||||
|
@ -167,6 +177,17 @@
|
||||||
- "ahb" AHB Reset
|
- "ahb" AHB Reset
|
||||||
- "axi_m_sticky" AXI Master Sticky reset
|
- "axi_m_sticky" AXI Master Sticky reset
|
||||||
|
|
||||||
|
- reset-names:
|
||||||
|
Usage: required for qcs404
|
||||||
|
Value type: <stringlist>
|
||||||
|
Definition: Should contain the following entries
|
||||||
|
- "axi_m" AXI Master reset
|
||||||
|
- "axi_s" AXI Slave reset
|
||||||
|
- "axi_m_sticky" AXI Master Sticky reset
|
||||||
|
- "pipe_sticky" PIPE sticky reset
|
||||||
|
- "pwr" PWR reset
|
||||||
|
- "ahb" AHB reset
|
||||||
|
|
||||||
- power-domains:
|
- power-domains:
|
||||||
Usage: required for apq8084 and msm8996/apq8096
|
Usage: required for apq8084 and msm8996/apq8096
|
||||||
Value type: <prop-encoded-array>
|
Value type: <prop-encoded-array>
|
||||||
|
@ -195,12 +216,12 @@
|
||||||
Definition: A phandle to the PCIe endpoint power supply
|
Definition: A phandle to the PCIe endpoint power supply
|
||||||
|
|
||||||
- phys:
|
- phys:
|
||||||
Usage: required for apq8084
|
Usage: required for apq8084 and qcs404
|
||||||
Value type: <phandle>
|
Value type: <phandle>
|
||||||
Definition: List of phandle(s) as listed in phy-names property
|
Definition: List of phandle(s) as listed in phy-names property
|
||||||
|
|
||||||
- phy-names:
|
- phy-names:
|
||||||
Usage: required for apq8084
|
Usage: required for apq8084 and qcs404
|
||||||
Value type: <stringlist>
|
Value type: <stringlist>
|
||||||
Definition: Should contain "pciephy"
|
Definition: Should contain "pciephy"
|
||||||
|
|
||||||
|
|
|
@ -112,10 +112,10 @@ struct qcom_pcie_resources_2_3_2 {
|
||||||
struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY];
|
struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define QCOM_PCIE_2_4_0_MAX_CLOCKS 4
|
||||||
struct qcom_pcie_resources_2_4_0 {
|
struct qcom_pcie_resources_2_4_0 {
|
||||||
struct clk *aux_clk;
|
struct clk_bulk_data clks[QCOM_PCIE_2_4_0_MAX_CLOCKS];
|
||||||
struct clk *master_clk;
|
int num_clks;
|
||||||
struct clk *slave_clk;
|
|
||||||
struct reset_control *axi_m_reset;
|
struct reset_control *axi_m_reset;
|
||||||
struct reset_control *axi_s_reset;
|
struct reset_control *axi_s_reset;
|
||||||
struct reset_control *pipe_reset;
|
struct reset_control *pipe_reset;
|
||||||
|
@ -178,6 +178,8 @@ static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
|
||||||
|
|
||||||
static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
|
static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
|
||||||
{
|
{
|
||||||
|
/* Ensure that PERST has been asserted for at least 100 ms */
|
||||||
|
msleep(100);
|
||||||
gpiod_set_value_cansleep(pcie->reset, 0);
|
gpiod_set_value_cansleep(pcie->reset, 0);
|
||||||
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
|
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
|
||||||
}
|
}
|
||||||
|
@ -638,18 +640,20 @@ static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
|
||||||
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
|
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
|
||||||
struct dw_pcie *pci = pcie->pci;
|
struct dw_pcie *pci = pcie->pci;
|
||||||
struct device *dev = pci->dev;
|
struct device *dev = pci->dev;
|
||||||
|
bool is_ipq = of_device_is_compatible(dev->of_node, "qcom,pcie-ipq4019");
|
||||||
|
int ret;
|
||||||
|
|
||||||
res->aux_clk = devm_clk_get(dev, "aux");
|
res->clks[0].id = "aux";
|
||||||
if (IS_ERR(res->aux_clk))
|
res->clks[1].id = "master_bus";
|
||||||
return PTR_ERR(res->aux_clk);
|
res->clks[2].id = "slave_bus";
|
||||||
|
res->clks[3].id = "iface";
|
||||||
|
|
||||||
res->master_clk = devm_clk_get(dev, "master_bus");
|
/* qcom,pcie-ipq4019 is defined without "iface" */
|
||||||
if (IS_ERR(res->master_clk))
|
res->num_clks = is_ipq ? 3 : 4;
|
||||||
return PTR_ERR(res->master_clk);
|
|
||||||
|
|
||||||
res->slave_clk = devm_clk_get(dev, "slave_bus");
|
ret = devm_clk_bulk_get(dev, res->num_clks, res->clks);
|
||||||
if (IS_ERR(res->slave_clk))
|
if (ret < 0)
|
||||||
return PTR_ERR(res->slave_clk);
|
return ret;
|
||||||
|
|
||||||
res->axi_m_reset = devm_reset_control_get_exclusive(dev, "axi_m");
|
res->axi_m_reset = devm_reset_control_get_exclusive(dev, "axi_m");
|
||||||
if (IS_ERR(res->axi_m_reset))
|
if (IS_ERR(res->axi_m_reset))
|
||||||
|
@ -659,27 +663,33 @@ static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
|
||||||
if (IS_ERR(res->axi_s_reset))
|
if (IS_ERR(res->axi_s_reset))
|
||||||
return PTR_ERR(res->axi_s_reset);
|
return PTR_ERR(res->axi_s_reset);
|
||||||
|
|
||||||
res->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
|
if (is_ipq) {
|
||||||
if (IS_ERR(res->pipe_reset))
|
/*
|
||||||
return PTR_ERR(res->pipe_reset);
|
* These resources relates to the PHY or are secure clocks, but
|
||||||
|
* are controlled here for IPQ4019
|
||||||
|
*/
|
||||||
|
res->pipe_reset = devm_reset_control_get_exclusive(dev, "pipe");
|
||||||
|
if (IS_ERR(res->pipe_reset))
|
||||||
|
return PTR_ERR(res->pipe_reset);
|
||||||
|
|
||||||
res->axi_m_vmid_reset = devm_reset_control_get_exclusive(dev,
|
res->axi_m_vmid_reset = devm_reset_control_get_exclusive(dev,
|
||||||
"axi_m_vmid");
|
"axi_m_vmid");
|
||||||
if (IS_ERR(res->axi_m_vmid_reset))
|
if (IS_ERR(res->axi_m_vmid_reset))
|
||||||
return PTR_ERR(res->axi_m_vmid_reset);
|
return PTR_ERR(res->axi_m_vmid_reset);
|
||||||
|
|
||||||
res->axi_s_xpu_reset = devm_reset_control_get_exclusive(dev,
|
res->axi_s_xpu_reset = devm_reset_control_get_exclusive(dev,
|
||||||
"axi_s_xpu");
|
"axi_s_xpu");
|
||||||
if (IS_ERR(res->axi_s_xpu_reset))
|
if (IS_ERR(res->axi_s_xpu_reset))
|
||||||
return PTR_ERR(res->axi_s_xpu_reset);
|
return PTR_ERR(res->axi_s_xpu_reset);
|
||||||
|
|
||||||
res->parf_reset = devm_reset_control_get_exclusive(dev, "parf");
|
res->parf_reset = devm_reset_control_get_exclusive(dev, "parf");
|
||||||
if (IS_ERR(res->parf_reset))
|
if (IS_ERR(res->parf_reset))
|
||||||
return PTR_ERR(res->parf_reset);
|
return PTR_ERR(res->parf_reset);
|
||||||
|
|
||||||
res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
|
res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
|
||||||
if (IS_ERR(res->phy_reset))
|
if (IS_ERR(res->phy_reset))
|
||||||
return PTR_ERR(res->phy_reset);
|
return PTR_ERR(res->phy_reset);
|
||||||
|
}
|
||||||
|
|
||||||
res->axi_m_sticky_reset = devm_reset_control_get_exclusive(dev,
|
res->axi_m_sticky_reset = devm_reset_control_get_exclusive(dev,
|
||||||
"axi_m_sticky");
|
"axi_m_sticky");
|
||||||
|
@ -699,9 +709,11 @@ static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
|
||||||
if (IS_ERR(res->ahb_reset))
|
if (IS_ERR(res->ahb_reset))
|
||||||
return PTR_ERR(res->ahb_reset);
|
return PTR_ERR(res->ahb_reset);
|
||||||
|
|
||||||
res->phy_ahb_reset = devm_reset_control_get_exclusive(dev, "phy_ahb");
|
if (is_ipq) {
|
||||||
if (IS_ERR(res->phy_ahb_reset))
|
res->phy_ahb_reset = devm_reset_control_get_exclusive(dev, "phy_ahb");
|
||||||
return PTR_ERR(res->phy_ahb_reset);
|
if (IS_ERR(res->phy_ahb_reset))
|
||||||
|
return PTR_ERR(res->phy_ahb_reset);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -719,9 +731,7 @@ static void qcom_pcie_deinit_2_4_0(struct qcom_pcie *pcie)
|
||||||
reset_control_assert(res->axi_m_sticky_reset);
|
reset_control_assert(res->axi_m_sticky_reset);
|
||||||
reset_control_assert(res->pwr_reset);
|
reset_control_assert(res->pwr_reset);
|
||||||
reset_control_assert(res->ahb_reset);
|
reset_control_assert(res->ahb_reset);
|
||||||
clk_disable_unprepare(res->aux_clk);
|
clk_bulk_disable_unprepare(res->num_clks, res->clks);
|
||||||
clk_disable_unprepare(res->master_clk);
|
|
||||||
clk_disable_unprepare(res->slave_clk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
|
static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
|
||||||
|
@ -850,23 +860,9 @@ static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
|
||||||
|
|
||||||
usleep_range(10000, 12000);
|
usleep_range(10000, 12000);
|
||||||
|
|
||||||
ret = clk_prepare_enable(res->aux_clk);
|
ret = clk_bulk_prepare_enable(res->num_clks, res->clks);
|
||||||
if (ret) {
|
if (ret)
|
||||||
dev_err(dev, "cannot prepare/enable iface clock\n");
|
goto err_clks;
|
||||||
goto err_clk_aux;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(res->master_clk);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(dev, "cannot prepare/enable core clock\n");
|
|
||||||
goto err_clk_axi_m;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(res->slave_clk);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(dev, "cannot prepare/enable phy clock\n");
|
|
||||||
goto err_clk_axi_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* enable PCIe clocks and resets */
|
/* enable PCIe clocks and resets */
|
||||||
val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
|
val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
|
||||||
|
@ -891,11 +887,7 @@ static int qcom_pcie_init_2_4_0(struct qcom_pcie *pcie)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_clk_axi_s:
|
err_clks:
|
||||||
clk_disable_unprepare(res->master_clk);
|
|
||||||
err_clk_axi_m:
|
|
||||||
clk_disable_unprepare(res->aux_clk);
|
|
||||||
err_clk_aux:
|
|
||||||
reset_control_assert(res->ahb_reset);
|
reset_control_assert(res->ahb_reset);
|
||||||
err_rst_ahb:
|
err_rst_ahb:
|
||||||
reset_control_assert(res->pwr_reset);
|
reset_control_assert(res->pwr_reset);
|
||||||
|
@ -1289,6 +1281,7 @@ static const struct of_device_id qcom_pcie_match[] = {
|
||||||
{ .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
|
{ .compatible = "qcom,pcie-msm8996", .data = &ops_2_3_2 },
|
||||||
{ .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
|
{ .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
|
||||||
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
|
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
|
||||||
|
{ .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue