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>
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+
4655struct 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
8192static 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+
193294static 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)
239340static 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 );
660775depopulate :
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