| From 6a114526af4689938863bf34976c83bfd279f517 Mon Sep 17 00:00:00 2001 |
| From: Ansuel Smith <ansuelsmth@gmail.com> |
| Date: Mon, 15 Jun 2020 23:06:02 +0200 |
| Subject: PCI: qcom: Use bulk clk api and assert on error |
| |
| Rework 2.1.0 revision to use bulk clk api and fix missing assert on |
| reset_control_deassert error. |
| |
| Link: https://lore.kernel.org/r/20200615210608.21469-7-ansuelsmth@gmail.com |
| Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com> |
| Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> |
| Reviewed-by: Rob Herring <robh@kernel.org> |
| Acked-by: Stanimir Varbanov <svarbanov@mm-sol.com> |
| --- |
| drivers/pci/controller/dwc/pcie-qcom.c | 131 ++++++++++++--------------------- |
| 1 file changed, 46 insertions(+), 85 deletions(-) |
| |
| --- a/drivers/pci/controller/dwc/pcie-qcom.c |
| +++ b/drivers/pci/controller/dwc/pcie-qcom.c |
| @@ -99,12 +99,9 @@ |
| #define SLV_ADDR_SPACE_SZ 0x10000000 |
| |
| #define QCOM_PCIE_2_1_0_MAX_SUPPLY 3 |
| +#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5 |
| struct qcom_pcie_resources_2_1_0 { |
| - struct clk *iface_clk; |
| - struct clk *core_clk; |
| - struct clk *phy_clk; |
| - struct clk *aux_clk; |
| - struct clk *ref_clk; |
| + struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS]; |
| struct reset_control *pci_reset; |
| struct reset_control *axi_reset; |
| struct reset_control *ahb_reset; |
| @@ -244,25 +241,21 @@ static int qcom_pcie_get_resources_2_1_0 |
| if (ret) |
| return ret; |
| |
| - res->iface_clk = devm_clk_get(dev, "iface"); |
| - if (IS_ERR(res->iface_clk)) |
| - return PTR_ERR(res->iface_clk); |
| - |
| - res->core_clk = devm_clk_get(dev, "core"); |
| - if (IS_ERR(res->core_clk)) |
| - return PTR_ERR(res->core_clk); |
| - |
| - res->phy_clk = devm_clk_get(dev, "phy"); |
| - if (IS_ERR(res->phy_clk)) |
| - return PTR_ERR(res->phy_clk); |
| - |
| - res->aux_clk = devm_clk_get_optional(dev, "aux"); |
| - if (IS_ERR(res->aux_clk)) |
| - return PTR_ERR(res->aux_clk); |
| - |
| - res->ref_clk = devm_clk_get_optional(dev, "ref"); |
| - if (IS_ERR(res->ref_clk)) |
| - return PTR_ERR(res->ref_clk); |
| + res->clks[0].id = "iface"; |
| + res->clks[1].id = "core"; |
| + res->clks[2].id = "phy"; |
| + res->clks[3].id = "aux"; |
| + res->clks[4].id = "ref"; |
| + |
| + /* iface, core, phy are required */ |
| + ret = devm_clk_bulk_get(dev, 3, res->clks); |
| + if (ret < 0) |
| + return ret; |
| + |
| + /* aux, ref are optional */ |
| + ret = devm_clk_bulk_get_optional(dev, 2, res->clks + 3); |
| + if (ret < 0) |
| + return ret; |
| |
| res->pci_reset = devm_reset_control_get_exclusive(dev, "pci"); |
| if (IS_ERR(res->pci_reset)) |
| @@ -292,17 +285,13 @@ static void qcom_pcie_deinit_2_1_0(struc |
| { |
| struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0; |
| |
| - clk_disable_unprepare(res->phy_clk); |
| + clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks); |
| reset_control_assert(res->pci_reset); |
| reset_control_assert(res->axi_reset); |
| reset_control_assert(res->ahb_reset); |
| reset_control_assert(res->por_reset); |
| reset_control_assert(res->ext_reset); |
| reset_control_assert(res->phy_reset); |
| - clk_disable_unprepare(res->iface_clk); |
| - clk_disable_unprepare(res->core_clk); |
| - clk_disable_unprepare(res->aux_clk); |
| - clk_disable_unprepare(res->ref_clk); |
| |
| writel(1, pcie->parf + PCIE20_PARF_PHY_CTRL); |
| |
| @@ -334,47 +323,45 @@ static int qcom_pcie_init_2_1_0(struct q |
| return ret; |
| } |
| |
| - ret = reset_control_assert(res->ahb_reset); |
| + ret = reset_control_deassert(res->ahb_reset); |
| if (ret) { |
| - dev_err(dev, "cannot assert ahb reset\n"); |
| - goto err_assert_ahb; |
| + dev_err(dev, "cannot deassert ahb reset\n"); |
| + goto err_deassert_ahb; |
| } |
| |
| - ret = clk_prepare_enable(res->iface_clk); |
| + ret = reset_control_deassert(res->ext_reset); |
| if (ret) { |
| - dev_err(dev, "cannot prepare/enable iface clock\n"); |
| - goto err_assert_ahb; |
| + dev_err(dev, "cannot deassert ext reset\n"); |
| + goto err_deassert_ext; |
| } |
| |
| - ret = clk_prepare_enable(res->core_clk); |
| + ret = reset_control_deassert(res->phy_reset); |
| if (ret) { |
| - dev_err(dev, "cannot prepare/enable core clock\n"); |
| - goto err_clk_core; |
| + dev_err(dev, "cannot deassert phy reset\n"); |
| + goto err_deassert_phy; |
| } |
| |
| - ret = clk_prepare_enable(res->aux_clk); |
| + ret = reset_control_deassert(res->pci_reset); |
| if (ret) { |
| - dev_err(dev, "cannot prepare/enable aux clock\n"); |
| - goto err_clk_aux; |
| + dev_err(dev, "cannot deassert pci reset\n"); |
| + goto err_deassert_pci; |
| } |
| |
| - ret = clk_prepare_enable(res->ref_clk); |
| + ret = reset_control_deassert(res->por_reset); |
| if (ret) { |
| - dev_err(dev, "cannot prepare/enable ref clock\n"); |
| - goto err_clk_ref; |
| + dev_err(dev, "cannot deassert por reset\n"); |
| + goto err_deassert_por; |
| } |
| |
| - ret = reset_control_deassert(res->ahb_reset); |
| + ret = reset_control_deassert(res->axi_reset); |
| if (ret) { |
| - dev_err(dev, "cannot deassert ahb reset\n"); |
| - goto err_deassert_ahb; |
| + dev_err(dev, "cannot deassert axi reset\n"); |
| + goto err_deassert_axi; |
| } |
| |
| - ret = reset_control_deassert(res->ext_reset); |
| - if (ret) { |
| - dev_err(dev, "cannot deassert ext reset\n"); |
| - goto err_deassert_ahb; |
| - } |
| + ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks); |
| + if (ret) |
| + goto err_clks; |
| |
| /* enable PCIe clocks and resets */ |
| val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL); |
| @@ -408,36 +395,6 @@ static int qcom_pcie_init_2_1_0(struct q |
| val |= PHY_REFCLK_SSP_EN; |
| writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK); |
| |
| - ret = reset_control_deassert(res->phy_reset); |
| - if (ret) { |
| - dev_err(dev, "cannot deassert phy reset\n"); |
| - return ret; |
| - } |
| - |
| - ret = reset_control_deassert(res->pci_reset); |
| - if (ret) { |
| - dev_err(dev, "cannot deassert pci reset\n"); |
| - return ret; |
| - } |
| - |
| - ret = reset_control_deassert(res->por_reset); |
| - if (ret) { |
| - dev_err(dev, "cannot deassert por reset\n"); |
| - return ret; |
| - } |
| - |
| - ret = reset_control_deassert(res->axi_reset); |
| - if (ret) { |
| - dev_err(dev, "cannot deassert axi reset\n"); |
| - return ret; |
| - } |
| - |
| - ret = clk_prepare_enable(res->phy_clk); |
| - if (ret) { |
| - dev_err(dev, "cannot prepare/enable phy clock\n"); |
| - goto err_deassert_ahb; |
| - } |
| - |
| /* wait for clock acquisition */ |
| usleep_range(1000, 1500); |
| |
| @@ -450,15 +407,19 @@ static int qcom_pcie_init_2_1_0(struct q |
| |
| return 0; |
| |
| +err_clks: |
| + reset_control_assert(res->axi_reset); |
| +err_deassert_axi: |
| + reset_control_assert(res->por_reset); |
| +err_deassert_por: |
| + reset_control_assert(res->pci_reset); |
| +err_deassert_pci: |
| + reset_control_assert(res->phy_reset); |
| +err_deassert_phy: |
| + reset_control_assert(res->ext_reset); |
| +err_deassert_ext: |
| + reset_control_assert(res->ahb_reset); |
| err_deassert_ahb: |
| - clk_disable_unprepare(res->ref_clk); |
| -err_clk_ref: |
| - clk_disable_unprepare(res->aux_clk); |
| -err_clk_aux: |
| - clk_disable_unprepare(res->core_clk); |
| -err_clk_core: |
| - clk_disable_unprepare(res->iface_clk); |
| -err_assert_ahb: |
| regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies); |
| |
| return ret; |