Skip to content

Commit bea46b9

Browse files
Sandeep Maheswaramfelipebalbi
authored andcommitted
usb: dwc3: qcom: Add interconnect support in dwc3 driver
Add interconnect support in dwc3-qcom driver to vote for bus bandwidth. This requires for two different paths - from USB to DDR. The other is from APPS to USB. Reviewed-by: Matthias Kaehlcke <[email protected]> Signed-off-by: Sandeep Maheswaram <[email protected]> Signed-off-by: Chandana Kishori Chiluveru <[email protected]> Signed-off-by: Felipe Balbi <[email protected]>
1 parent 072f34c commit bea46b9

File tree

1 file changed

+118
-2
lines changed

1 file changed

+118
-2
lines changed

drivers/usb/dwc3/dwc3-qcom.c

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/module.h>
1414
#include <linux/kernel.h>
1515
#include <linux/extcon.h>
16+
#include <linux/interconnect.h>
1617
#include <linux/of_platform.h>
1718
#include <linux/platform_device.h>
1819
#include <linux/phy/phy.h>
@@ -43,6 +44,14 @@
4344
#define SDM845_QSCRATCH_SIZE 0x400
4445
#define SDM845_DWC3_CORE_SIZE 0xcd00
4546

47+
/* Interconnect path bandwidths in MBps */
48+
#define USB_MEMORY_AVG_HS_BW MBps_to_icc(240)
49+
#define USB_MEMORY_PEAK_HS_BW MBps_to_icc(700)
50+
#define USB_MEMORY_AVG_SS_BW MBps_to_icc(1000)
51+
#define USB_MEMORY_PEAK_SS_BW MBps_to_icc(2500)
52+
#define APPS_USB_AVG_BW 0
53+
#define APPS_USB_PEAK_BW MBps_to_icc(40)
54+
4655
struct dwc3_acpi_pdata {
4756
u32 qscratch_base_offset;
4857
u32 qscratch_base_size;
@@ -76,6 +85,8 @@ struct dwc3_qcom {
7685
enum usb_dr_mode mode;
7786
bool is_suspended;
7887
bool pm_suspended;
88+
struct icc_path *icc_path_ddr;
89+
struct icc_path *icc_path_apps;
7990
};
8091

8192
static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
@@ -190,6 +201,96 @@ static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
190201
return 0;
191202
}
192203

204+
static int dwc3_qcom_interconnect_enable(struct dwc3_qcom *qcom)
205+
{
206+
int ret;
207+
208+
ret = icc_enable(qcom->icc_path_ddr);
209+
if (ret)
210+
return ret;
211+
212+
ret = icc_enable(qcom->icc_path_apps);
213+
if (ret)
214+
icc_disable(qcom->icc_path_ddr);
215+
216+
return ret;
217+
}
218+
219+
static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom)
220+
{
221+
int ret;
222+
223+
ret = icc_disable(qcom->icc_path_ddr);
224+
if (ret)
225+
return ret;
226+
227+
ret = icc_disable(qcom->icc_path_apps);
228+
if (ret)
229+
icc_enable(qcom->icc_path_ddr);
230+
231+
return ret;
232+
}
233+
234+
/**
235+
* dwc3_qcom_interconnect_init() - Get interconnect path handles
236+
* and set bandwidhth.
237+
* @qcom: Pointer to the concerned usb core.
238+
*
239+
*/
240+
static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
241+
{
242+
struct device *dev = qcom->dev;
243+
int ret;
244+
245+
qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
246+
if (IS_ERR(qcom->icc_path_ddr)) {
247+
dev_err(dev, "failed to get usb-ddr path: %ld\n",
248+
PTR_ERR(qcom->icc_path_ddr));
249+
return PTR_ERR(qcom->icc_path_ddr);
250+
}
251+
252+
qcom->icc_path_apps = of_icc_get(dev, "apps-usb");
253+
if (IS_ERR(qcom->icc_path_apps)) {
254+
dev_err(dev, "failed to get apps-usb path: %ld\n",
255+
PTR_ERR(qcom->icc_path_apps));
256+
return PTR_ERR(qcom->icc_path_apps);
257+
}
258+
259+
if (usb_get_maximum_speed(&qcom->dwc3->dev) >= USB_SPEED_SUPER ||
260+
usb_get_maximum_speed(&qcom->dwc3->dev) == USB_SPEED_UNKNOWN)
261+
ret = icc_set_bw(qcom->icc_path_ddr,
262+
USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
263+
else
264+
ret = icc_set_bw(qcom->icc_path_ddr,
265+
USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW);
266+
267+
if (ret) {
268+
dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
269+
return ret;
270+
}
271+
272+
ret = icc_set_bw(qcom->icc_path_apps,
273+
APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
274+
if (ret) {
275+
dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
276+
return ret;
277+
}
278+
279+
return 0;
280+
}
281+
282+
/**
283+
* dwc3_qcom_interconnect_exit() - Release interconnect path handles
284+
* @qcom: Pointer to the concerned usb core.
285+
*
286+
* This function is used to release interconnect path handle.
287+
*/
288+
static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
289+
{
290+
icc_put(qcom->icc_path_ddr);
291+
icc_put(qcom->icc_path_apps);
292+
}
293+
193294
static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
194295
{
195296
if (qcom->hs_phy_irq) {
@@ -239,7 +340,7 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
239340
static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
240341
{
241342
u32 val;
242-
int i;
343+
int i, ret;
243344

244345
if (qcom->is_suspended)
245346
return 0;
@@ -251,6 +352,10 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
251352
for (i = qcom->num_clocks - 1; i >= 0; i--)
252353
clk_disable_unprepare(qcom->clks[i]);
253354

355+
ret = dwc3_qcom_interconnect_disable(qcom);
356+
if (ret)
357+
dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
358+
254359
qcom->is_suspended = true;
255360
dwc3_qcom_enable_interrupts(qcom);
256361

@@ -276,6 +381,10 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom)
276381
}
277382
}
278383

384+
ret = dwc3_qcom_interconnect_enable(qcom);
385+
if (ret)
386+
dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
387+
279388
/* Clear existing events from PHY related to L2 in/out */
280389
dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG,
281390
PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
@@ -638,6 +747,10 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
638747
goto depopulate;
639748
}
640749

750+
ret = dwc3_qcom_interconnect_init(qcom);
751+
if (ret)
752+
goto depopulate;
753+
641754
qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
642755

643756
/* enable vbus override for device mode */
@@ -647,7 +760,7 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
647760
/* register extcon to override sw_vbus on Vbus change later */
648761
ret = dwc3_qcom_register_extcon(qcom);
649762
if (ret)
650-
goto depopulate;
763+
goto interconnect_exit;
651764

652765
device_init_wakeup(&pdev->dev, 1);
653766
qcom->is_suspended = false;
@@ -657,6 +770,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
657770

658771
return 0;
659772

773+
interconnect_exit:
774+
dwc3_qcom_interconnect_exit(qcom);
660775
depopulate:
661776
if (np)
662777
of_platform_depopulate(&pdev->dev);
@@ -687,6 +802,7 @@ static int dwc3_qcom_remove(struct platform_device *pdev)
687802
}
688803
qcom->num_clocks = 0;
689804

805+
dwc3_qcom_interconnect_exit(qcom);
690806
reset_control_assert(qcom->resets);
691807

692808
pm_runtime_allow(dev);

0 commit comments

Comments
 (0)