aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc2/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc2/core.c')
-rw-r--r--drivers/usb/dwc2/core.c414
1 files changed, 413 insertions, 1 deletions
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index d5197d492e21..c3cc1a78d1e2 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -56,6 +56,364 @@
56#include "core.h" 56#include "core.h"
57#include "hcd.h" 57#include "hcd.h"
58 58
59#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
60/**
61 * dwc2_backup_host_registers() - Backup controller host registers.
62 * When suspending usb bus, registers needs to be backuped
63 * if controller power is disabled once suspended.
64 *
65 * @hsotg: Programming view of the DWC_otg controller
66 */
67static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
68{
69 struct dwc2_hregs_backup *hr;
70 int i;
71
72 dev_dbg(hsotg->dev, "%s\n", __func__);
73
74 /* Backup Host regs */
75 hr = &hsotg->hr_backup;
76 hr->hcfg = readl(hsotg->regs + HCFG);
77 hr->haintmsk = readl(hsotg->regs + HAINTMSK);
78 for (i = 0; i < hsotg->core_params->host_channels; ++i)
79 hr->hcintmsk[i] = readl(hsotg->regs + HCINTMSK(i));
80
81 hr->hprt0 = readl(hsotg->regs + HPRT0);
82 hr->hfir = readl(hsotg->regs + HFIR);
83 hr->valid = true;
84
85 return 0;
86}
87
88/**
89 * dwc2_restore_host_registers() - Restore controller host registers.
90 * When resuming usb bus, device registers needs to be restored
91 * if controller power were disabled.
92 *
93 * @hsotg: Programming view of the DWC_otg controller
94 */
95static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
96{
97 struct dwc2_hregs_backup *hr;
98 int i;
99
100 dev_dbg(hsotg->dev, "%s\n", __func__);
101
102 /* Restore host regs */
103 hr = &hsotg->hr_backup;
104 if (!hr->valid) {
105 dev_err(hsotg->dev, "%s: no host registers to restore\n",
106 __func__);
107 return -EINVAL;
108 }
109 hr->valid = false;
110
111 writel(hr->hcfg, hsotg->regs + HCFG);
112 writel(hr->haintmsk, hsotg->regs + HAINTMSK);
113
114 for (i = 0; i < hsotg->core_params->host_channels; ++i)
115 writel(hr->hcintmsk[i], hsotg->regs + HCINTMSK(i));
116
117 writel(hr->hprt0, hsotg->regs + HPRT0);
118 writel(hr->hfir, hsotg->regs + HFIR);
119
120 return 0;
121}
122#else
123static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
124{ return 0; }
125
126static inline int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
127{ return 0; }
128#endif
129
130#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
131 IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
132/**
133 * dwc2_backup_device_registers() - Backup controller device registers.
134 * When suspending usb bus, registers needs to be backuped
135 * if controller power is disabled once suspended.
136 *
137 * @hsotg: Programming view of the DWC_otg controller
138 */
139static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
140{
141 struct dwc2_dregs_backup *dr;
142 int i;
143
144 dev_dbg(hsotg->dev, "%s\n", __func__);
145
146 /* Backup dev regs */
147 dr = &hsotg->dr_backup;
148
149 dr->dcfg = readl(hsotg->regs + DCFG);
150 dr->dctl = readl(hsotg->regs + DCTL);
151 dr->daintmsk = readl(hsotg->regs + DAINTMSK);
152 dr->diepmsk = readl(hsotg->regs + DIEPMSK);
153 dr->doepmsk = readl(hsotg->regs + DOEPMSK);
154
155 for (i = 0; i < hsotg->num_of_eps; i++) {
156 /* Backup IN EPs */
157 dr->diepctl[i] = readl(hsotg->regs + DIEPCTL(i));
158
159 /* Ensure DATA PID is correctly configured */
160 if (dr->diepctl[i] & DXEPCTL_DPID)
161 dr->diepctl[i] |= DXEPCTL_SETD1PID;
162 else
163 dr->diepctl[i] |= DXEPCTL_SETD0PID;
164
165 dr->dieptsiz[i] = readl(hsotg->regs + DIEPTSIZ(i));
166 dr->diepdma[i] = readl(hsotg->regs + DIEPDMA(i));
167
168 /* Backup OUT EPs */
169 dr->doepctl[i] = readl(hsotg->regs + DOEPCTL(i));
170
171 /* Ensure DATA PID is correctly configured */
172 if (dr->doepctl[i] & DXEPCTL_DPID)
173 dr->doepctl[i] |= DXEPCTL_SETD1PID;
174 else
175 dr->doepctl[i] |= DXEPCTL_SETD0PID;
176
177 dr->doeptsiz[i] = readl(hsotg->regs + DOEPTSIZ(i));
178 dr->doepdma[i] = readl(hsotg->regs + DOEPDMA(i));
179 }
180 dr->valid = true;
181 return 0;
182}
183
184/**
185 * dwc2_restore_device_registers() - Restore controller device registers.
186 * When resuming usb bus, device registers needs to be restored
187 * if controller power were disabled.
188 *
189 * @hsotg: Programming view of the DWC_otg controller
190 */
191static int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
192{
193 struct dwc2_dregs_backup *dr;
194 u32 dctl;
195 int i;
196
197 dev_dbg(hsotg->dev, "%s\n", __func__);
198
199 /* Restore dev regs */
200 dr = &hsotg->dr_backup;
201 if (!dr->valid) {
202 dev_err(hsotg->dev, "%s: no device registers to restore\n",
203 __func__);
204 return -EINVAL;
205 }
206 dr->valid = false;
207
208 writel(dr->dcfg, hsotg->regs + DCFG);
209 writel(dr->dctl, hsotg->regs + DCTL);
210 writel(dr->daintmsk, hsotg->regs + DAINTMSK);
211 writel(dr->diepmsk, hsotg->regs + DIEPMSK);
212 writel(dr->doepmsk, hsotg->regs + DOEPMSK);
213
214 for (i = 0; i < hsotg->num_of_eps; i++) {
215 /* Restore IN EPs */
216 writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
217 writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i));
218 writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i));
219
220 /* Restore OUT EPs */
221 writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
222 writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
223 writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
224 }
225
226 /* Set the Power-On Programming done bit */
227 dctl = readl(hsotg->regs + DCTL);
228 dctl |= DCTL_PWRONPRGDONE;
229 writel(dctl, hsotg->regs + DCTL);
230
231 return 0;
232}
233#else
234static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
235{ return 0; }
236
237static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
238{ return 0; }
239#endif
240
241/**
242 * dwc2_backup_global_registers() - Backup global controller registers.
243 * When suspending usb bus, registers needs to be backuped
244 * if controller power is disabled once suspended.
245 *
246 * @hsotg: Programming view of the DWC_otg controller
247 */
248static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
249{
250 struct dwc2_gregs_backup *gr;
251 int i;
252
253 /* Backup global regs */
254 gr = &hsotg->gr_backup;
255
256 gr->gotgctl = readl(hsotg->regs + GOTGCTL);
257 gr->gintmsk = readl(hsotg->regs + GINTMSK);
258 gr->gahbcfg = readl(hsotg->regs + GAHBCFG);
259 gr->gusbcfg = readl(hsotg->regs + GUSBCFG);
260 gr->grxfsiz = readl(hsotg->regs + GRXFSIZ);
261 gr->gnptxfsiz = readl(hsotg->regs + GNPTXFSIZ);
262 gr->hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
263 gr->gdfifocfg = readl(hsotg->regs + GDFIFOCFG);
264 for (i = 0; i < MAX_EPS_CHANNELS; i++)
265 gr->dtxfsiz[i] = readl(hsotg->regs + DPTXFSIZN(i));
266
267 gr->valid = true;
268 return 0;
269}
270
271/**
272 * dwc2_restore_global_registers() - Restore controller global registers.
273 * When resuming usb bus, device registers needs to be restored
274 * if controller power were disabled.
275 *
276 * @hsotg: Programming view of the DWC_otg controller
277 */
278static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
279{
280 struct dwc2_gregs_backup *gr;
281 int i;
282
283 dev_dbg(hsotg->dev, "%s\n", __func__);
284
285 /* Restore global regs */
286 gr = &hsotg->gr_backup;
287 if (!gr->valid) {
288 dev_err(hsotg->dev, "%s: no global registers to restore\n",
289 __func__);
290 return -EINVAL;
291 }
292 gr->valid = false;
293
294 writel(0xffffffff, hsotg->regs + GINTSTS);
295 writel(gr->gotgctl, hsotg->regs + GOTGCTL);
296 writel(gr->gintmsk, hsotg->regs + GINTMSK);
297 writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
298 writel(gr->gahbcfg, hsotg->regs + GAHBCFG);
299 writel(gr->grxfsiz, hsotg->regs + GRXFSIZ);
300 writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ);
301 writel(gr->hptxfsiz, hsotg->regs + HPTXFSIZ);
302 writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG);
303 for (i = 0; i < MAX_EPS_CHANNELS; i++)
304 writel(gr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
305
306 return 0;
307}
308
309/**
310 * dwc2_exit_hibernation() - Exit controller from Partial Power Down.
311 *
312 * @hsotg: Programming view of the DWC_otg controller
313 * @restore: Controller registers need to be restored
314 */
315int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
316{
317 u32 pcgcctl;
318 int ret = 0;
319
320 if (!hsotg->core_params->hibernation)
321 return -ENOTSUPP;
322
323 pcgcctl = readl(hsotg->regs + PCGCTL);
324 pcgcctl &= ~PCGCTL_STOPPCLK;
325 writel(pcgcctl, hsotg->regs + PCGCTL);
326
327 pcgcctl = readl(hsotg->regs + PCGCTL);
328 pcgcctl &= ~PCGCTL_PWRCLMP;
329 writel(pcgcctl, hsotg->regs + PCGCTL);
330
331 pcgcctl = readl(hsotg->regs + PCGCTL);
332 pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
333 writel(pcgcctl, hsotg->regs + PCGCTL);
334
335 udelay(100);
336 if (restore) {
337 ret = dwc2_restore_global_registers(hsotg);
338 if (ret) {
339 dev_err(hsotg->dev, "%s: failed to restore registers\n",
340 __func__);
341 return ret;
342 }
343 if (dwc2_is_host_mode(hsotg)) {
344 ret = dwc2_restore_host_registers(hsotg);
345 if (ret) {
346 dev_err(hsotg->dev, "%s: failed to restore host registers\n",
347 __func__);
348 return ret;
349 }
350 } else {
351 ret = dwc2_restore_device_registers(hsotg);
352 if (ret) {
353 dev_err(hsotg->dev, "%s: failed to restore device registers\n",
354 __func__);
355 return ret;
356 }
357 }
358 }
359
360 return ret;
361}
362
363/**
364 * dwc2_enter_hibernation() - Put controller in Partial Power Down.
365 *
366 * @hsotg: Programming view of the DWC_otg controller
367 */
368int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
369{
370 u32 pcgcctl;
371 int ret = 0;
372
373 if (!hsotg->core_params->hibernation)
374 return -ENOTSUPP;
375
376 /* Backup all registers */
377 ret = dwc2_backup_global_registers(hsotg);
378 if (ret) {
379 dev_err(hsotg->dev, "%s: failed to backup global registers\n",
380 __func__);
381 return ret;
382 }
383
384 if (dwc2_is_host_mode(hsotg)) {
385 ret = dwc2_backup_host_registers(hsotg);
386 if (ret) {
387 dev_err(hsotg->dev, "%s: failed to backup host registers\n",
388 __func__);
389 return ret;
390 }
391 } else {
392 ret = dwc2_backup_device_registers(hsotg);
393 if (ret) {
394 dev_err(hsotg->dev, "%s: failed to backup device registers\n",
395 __func__);
396 return ret;
397 }
398 }
399
400 /* Put the controller in low power state */
401 pcgcctl = readl(hsotg->regs + PCGCTL);
402
403 pcgcctl |= PCGCTL_PWRCLMP;
404 writel(pcgcctl, hsotg->regs + PCGCTL);
405 ndelay(20);
406
407 pcgcctl |= PCGCTL_RSTPDWNMODULE;
408 writel(pcgcctl, hsotg->regs + PCGCTL);
409 ndelay(20);
410
411 pcgcctl |= PCGCTL_STOPPCLK;
412 writel(pcgcctl, hsotg->regs + PCGCTL);
413
414 return ret;
415}
416
59/** 417/**
60 * dwc2_enable_common_interrupts() - Initializes the commmon interrupts, 418 * dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
61 * used in both device and host modes 419 * used in both device and host modes
@@ -77,8 +435,10 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
77 435
78 if (hsotg->core_params->dma_enable <= 0) 436 if (hsotg->core_params->dma_enable <= 0)
79 intmsk |= GINTSTS_RXFLVL; 437 intmsk |= GINTSTS_RXFLVL;
438 if (hsotg->core_params->external_id_pin_ctl <= 0)
439 intmsk |= GINTSTS_CONIDSTSCHNG;
80 440
81 intmsk |= GINTSTS_CONIDSTSCHNG | GINTSTS_WKUPINT | GINTSTS_USBSUSP | 441 intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP |
82 GINTSTS_SESSREQINT; 442 GINTSTS_SESSREQINT;
83 443
84 writel(intmsk, hsotg->regs + GINTMSK); 444 writel(intmsk, hsotg->regs + GINTMSK);
@@ -2602,6 +2962,40 @@ static void dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val)
2602 hsotg->core_params->uframe_sched = val; 2962 hsotg->core_params->uframe_sched = val;
2603} 2963}
2604 2964
2965static void dwc2_set_param_external_id_pin_ctl(struct dwc2_hsotg *hsotg,
2966 int val)
2967{
2968 if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
2969 if (val >= 0) {
2970 dev_err(hsotg->dev,
2971 "'%d' invalid for parameter external_id_pin_ctl\n",
2972 val);
2973 dev_err(hsotg->dev, "external_id_pin_ctl must be 0 or 1\n");
2974 }
2975 val = 0;
2976 dev_dbg(hsotg->dev, "Setting external_id_pin_ctl to %d\n", val);
2977 }
2978
2979 hsotg->core_params->external_id_pin_ctl = val;
2980}
2981
2982static void dwc2_set_param_hibernation(struct dwc2_hsotg *hsotg,
2983 int val)
2984{
2985 if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
2986 if (val >= 0) {
2987 dev_err(hsotg->dev,
2988 "'%d' invalid for parameter hibernation\n",
2989 val);
2990 dev_err(hsotg->dev, "hibernation must be 0 or 1\n");
2991 }
2992 val = 0;
2993 dev_dbg(hsotg->dev, "Setting hibernation to %d\n", val);
2994 }
2995
2996 hsotg->core_params->hibernation = val;
2997}
2998
2605/* 2999/*
2606 * This function is called during module intialization to pass module parameters 3000 * This function is called during module intialization to pass module parameters
2607 * for the DWC_otg core. 3001 * for the DWC_otg core.
@@ -2646,6 +3040,8 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
2646 dwc2_set_param_ahbcfg(hsotg, params->ahbcfg); 3040 dwc2_set_param_ahbcfg(hsotg, params->ahbcfg);
2647 dwc2_set_param_otg_ver(hsotg, params->otg_ver); 3041 dwc2_set_param_otg_ver(hsotg, params->otg_ver);
2648 dwc2_set_param_uframe_sched(hsotg, params->uframe_sched); 3042 dwc2_set_param_uframe_sched(hsotg, params->uframe_sched);
3043 dwc2_set_param_external_id_pin_ctl(hsotg, params->external_id_pin_ctl);
3044 dwc2_set_param_hibernation(hsotg, params->hibernation);
2649} 3045}
2650 3046
2651/** 3047/**
@@ -2814,6 +3210,22 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
2814 return 0; 3210 return 0;
2815} 3211}
2816 3212
3213/*
3214 * Sets all parameters to the given value.
3215 *
3216 * Assumes that the dwc2_core_params struct contains only integers.
3217 */
3218void dwc2_set_all_params(struct dwc2_core_params *params, int value)
3219{
3220 int *p = (int *)params;
3221 size_t size = sizeof(*params) / sizeof(*p);
3222 int i;
3223
3224 for (i = 0; i < size; i++)
3225 p[i] = value;
3226}
3227
3228
2817u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg) 3229u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg)
2818{ 3230{
2819 return hsotg->core_params->otg_ver == 1 ? 0x0200 : 0x0103; 3231 return hsotg->core_params->otg_ver == 1 ? 0x0200 : 0x0103;