Skip to content

Commit 9365bf0

Browse files
Sumit Guptathierryreding
authored andcommitted
PCI: tegra194: Add interconnect support in Tegra234
Add support to request DRAM bandwidth (BW) with Memory Interconnect in Tegra234 SoC. The DRAM BW required for different modes depends on the link speed (Gen-1/2/3/4) and width/lanes (x1/x2/x4/x8). Currently, the DRAM frequency is always set to the maximum available but that results in the highest power consumption. The Memory Interconnect is a software feature which uses Interconnect framework (ICC). It adds the capability for Memory Controller (MC) clients to request bandwidth and therefore scale DRAM frequency dynamically depending on the required link speed so that the DRAM energy consumption can be optimized. Suggested-by: Manikanta Maddireddy <mmaddireddy@nvidia.com> Signed-off-by: Sumit Gupta <sumitg@nvidia.com> Acked-by: Lorenzo Pieralisi <lpieralisi@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com>
1 parent 205b3d0 commit 9365bf0

1 file changed

Lines changed: 35 additions & 16 deletions

File tree

drivers/pci/controller/dwc/pcie-tegra194.c

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/delay.h>
1515
#include <linux/gpio.h>
1616
#include <linux/gpio/consumer.h>
17+
#include <linux/interconnect.h>
1718
#include <linux/interrupt.h>
1819
#include <linux/iopoll.h>
1920
#include <linux/kernel.h>
@@ -288,6 +289,7 @@ struct tegra_pcie_dw {
288289
unsigned int pex_rst_irq;
289290
int ep_state;
290291
long link_status;
292+
struct icc_path *icc_path;
291293
};
292294

293295
static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
@@ -310,6 +312,27 @@ struct tegra_pcie_soc {
310312
enum dw_pcie_device_mode mode;
311313
};
312314

315+
static void tegra_pcie_icc_set(struct tegra_pcie_dw *pcie)
316+
{
317+
struct dw_pcie *pci = &pcie->pci;
318+
u32 val, speed, width;
319+
320+
val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
321+
322+
speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, val);
323+
width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val);
324+
325+
val = width * (PCIE_SPEED2MBS_ENC(pcie_link_speed[speed]) / BITS_PER_BYTE);
326+
327+
if (icc_set_bw(pcie->icc_path, MBps_to_icc(val), 0))
328+
dev_err(pcie->dev, "can't set bw[%u]\n", val);
329+
330+
if (speed >= ARRAY_SIZE(pcie_gen_freq))
331+
speed = 0;
332+
333+
clk_set_rate(pcie->core_clk, pcie_gen_freq[speed]);
334+
}
335+
313336
static void apply_bad_link_workaround(struct dw_pcie_rp *pp)
314337
{
315338
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -453,18 +476,12 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
453476
struct tegra_pcie_dw *pcie = arg;
454477
struct dw_pcie_ep *ep = &pcie->pci.ep;
455478
struct dw_pcie *pci = &pcie->pci;
456-
u32 val, speed;
479+
u32 val;
457480

458481
if (test_and_clear_bit(0, &pcie->link_status))
459482
dw_pcie_ep_linkup(ep);
460483

461-
speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
462-
PCI_EXP_LNKSTA_CLS;
463-
464-
if (speed >= ARRAY_SIZE(pcie_gen_freq))
465-
speed = 0;
466-
467-
clk_set_rate(pcie->core_clk, pcie_gen_freq[speed]);
484+
tegra_pcie_icc_set(pcie);
468485

469486
if (pcie->of_data->has_ltr_req_fix)
470487
return IRQ_HANDLED;
@@ -950,9 +967,9 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
950967

951968
static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
952969
{
953-
u32 val, offset, speed, tmp;
954970
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
955971
struct dw_pcie_rp *pp = &pci->pp;
972+
u32 val, offset, tmp;
956973
bool retry = true;
957974

958975
if (pcie->of_data->mode == DW_PCIE_EP_TYPE) {
@@ -1023,13 +1040,7 @@ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
10231040
goto retry_link;
10241041
}
10251042

1026-
speed = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA) &
1027-
PCI_EXP_LNKSTA_CLS;
1028-
1029-
if (speed >= ARRAY_SIZE(pcie_gen_freq))
1030-
speed = 0;
1031-
1032-
clk_set_rate(pcie->core_clk, pcie_gen_freq[speed]);
1043+
tegra_pcie_icc_set(pcie);
10331044

10341045
tegra_pcie_enable_interrupts(pp);
10351046

@@ -2233,6 +2244,14 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
22332244

22342245
platform_set_drvdata(pdev, pcie);
22352246

2247+
pcie->icc_path = devm_of_icc_get(&pdev->dev, "write");
2248+
ret = PTR_ERR_OR_ZERO(pcie->icc_path);
2249+
if (ret) {
2250+
tegra_bpmp_put(pcie->bpmp);
2251+
dev_err_probe(&pdev->dev, ret, "failed to get write interconnect\n");
2252+
return ret;
2253+
}
2254+
22362255
switch (pcie->of_data->mode) {
22372256
case DW_PCIE_RC_TYPE:
22382257
ret = devm_request_irq(dev, pp->irq, tegra_pcie_rp_irq_handler,

0 commit comments

Comments
 (0)