Skip to content

Commit 0179423

Browse files
Krishna chaitanya chundrukwilczynski
authored andcommitted
PCI: qcom-ep: Add ICC bandwidth voting support
Add support for voting interconnect (ICC) bandwidth based on the link speed and width. This commit is inspired from the basic interconnect support added to pcie-qcom driver in commit c4860af ("PCI: qcom: Add basic interconnect support"). The interconnect support is kept optional to be backward compatible with legacy device trees. [kwilczynski: add missing kernel-doc for the icc_mem variable] Link: https://lore.kernel.org/linux-pci/1689751218-24492-5-git-send-email-quic_krichai@quicinc.com Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com> Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org> Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
1 parent e590ad2 commit 0179423

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

drivers/pci/controller/dwc/pcie-qcom-ep.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/debugfs.h>
1414
#include <linux/delay.h>
1515
#include <linux/gpio/consumer.h>
16+
#include <linux/interconnect.h>
1617
#include <linux/mfd/syscon.h>
1718
#include <linux/phy/pcie.h>
1819
#include <linux/phy/phy.h>
@@ -133,6 +134,11 @@
133134
#define CORE_RESET_TIME_US_MAX 1005
134135
#define WAKE_DELAY_US 2000 /* 2 ms */
135136

137+
#define PCIE_GEN1_BW_MBPS 250
138+
#define PCIE_GEN2_BW_MBPS 500
139+
#define PCIE_GEN3_BW_MBPS 985
140+
#define PCIE_GEN4_BW_MBPS 1969
141+
136142
#define to_pcie_ep(x) dev_get_drvdata((x)->dev)
137143

138144
enum qcom_pcie_ep_link_status {
@@ -155,6 +161,7 @@ enum qcom_pcie_ep_link_status {
155161
* @wake: WAKE# GPIO
156162
* @phy: PHY controller block
157163
* @debugfs: PCIe Endpoint Debugfs directory
164+
* @icc_mem: Handle to an interconnect path between PCIe and MEM
158165
* @clks: PCIe clocks
159166
* @num_clks: PCIe clocks count
160167
* @perst_en: Flag for PERST enable
@@ -178,6 +185,8 @@ struct qcom_pcie_ep {
178185
struct phy *phy;
179186
struct dentry *debugfs;
180187

188+
struct icc_path *icc_mem;
189+
181190
struct clk_bulk_data *clks;
182191
int num_clks;
183192

@@ -253,8 +262,49 @@ static void qcom_pcie_dw_stop_link(struct dw_pcie *pci)
253262
disable_irq(pcie_ep->perst_irq);
254263
}
255264

265+
static void qcom_pcie_ep_icc_update(struct qcom_pcie_ep *pcie_ep)
266+
{
267+
struct dw_pcie *pci = &pcie_ep->pci;
268+
u32 offset, status, bw;
269+
int speed, width;
270+
int ret;
271+
272+
if (!pcie_ep->icc_mem)
273+
return;
274+
275+
offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
276+
status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
277+
278+
speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
279+
width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status);
280+
281+
switch (speed) {
282+
case 1:
283+
bw = MBps_to_icc(PCIE_GEN1_BW_MBPS);
284+
break;
285+
case 2:
286+
bw = MBps_to_icc(PCIE_GEN2_BW_MBPS);
287+
break;
288+
case 3:
289+
bw = MBps_to_icc(PCIE_GEN3_BW_MBPS);
290+
break;
291+
default:
292+
dev_warn(pci->dev, "using default GEN4 bandwidth\n");
293+
fallthrough;
294+
case 4:
295+
bw = MBps_to_icc(PCIE_GEN4_BW_MBPS);
296+
break;
297+
}
298+
299+
ret = icc_set_bw(pcie_ep->icc_mem, 0, width * bw);
300+
if (ret)
301+
dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
302+
ret);
303+
}
304+
256305
static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep)
257306
{
307+
struct dw_pcie *pci = &pcie_ep->pci;
258308
int ret;
259309

260310
ret = clk_bulk_prepare_enable(pcie_ep->num_clks, pcie_ep->clks);
@@ -277,8 +327,24 @@ static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep)
277327
if (ret)
278328
goto err_phy_exit;
279329

330+
/*
331+
* Some Qualcomm platforms require interconnect bandwidth constraints
332+
* to be set before enabling interconnect clocks.
333+
*
334+
* Set an initial peak bandwidth corresponding to single-lane Gen 1
335+
* for the pcie-mem path.
336+
*/
337+
ret = icc_set_bw(pcie_ep->icc_mem, 0, MBps_to_icc(PCIE_GEN1_BW_MBPS));
338+
if (ret) {
339+
dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
340+
ret);
341+
goto err_phy_off;
342+
}
343+
280344
return 0;
281345

346+
err_phy_off:
347+
phy_power_off(pcie_ep->phy);
282348
err_phy_exit:
283349
phy_exit(pcie_ep->phy);
284350
err_disable_clk:
@@ -289,6 +355,7 @@ static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep)
289355

290356
static void qcom_pcie_disable_resources(struct qcom_pcie_ep *pcie_ep)
291357
{
358+
icc_set_bw(pcie_ep->icc_mem, 0, 0);
292359
phy_power_off(pcie_ep->phy);
293360
phy_exit(pcie_ep->phy);
294361
clk_bulk_disable_unprepare(pcie_ep->num_clks, pcie_ep->clks);
@@ -550,6 +617,10 @@ static int qcom_pcie_ep_get_resources(struct platform_device *pdev,
550617
if (IS_ERR(pcie_ep->phy))
551618
ret = PTR_ERR(pcie_ep->phy);
552619

620+
pcie_ep->icc_mem = devm_of_icc_get(dev, "pcie-mem");
621+
if (IS_ERR(pcie_ep->icc_mem))
622+
ret = PTR_ERR(pcie_ep->icc_mem);
623+
553624
return ret;
554625
}
555626

@@ -573,6 +644,7 @@ static irqreturn_t qcom_pcie_ep_global_irq_thread(int irq, void *data)
573644
} else if (FIELD_GET(PARF_INT_ALL_BME, status)) {
574645
dev_dbg(dev, "Received BME event. Link is enabled!\n");
575646
pcie_ep->link_status = QCOM_PCIE_EP_LINK_ENABLED;
647+
qcom_pcie_ep_icc_update(pcie_ep);
576648
pci_epc_bme_notify(pci->ep.epc);
577649
} else if (FIELD_GET(PARF_INT_ALL_PM_TURNOFF, status)) {
578650
dev_dbg(dev, "Received PM Turn-off event! Entering L23\n");

0 commit comments

Comments
 (0)