13
13
#include <linux/debugfs.h>
14
14
#include <linux/delay.h>
15
15
#include <linux/gpio/consumer.h>
16
+ #include <linux/interconnect.h>
16
17
#include <linux/mfd/syscon.h>
17
18
#include <linux/phy/pcie.h>
18
19
#include <linux/phy/phy.h>
133
134
#define CORE_RESET_TIME_US_MAX 1005
134
135
#define WAKE_DELAY_US 2000 /* 2 ms */
135
136
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
+
136
142
#define to_pcie_ep (x ) dev_get_drvdata((x)->dev)
137
143
138
144
enum qcom_pcie_ep_link_status {
@@ -155,6 +161,7 @@ enum qcom_pcie_ep_link_status {
155
161
* @wake: WAKE# GPIO
156
162
* @phy: PHY controller block
157
163
* @debugfs: PCIe Endpoint Debugfs directory
164
+ * @icc_mem: Handle to an interconnect path between PCIe and MEM
158
165
* @clks: PCIe clocks
159
166
* @num_clks: PCIe clocks count
160
167
* @perst_en: Flag for PERST enable
@@ -178,6 +185,8 @@ struct qcom_pcie_ep {
178
185
struct phy * phy ;
179
186
struct dentry * debugfs ;
180
187
188
+ struct icc_path * icc_mem ;
189
+
181
190
struct clk_bulk_data * clks ;
182
191
int num_clks ;
183
192
@@ -253,8 +262,49 @@ static void qcom_pcie_dw_stop_link(struct dw_pcie *pci)
253
262
disable_irq (pcie_ep -> perst_irq );
254
263
}
255
264
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
+
256
305
static int qcom_pcie_enable_resources (struct qcom_pcie_ep * pcie_ep )
257
306
{
307
+ struct dw_pcie * pci = & pcie_ep -> pci ;
258
308
int ret ;
259
309
260
310
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)
277
327
if (ret )
278
328
goto err_phy_exit ;
279
329
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
+
280
344
return 0 ;
281
345
346
+ err_phy_off :
347
+ phy_power_off (pcie_ep -> phy );
282
348
err_phy_exit :
283
349
phy_exit (pcie_ep -> phy );
284
350
err_disable_clk :
@@ -289,6 +355,7 @@ static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep)
289
355
290
356
static void qcom_pcie_disable_resources (struct qcom_pcie_ep * pcie_ep )
291
357
{
358
+ icc_set_bw (pcie_ep -> icc_mem , 0 , 0 );
292
359
phy_power_off (pcie_ep -> phy );
293
360
phy_exit (pcie_ep -> phy );
294
361
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,
550
617
if (IS_ERR (pcie_ep -> phy ))
551
618
ret = PTR_ERR (pcie_ep -> phy );
552
619
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
+
553
624
return ret ;
554
625
}
555
626
@@ -573,6 +644,7 @@ static irqreturn_t qcom_pcie_ep_global_irq_thread(int irq, void *data)
573
644
} else if (FIELD_GET (PARF_INT_ALL_BME , status )) {
574
645
dev_dbg (dev , "Received BME event. Link is enabled!\n" );
575
646
pcie_ep -> link_status = QCOM_PCIE_EP_LINK_ENABLED ;
647
+ qcom_pcie_ep_icc_update (pcie_ep );
576
648
pci_epc_bme_notify (pci -> ep .epc );
577
649
} else if (FIELD_GET (PARF_INT_ALL_PM_TURNOFF , status )) {
578
650
dev_dbg (dev , "Received PM Turn-off event! Entering L23\n" );
0 commit comments