1 /* ==========================================================================
2 * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
7 * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
8 * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
9 * otherwise expressly agreed to in writing between Synopsys and you.
11 * The Software IS NOT an item of Licensed Software or Licensed Product under
12 * any End User Software License Agreement or Agreement for Licensed Product
13 * with Synopsys or any supplement thereto. You are permitted to use and
14 * redistribute this Software in source and binary forms, with or without
15 * modification, provided that redistributions of source code must retain this
16 * notice. You may not view, use, disclose, copy or distribute this file or
17 * any information contained herein except pursuant to this license grant from
18 * Synopsys. If you do not agree with this notice, including the disclaimer
19 * below, then you are not authorized to use the Software.
21 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32 * ========================================================================== */
36 * The Core Interface Layer provides basic services for accessing and
37 * managing the DWC_otg hardware. These services are used by both the
38 * Host Controller Driver and the Peripheral Controller Driver.
40 * This file contains the Common Interrupt handlers.
42 #include "common_port/dwc_os.h"
43 #include "dwc_otg_regs.h"
44 #include "dwc_otg_cil.h"
45 #include "dwc_otg_driver.h"
46 #include "dwc_otg_pcd.h"
47 #include "dwc_otg_hcd.h"
48 #include "usbdev_rk.h"
51 inline const char *op_state_str(dwc_otg_core_if_t *core_if)
53 return (core_if->op_state == A_HOST ? "a_host" :
54 (core_if->op_state == A_SUSPEND ? "a_suspend" :
55 (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
56 (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
57 (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
61 /** This function will log a debug message
63 * @param core_if Programming view of DWC_otg controller.
65 int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t *core_if)
67 gintsts_data_t gintsts;
68 DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
69 dwc_otg_mode(core_if) ? "Host" : "Device");
73 gintsts.b.modemismatch = 1;
74 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
79 * This function handles the OTG Interrupts. It reads the OTG
80 * Interrupt Register (GOTGINT) to determine what interrupt has
83 * @param core_if Programming view of DWC_otg controller.
85 int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *core_if)
87 dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
88 gotgint_data_t gotgint;
89 gotgctl_data_t gotgctl;
90 gintmsk_data_t gintmsk;
92 dctl_data_t dctl = {.d32 = 0 };
94 gotgint.d32 = DWC_READ_REG32(&global_regs->gotgint);
95 gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
96 DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
97 op_state_str(core_if));
99 if (gotgint.b.sesenddet) {
100 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
101 "Session End Detected++ (%s)\n",
102 op_state_str(core_if));
104 /* do soft disconnect */
106 DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl);
107 dctl.b.sftdiscon = 1;
108 DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl,
110 dwc_otg_disable_global_interrupts(core_if);
111 core_if->otg_dev->pcd->vbus_status = USB_BC_TYPE_DISCNT;
113 DWC_PRINTF("********session end ,soft disconnect***********\n");
115 gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
117 if (core_if->op_state == B_HOST) {
118 cil_pcd_start(core_if);
119 core_if->op_state = B_PERIPHERAL;
121 /* If not B_HOST and Device HNP still set. HNP
123 if (gotgctl.b.devhnpen) {
124 DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
126 ("Device Not Connected/Responding!\n");
129 /* If Session End Detected the B-Cable has
130 * been disconnected. */
131 /* Reset PCD and Gadget driver to a
133 core_if->lx_state = DWC_OTG_L0;
134 DWC_SPINUNLOCK(core_if->lock);
135 cil_pcd_stop(core_if);
136 DWC_SPINLOCK(core_if->lock);
138 if (core_if->otg_ver) {
141 gotgctl.b.devhnpen = 1;
142 DWC_MODIFY_REG32(&global_regs->gotgctl,
144 if (core_if->test_mode == 6) {
145 /* manukz: old value was 50 */
146 DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
147 dwc_otg_initiate_srp,
150 core_if->test_mode = 0;
151 } else if (core_if->adp_enable) {
152 if (core_if->power_down == 2) {
154 gpwrdn.b.pwrdnswtch = 1;
156 (&core_if->core_global_regs->gpwrdn,
161 gpwrdn.b.pmuintsel = 1;
162 gpwrdn.b.pmuactv = 1;
163 DWC_MODIFY_REG32(&core_if->
165 gpwrdn, 0, gpwrdn.d32);
166 dwc_otg_adp_sense_start(core_if);
170 if (core_if->otg_ver == 0) {
172 gotgctl.b.devhnpen = 1;
173 DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
176 if (gotgint.b.sesreqsucstschng) {
177 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
178 "Session Reqeust Success Status Change++\n");
179 gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
180 if (gotgctl.b.sesreqscs) {
182 if ((core_if->core_params->phy_type ==
183 DWC_PHY_TYPE_PARAM_FS)
184 && (core_if->core_params->i2c_enable)) {
185 core_if->srp_success = 1;
187 DWC_SPINUNLOCK(core_if->lock);
188 cil_pcd_resume(core_if);
189 DWC_SPINLOCK(core_if->lock);
190 /* Clear Session Request */
192 gotgctl.b.sesreq = 1;
193 DWC_MODIFY_REG32(&global_regs->gotgctl,
198 if (gotgint.b.hstnegsucstschng) {
199 /* Print statements during the HNP interrupt handling
200 * can cause it to fail.*/
201 gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
202 /* WA for 3.00a- HW is not setting cur_mode, even sometimes
203 * this does not help*/
204 if (core_if->snpsid >= OTG_CORE_REV_3_00a)
206 if (gotgctl.b.hstnegscs) {
207 if (dwc_otg_is_host_mode(core_if)) {
208 core_if->op_state = B_HOST;
210 * Need to disable SOF interrupt immediately.
211 * When switching from device to host, the PCD
212 * interrupt handler won't handle the
213 * interrupt if host mode is already set. The
214 * HCD interrupt handler won't get called if
215 * the HCD state is HALT. This means that the
216 * interrupt does not get handled and Linux
220 gintmsk.b.sofintr = 1;
221 /* gintmsk.b.usbsuspend = 1; */
222 DWC_MODIFY_REG32(&global_regs->gintmsk,
224 /* Call callback function with spin lock released */
225 DWC_SPINUNLOCK(core_if->lock);
226 cil_pcd_stop(core_if);
228 * Initialize the Core for Host mode.
230 cil_hcd_start(core_if);
231 DWC_SPINLOCK(core_if->lock);
235 gotgctl.b.hnpreq = 1;
236 gotgctl.b.devhnpen = 1;
237 DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
238 DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
239 __DWC_ERROR("Device Not Connected/Responding\n");
242 if (gotgint.b.hstnegdet) {
243 /* The disconnect interrupt is set at the same time as
244 * Host Negotiation Detected. During the mode
245 * switch all interrupts are cleared so the disconnect
246 * interrupt handler will not get executed.
248 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
249 "Host Negotiation Detected++ (%s)\n",
250 (dwc_otg_is_host_mode(core_if) ? "Host" :
252 if (dwc_otg_is_device_mode(core_if)) {
253 DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
255 DWC_SPINUNLOCK(core_if->lock);
256 cil_hcd_disconnect(core_if);
257 cil_pcd_start(core_if);
258 DWC_SPINLOCK(core_if->lock);
259 core_if->op_state = A_PERIPHERAL;
262 * Need to disable SOF interrupt immediately. When
263 * switching from device to host, the PCD interrupt
264 * handler won't handle the interrupt if host mode is
265 * already set. The HCD interrupt handler won't get
266 * called if the HCD state is HALT. This means that
267 * the interrupt does not get handled and Linux
271 gintmsk.b.sofintr = 1;
272 DWC_MODIFY_REG32(&global_regs->gintmsk, gintmsk.d32, 0);
273 DWC_SPINUNLOCK(core_if->lock);
274 cil_pcd_stop(core_if);
275 cil_hcd_start(core_if);
276 DWC_SPINLOCK(core_if->lock);
277 core_if->op_state = A_HOST;
280 if (gotgint.b.adevtoutchng) {
281 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
282 "A-Device Timeout Change++\n");
284 if (gotgint.b.debdone) {
285 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
286 /* Need to power off VBUS after 10s if OTG2 non-hnp capable host */
287 if (core_if->otg_ver == 1)
288 cil_hcd_session_start(core_if);
292 DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
297 void w_conn_id_status_change(void *p)
299 dwc_otg_core_if_t *core_if = p;
301 gotgctl_data_t gotgctl = {.d32 = 0 };
302 dwc_otg_pcd_t *pcd = core_if->otg_dev->pcd;
304 gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
305 DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
306 DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
308 /* B-Device connector (Device Mode) */
309 if (gotgctl.b.conidsts) {
310 gotgctl_data_t gotgctl_local;
312 /* Wait for switch to device mode. */
313 while (!dwc_otg_is_device_mode(core_if)) {
315 DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
317 "Waiting for Peripheral Mode, Mode=%s count = %d gotgctl=%08x\n",
318 (dwc_otg_is_host_mode(core_if) ? "Host" :
319 "Peripheral"), count, gotgctl_local.d32);
320 dwc_mdelay(1); /* vahrama previous value was 100 */
321 if (!gotgctl_local.b.conidsts)
326 DWC_ASSERT(++count < 10000,
327 "Connection id status change timed out");
328 core_if->op_state = B_PERIPHERAL;
329 cil_hcd_stop(core_if);;
330 /* pcd->phy_suspend = 1; */
331 pcd->vbus_status = 0;
332 dwc_otg_pcd_start_check_vbus_work(pcd);
333 if (core_if->otg_ver == 0)
334 dwc_otg_core_init(core_if);
335 dwc_otg_enable_global_interrupts(core_if);
336 cil_pcd_start(core_if);
339 /* A-Device connector (Host Mode) */
340 while (!dwc_otg_is_host_mode(core_if)) {
341 DWC_DEBUGPL(DBG_ANY, "Waiting for Host Mode, Mode=%s\n",
342 (dwc_otg_is_host_mode(core_if) ? "Host" :
344 dwc_mdelay(1); /* vahrama previously was 100 */
348 DWC_ASSERT(++count < 10000,
349 "Connection id status change timed out");
350 core_if->op_state = A_HOST;
352 cancel_delayed_work(&pcd->check_vbus_work);
355 * Initialize the Core for Host mode.
357 if (core_if->otg_ver)
358 /* To power off the bus in 10s from the beginning
359 * of test while denounce has not come yet */
360 cil_hcd_session_start(core_if);
362 dwc_otg_core_init(core_if);
363 dwc_otg_enable_global_interrupts(core_if);
364 cil_hcd_start(core_if);
369 * This function handles the Connector ID Status Change Interrupt. It
370 * reads the OTG Interrupt Register (GOTCTL) to determine whether this
371 * is a Device to Host Mode transition or a Host Mode to Device
374 * This only occurs when the cable is connected/removed from the PHY
377 * @param core_if Programming view of DWC_otg controller.
379 int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *core_if)
383 * Need to disable SOF interrupt immediately. If switching from device
384 * to host, the PCD interrupt handler won't handle the interrupt if
385 * host mode is already set. The HCD interrupt handler won't get
386 * called if the HCD state is HALT. This means that the interrupt does
387 * not get handled and Linux complains loudly.
389 gintmsk_data_t gintmsk = {.d32 = 0 };
390 gintsts_data_t gintsts = {.d32 = 0 };
392 dwc_otg_disable_host_interrupts(core_if);
393 if (core_if->usb_mode != USB_MODE_NORMAL)
396 gintmsk.b.sofintr = 1;
397 DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
399 " ++Connector ID Status Change Interrupt++ (%s)\n",
400 (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
402 DWC_SPINUNLOCK(core_if->lock);
405 * Need to schedule a work, as there are possible DELAY function calls
406 * Release lock before scheduling workq as it holds spinlock during scheduling
409 /*DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
410 core_if, "connection id status change");*/
411 DWC_SPINLOCK(core_if->lock);
413 /* Set flag and clear interrupt */
414 gintsts.b.conidstschng = 1;
415 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
421 * This interrupt indicates that a device is initiating the Session
422 * Request Protocol to request the host to turn on bus power so a new
423 * session can begin. The handler responds by turning on bus power. If
424 * the DWC_otg controller is in low power mode, the handler brings the
425 * controller out of low power mode before turning on bus power.
427 * @param core_if Programming view of DWC_otg controller.
429 int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t *core_if)
431 gintsts_data_t gintsts;
433 #ifndef DWC_HOST_ONLY
434 DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
435 if (dwc_otg_is_device_mode(core_if)) {
436 gotgctl_data_t gotgctl = {.d32 = 0 };
437 DWC_PRINTF("SRP: Device mode\n");
439 DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
440 if (gotgctl.b.sesreqscs)
441 DWC_PRINTF("SRP Success\n");
443 DWC_PRINTF("SRP Fail\n");
444 if (core_if->otg_ver) {
446 gotgctl.b.devhnpen = 1;
447 DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
452 DWC_PRINTF("SRP: Host mode\n");
454 /* Turn on the port power bit. */
455 hprt0.d32 = dwc_otg_read_hprt0(core_if);
457 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
459 /* Start the Connection timer. So a message can be displayed
460 * if connect does not occur within 10 seconds. */
461 cil_hcd_session_start(core_if);
465 /* Clear interrupt */
467 gintsts.b.sessreqintr = 1;
468 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
473 void w_wakeup_detected(void *data)
475 dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) data;
477 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
478 * so that OPT tests pass with all PHYs).
480 hprt0_data_t hprt0 = {.d32 = 0 };
482 pcgcctl_data_t pcgcctl = {.d32 = 0 };
483 /* Restart the Phy Clock */
484 pcgcctl.b.stoppclk = 1;
485 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
488 hprt0.d32 = dwc_otg_read_hprt0(core_if);
489 DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
491 hprt0.b.prtres = 0; /* Resume */
492 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
493 DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
494 DWC_READ_REG32(core_if->host_if->hprt0));
496 cil_hcd_resume(core_if);
498 /** Change to L0 state*/
499 core_if->lx_state = DWC_OTG_L0;
502 static inline void rk_dwc_otg_phy_soft_reset(dwc_otg_core_if_t *core_if)
504 struct dwc_otg_platform_data *pldata;
507 pldata = core_if->otg_dev->pldata;
508 guid.d32 = core_if->core_global_regs->guid;
510 if ((cpu_is_rk3288()) && ((guid.d32 & 0x01) == 0)) {
511 /* only used for HOST20, OTG HOST do not need.
512 * first, do soft reset usb phy, and then usb phy
513 * can drive resume signal.
514 * second, set usb phy into suspend mode and
515 * normal mode once time, and then usb phy can
516 * send SOFs immediately after resume.
518 rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, true);
520 rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, false);
523 pldata->phy_suspend(pldata, USB_PHY_SUSPEND);
525 pldata->phy_suspend(pldata, USB_PHY_ENABLED);
531 * This interrupt indicates that the DWC_otg controller has detected a
532 * resume or remote wakeup sequence. If the DWC_otg controller is in
533 * low power mode, the handler must brings the controller out of low
534 * power mode. The controller automatically begins resume
535 * signaling. The handler schedules a time to stop resume signaling.
537 int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t *core_if)
539 gintsts_data_t gintsts;
542 "++Resume and Remote Wakeup Detected Interrupt++\n");
544 DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
546 if (dwc_otg_is_device_mode(core_if)) {
547 dctl_data_t dctl = {.d32 = 0 };
548 DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
549 DWC_READ_REG32(&core_if->dev_if->
550 dev_global_regs->dsts));
551 if (core_if->lx_state == DWC_OTG_L2) {
552 #ifdef PARTIAL_POWER_DOWN
553 if (core_if->hwcfg4.b.power_optimiz) {
554 pcgcctl_data_t power = {.d32 = 0 };
556 power.d32 = DWC_READ_REG32(core_if->pcgcctl);
557 DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
560 power.b.stoppclk = 0;
561 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
564 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
566 power.b.rstpdwnmodule = 0;
567 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
570 /* Clear the Remote Wakeup Signaling */
571 dctl.b.rmtwkupsig = 1;
572 DWC_MODIFY_REG32(&core_if->dev_if->
573 dev_global_regs->dctl, dctl.d32, 0);
575 DWC_SPINUNLOCK(core_if->lock);
576 if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
577 core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
580 DWC_SPINLOCK(core_if->lock);
582 glpmcfg_data_t lpmcfg;
583 pcgcctl_data_t pcgcctl = {.d32 = 0 };
586 DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
587 lpmcfg.b.hird_thres &= (~(1 << 4));
588 lpmcfg.b.en_utmi_sleep = 0;
590 /* Clear Enbl_L1Gating bit. */
591 pcgcctl.b.enbl_sleep_gating = 1;
592 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
594 DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
597 /** Change to L0 state*/
598 core_if->lx_state = DWC_OTG_L0;
600 if (core_if->lx_state != DWC_OTG_L1) {
601 pcgcctl_data_t pcgcctl = {.d32 = 0 };
603 /* Restart the Phy Clock */
604 pcgcctl.b.stoppclk = 1;
605 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
608 rk_dwc_otg_phy_soft_reset(core_if);
610 DWC_TASK_SCHEDULE(core_if->wkp_tasklet);
612 /** Change to L0 state*/
613 core_if->lx_state = DWC_OTG_L0;
617 /* Clear interrupt */
619 gintsts.b.wkupintr = 1;
620 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
626 * This interrupt indicates that the Wakeup Logic has detected a
629 static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
631 gpwrdn_data_t gpwrdn = {.d32 = 0 };
632 gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
633 gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
635 DWC_PRINTF("%s called\n", __FUNCTION__);
637 if (!core_if->hibernation_suspend) {
638 DWC_PRINTF("Already exited from Hibernation\n");
642 /* Switch on the voltage to the core */
643 gpwrdn.b.pwrdnswtch = 1;
644 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
649 gpwrdn.b.pwrdnrstn = 1;
650 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
653 /* Disable power clamps */
655 gpwrdn.b.pwrdnclmp = 1;
656 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
658 /* Remove reset the core signal */
660 gpwrdn.b.pwrdnrstn = 1;
661 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
664 /* Disable PMU interrupt */
666 gpwrdn.b.pmuintsel = 1;
667 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
669 core_if->hibernation_suspend = 0;
673 gpwrdn.b.pmuactv = 1;
674 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
677 if (gpwrdn_temp.b.idsts) {
678 core_if->op_state = B_PERIPHERAL;
679 dwc_otg_core_init(core_if);
680 dwc_otg_enable_global_interrupts(core_if);
681 cil_pcd_start(core_if);
683 core_if->op_state = A_HOST;
684 dwc_otg_core_init(core_if);
685 dwc_otg_enable_global_interrupts(core_if);
686 cil_hcd_start(core_if);
693 * This interrupt indicates that the Wakeup Logic has detected a
694 * remote wakeup sequence.
696 static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t *
699 gpwrdn_data_t gpwrdn = {.d32 = 0 };
701 "++Powerdown Remote Wakeup Detected Interrupt++\n");
703 if (!core_if->hibernation_suspend) {
704 DWC_PRINTF("Already exited from Hibernation\n");
708 gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
709 if (gpwrdn.b.idsts) { /* Device Mode */
710 if ((core_if->power_down == 2)
711 && (core_if->hibernation_suspend == 1)) {
712 dwc_otg_device_hibernation_restore(core_if, 0, 0);
715 if ((core_if->power_down == 2)
716 && (core_if->hibernation_suspend == 1)) {
717 dwc_otg_host_hibernation_restore(core_if, 1, 0);
723 static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
725 gpwrdn_data_t gpwrdn = {.d32 = 0 };
726 gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
727 dwc_otg_core_if_t *core_if = otg_dev->core_if;
729 DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
730 gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
731 if (core_if->power_down == 2) {
732 if (!core_if->hibernation_suspend) {
733 DWC_PRINTF("Already exited from Hibernation\n");
737 "Exit from hibernation on ID sts change\n");
738 /* Switch on the voltage to the core */
739 gpwrdn.b.pwrdnswtch = 1;
740 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
746 gpwrdn.b.pwrdnrstn = 1;
747 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
751 /* Disable power clamps */
753 gpwrdn.b.pwrdnclmp = 1;
754 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
757 /* Remove reset the core signal */
759 gpwrdn.b.pwrdnrstn = 1;
760 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
764 /* Disable PMU interrupt */
766 gpwrdn.b.pmuintsel = 1;
767 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
770 /*Indicates that we are exiting from hibernation */
771 core_if->hibernation_suspend = 0;
775 gpwrdn.b.pmuactv = 1;
776 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
780 gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
781 if (gpwrdn.b.dis_vbus == 1) {
783 gpwrdn.b.dis_vbus = 1;
784 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
788 if (gpwrdn_temp.b.idsts) {
789 core_if->op_state = B_PERIPHERAL;
790 dwc_otg_core_init(core_if);
791 dwc_otg_enable_global_interrupts(core_if);
792 cil_pcd_start(core_if);
794 core_if->op_state = A_HOST;
795 dwc_otg_core_init(core_if);
796 dwc_otg_enable_global_interrupts(core_if);
797 cil_hcd_start(core_if);
801 if (core_if->adp_enable) {
803 DWC_SPINUNLOCK(core_if->lock);
804 /* Change the core_if's lock to hcd/pcd lock depend on mode? */
805 #ifndef DWC_HOST_ONLY
806 if (gpwrdn_temp.b.idsts)
807 core_if->lock = otg_dev->pcd->lock;
809 #ifndef DWC_DEVICE_ONLY
810 if (!gpwrdn_temp.b.idsts) {
811 core_if->lock = otg_dev->hcd->lock;
815 DWC_PRINTF("RESTART ADP\n");
816 if (core_if->adp.probe_enabled)
817 dwc_otg_adp_probe_stop(core_if);
818 if (core_if->adp.sense_enabled)
819 dwc_otg_adp_sense_stop(core_if);
820 if (core_if->adp.sense_timer_started)
821 DWC_TIMER_CANCEL(core_if->adp.sense_timer);
822 if (core_if->adp.vbuson_timer_started)
823 DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
824 core_if->adp.probe_timer_values[0] = -1;
825 core_if->adp.probe_timer_values[1] = -1;
826 core_if->adp.sense_timer_started = 0;
827 core_if->adp.vbuson_timer_started = 0;
828 core_if->adp.probe_counter = 0;
829 core_if->adp.gpwrdn = 0;
831 /* Disable PMU and restart ADP */
833 gpwrdn_temp.b.pmuactv = 1;
834 gpwrdn_temp.b.pmuintsel = 1;
835 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
837 DWC_PRINTF("Check point 1\n");
839 dwc_otg_adp_start(core_if, is_host);
840 DWC_SPINLOCK(core_if->lock);
846 static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t *core_if)
848 gpwrdn_data_t gpwrdn = {.d32 = 0 };
849 int32_t otg_cap_param = core_if->core_params->otg_cap;
850 DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
852 gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
853 if (core_if->power_down == 2) {
854 if (!core_if->hibernation_suspend) {
855 DWC_PRINTF("Already exited from Hibernation\n");
859 if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
860 otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
861 gpwrdn.b.bsessvld == 0) {
862 /* Save gpwrdn register for further usage if stschng interrupt */
863 core_if->gr_backup->gpwrdn_local =
864 DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
865 /*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
869 /* Switch on the voltage to the core */
871 gpwrdn.b.pwrdnswtch = 1;
872 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
878 gpwrdn.b.pwrdnrstn = 1;
879 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
883 /* Disable power clamps */
885 gpwrdn.b.pwrdnclmp = 1;
886 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
889 /* Remove reset the core signal */
891 gpwrdn.b.pwrdnrstn = 1;
892 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
896 /* Disable PMU interrupt */
898 gpwrdn.b.pmuintsel = 1;
899 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
903 /*Indicates that we are exiting from hibernation */
904 core_if->hibernation_suspend = 0;
908 gpwrdn.b.pmuactv = 1;
909 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
913 core_if->op_state = B_PERIPHERAL;
914 dwc_otg_core_init(core_if);
915 dwc_otg_enable_global_interrupts(core_if);
916 cil_pcd_start(core_if);
918 if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
919 otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
921 * Initiate SRP after initial ADP probe.
923 dwc_otg_initiate_srp(core_if);
925 } else if (core_if->adp_enable) {
926 dwc_otg_adp_probe_stop(core_if);
927 if (DWC_WORKQ_PENDING(core_if->wq_otg))
928 core_if->stop_adpprb = 1;
929 /* Disable Power Down Logic */
931 gpwrdn.b.pmuintsel = 1;
932 gpwrdn.b.pmuactv = 1;
933 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
937 * Initialize the Core for Device mode.
939 core_if->op_state = B_PERIPHERAL;
940 cil_pcd_start(core_if);
941 dwc_otg_enable_global_interrupts(core_if);
948 * This interrupt indicates that the Wakeup Logic has detected a
949 * status change either on IDDIG or BSessVld.
951 static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
954 gpwrdn_data_t gpwrdn = {.d32 = 0 };
955 gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
956 dwc_otg_core_if_t *core_if = otg_dev->core_if;
958 DWC_PRINTF("%s called\n", __FUNCTION__);
960 if (core_if->power_down == 2) {
961 if (core_if->hibernation_suspend <= 0) {
962 DWC_PRINTF("Already exited from Hibernation\n");
965 gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
968 gpwrdn_temp.d32 = core_if->adp.gpwrdn;
971 gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
973 if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
974 retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
975 } else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
976 retval = dwc_otg_handle_pwrdn_session_change(core_if);
983 * This interrupt indicates that the Wakeup Logic has detected a
986 static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t *core_if)
988 gpwrdn_data_t gpwrdn = {.d32 = 0 };
990 DWC_PRINTF("%s called\n", __FUNCTION__);
992 if (!core_if->hibernation_suspend) {
993 DWC_PRINTF("Already exited from Hibernation\n");
996 #ifdef DWC_DEV_SRPCAP
997 if (core_if->pwron_timer_started) {
998 core_if->pwron_timer_started = 0;
999 DWC_TIMER_CANCEL(core_if->pwron_timer);
1003 /* Switch on the voltage to the core */
1004 gpwrdn.b.pwrdnswtch = 1;
1005 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1008 /* Reset the core */
1010 gpwrdn.b.pwrdnrstn = 1;
1011 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1014 /* Disable power clamps */
1016 gpwrdn.b.pwrdnclmp = 1;
1017 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1019 /* Remove reset the core signal */
1021 gpwrdn.b.pwrdnrstn = 1;
1022 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
1025 /* Disable PMU interrupt */
1027 gpwrdn.b.pmuintsel = 1;
1028 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1030 /* Indicates that we are exiting from hibernation */
1031 core_if->hibernation_suspend = 0;
1035 gpwrdn.b.pmuactv = 1;
1036 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1039 /* Programm Disable VBUS to 0 */
1041 gpwrdn.b.dis_vbus = 1;
1042 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1044 /*Initialize the core as Host */
1045 core_if->op_state = A_HOST;
1046 dwc_otg_core_init(core_if);
1047 dwc_otg_enable_global_interrupts(core_if);
1048 cil_hcd_start(core_if);
1053 /** This interrupt indicates that restore command after Hibernation
1054 * was completed by the core. */
1055 int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t *core_if)
1057 pcgcctl_data_t pcgcctl;
1058 DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
1060 /* TODO De-assert restore signal. 8.a */
1061 pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
1062 if (pcgcctl.b.restoremode == 1) {
1063 gintmsk_data_t gintmsk = {.d32 = 0 };
1065 * If restore mode is Remote Wakeup,
1066 * unmask Remote Wakeup interrupt.
1068 gintmsk.b.wkupintr = 1;
1069 DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
1077 * This interrupt indicates that a device has been disconnected from
1080 int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t *core_if)
1082 gintsts_data_t gintsts;
1084 DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
1085 (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
1086 op_state_str(core_if));
1088 /** @todo Consolidate this if statement. */
1089 #ifndef DWC_HOST_ONLY
1090 if (core_if->op_state == B_HOST) {
1091 /* If in device mode Disconnect and stop the HCD, then
1093 DWC_SPINUNLOCK(core_if->lock);
1094 cil_hcd_disconnect(core_if);
1095 cil_pcd_start(core_if);
1096 DWC_SPINLOCK(core_if->lock);
1097 core_if->op_state = B_PERIPHERAL;
1098 } else if (dwc_otg_is_device_mode(core_if)) {
1099 gotgctl_data_t gotgctl = {.d32 = 0 };
1101 DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
1102 if (gotgctl.b.hstsethnpen == 1) {
1103 /* Do nothing, if HNP in process the OTG
1104 * interrupt "Host Negotiation Detected"
1105 * interrupt will do the mode switch.
1107 } else if (gotgctl.b.devhnpen == 0) {
1108 /* If in device mode Disconnect and stop the HCD, then
1110 DWC_SPINUNLOCK(core_if->lock);
1111 cil_hcd_disconnect(core_if);
1112 cil_pcd_start(core_if);
1113 DWC_SPINLOCK(core_if->lock);
1114 core_if->op_state = B_PERIPHERAL;
1116 DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
1119 if (core_if->op_state == A_HOST) {
1120 /* A-Cable still connected but device disconnected. */
1121 cil_hcd_disconnect(core_if);
1122 if (core_if->adp_enable) {
1123 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1124 cil_hcd_stop(core_if);
1125 /* Enable Power Down Logic */
1126 gpwrdn.b.pmuintsel = 1;
1127 gpwrdn.b.pmuactv = 1;
1128 DWC_MODIFY_REG32(&core_if->
1129 core_global_regs->gpwrdn, 0,
1131 dwc_otg_adp_probe_start(core_if);
1133 /* Power off the core */
1134 if (core_if->power_down == 2) {
1136 gpwrdn.b.pwrdnswtch = 1;
1138 (&core_if->core_global_regs->gpwrdn,
1145 /* Change to L3(OFF) state */
1146 core_if->lx_state = DWC_OTG_L3;
1149 gintsts.b.disconnect = 1;
1150 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1155 * This interrupt indicates that SUSPEND state has been detected on
1158 * For HNP the USB Suspend interrupt signals the change from
1159 * "a_peripheral" to "a_host".
1161 * When power management is enabled the core will be put in low power
1164 int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t *core_if)
1167 gintsts_data_t gintsts;
1170 DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
1172 if ((core_if->otg_ver == 1) && (core_if->op_state == A_PERIPHERAL))
1173 dwc_mdelay(200); /* vahrama - WA - see BU's mail */
1175 if (dwc_otg_is_device_mode(core_if)) {
1176 /* Check the Device status register to determine if the Suspend
1177 * state is active. */
1179 DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
1180 DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
1181 DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
1182 "HWCFG4.power Optimize=%d\n",
1183 dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
1185 #ifdef PARTIAL_POWER_DOWN
1186 /** @todo Add a module parameter for power management. */
1188 if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
1189 pcgcctl_data_t power = {.d32 = 0 };
1190 DWC_DEBUGPL(DBG_CIL, "suspend\n");
1192 power.b.pwrclmp = 1;
1193 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
1195 power.b.rstpdwnmodule = 1;
1196 DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
1198 power.b.stoppclk = 1;
1199 DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
1202 DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
1205 /* PCD callback for suspend. Release the lock inside of callback function */
1206 cil_pcd_suspend(core_if);
1207 if (core_if->power_down == 2) {
1209 DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
1211 DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",
1213 DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",
1216 if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
1217 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1218 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1219 gusbcfg_data_t gusbcfg = {.d32 = 0 };
1221 /* Change to L2(suspend) state */
1222 core_if->lx_state = DWC_OTG_L2;
1224 /* Clear interrupt in gintsts */
1226 gintsts.b.usbsuspend = 1;
1227 DWC_WRITE_REG32(&core_if->
1228 core_global_regs->gintsts,
1230 DWC_PRINTF("Start of hibernation completed\n");
1231 dwc_otg_save_global_regs(core_if);
1232 dwc_otg_save_dev_regs(core_if);
1235 DWC_READ_REG32(&core_if->
1236 core_global_regs->gusbcfg);
1237 if (gusbcfg.b.ulpi_utmi_sel == 1) {
1238 /* ULPI interface */
1239 /* Suspend the Phy Clock */
1241 pcgcctl.b.stoppclk = 1;
1242 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1245 gpwrdn.b.pmuactv = 1;
1247 (&core_if->core_global_regs->gpwrdn,
1250 /* UTMI+ Interface */
1251 gpwrdn.b.pmuactv = 1;
1253 (&core_if->core_global_regs->gpwrdn,
1256 pcgcctl.b.stoppclk = 1;
1257 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1262 /* Set flag to indicate that we are in hibernation */
1263 core_if->hibernation_suspend = 1;
1264 /* Enable interrupts from wake up logic */
1266 gpwrdn.b.pmuintsel = 1;
1267 DWC_MODIFY_REG32(&core_if->
1268 core_global_regs->gpwrdn, 0,
1272 /* Unmask device mode interrupts in GPWRDN */
1274 gpwrdn.b.rst_det_msk = 1;
1275 gpwrdn.b.lnstchng_msk = 1;
1276 gpwrdn.b.sts_chngint_msk = 1;
1277 DWC_MODIFY_REG32(&core_if->
1278 core_global_regs->gpwrdn, 0,
1282 /* Enable Power Down Clamp */
1284 gpwrdn.b.pwrdnclmp = 1;
1285 DWC_MODIFY_REG32(&core_if->
1286 core_global_regs->gpwrdn, 0,
1290 /* Switch off VDD */
1292 gpwrdn.b.pwrdnswtch = 1;
1293 DWC_MODIFY_REG32(&core_if->
1294 core_global_regs->gpwrdn, 0,
1297 /* Save gpwrdn register for further usage if stschng interrupt */
1298 core_if->gr_backup->gpwrdn_local =
1299 DWC_READ_REG32(&core_if->core_global_regs->
1301 DWC_PRINTF("Hibernation completed\n");
1305 } else if (core_if->power_down == 3) {
1306 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1308 DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
1310 DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",
1312 DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",
1315 if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
1316 DWC_DEBUGPL(DBG_ANY,
1317 "Start entering to extended hibernation\n");
1320 /* Clear interrupt in gintsts */
1322 gintsts.b.usbsuspend = 1;
1323 DWC_WRITE_REG32(&core_if->
1324 core_global_regs->gintsts,
1327 dwc_otg_save_global_regs(core_if);
1328 dwc_otg_save_dev_regs(core_if);
1330 /* Wait for 10 PHY clocks */
1333 /* Program GPIO register while entering to xHib */
1334 DWC_WRITE_REG32(&core_if->core_global_regs->
1337 pcgcctl.b.enbl_extnd_hiber = 1;
1338 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1340 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1344 pcgcctl.b.extnd_hiber_pwrclmp = 1;
1345 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1349 pcgcctl.b.extnd_hiber_switch = 1;
1350 core_if->gr_backup->xhib_gpwrdn =
1351 DWC_READ_REG32(&core_if->core_global_regs->
1353 core_if->gr_backup->xhib_pcgcctl =
1354 DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.
1356 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1359 DWC_DEBUGPL(DBG_ANY,
1360 "Finished entering to extended hibernation\n");
1365 if ((core_if->otg_ver == 1)
1366 && (core_if->core_params->otg_cap ==
1367 DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)) {
1368 gotgctl_data_t gotgctl = {.d32 = 0 };
1370 DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
1371 if (gotgctl.b.devhnpen && core_if->otg_ver == 1) {
1372 gotgctl_data_t gotgctl = {.d32 = 0 };
1374 /**@todo Is the gotgctl.devhnpen cleared
1375 * by a USB Reset? */
1376 gotgctl.b.devhnpen = 1;
1377 gotgctl.b.hnpreq = 1;
1378 DWC_WRITE_REG32(&core_if->core_global_regs->
1379 gotgctl, gotgctl.d32);
1383 if (core_if->op_state == A_PERIPHERAL) {
1384 DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
1385 /* Clear the a_peripheral flag, back to a_host. */
1386 DWC_SPINUNLOCK(core_if->lock);
1387 cil_pcd_stop(core_if);
1388 cil_hcd_start(core_if);
1389 DWC_SPINLOCK(core_if->lock);
1390 core_if->op_state = A_HOST;
1394 /* Change to L2(suspend) state */
1395 core_if->lx_state = DWC_OTG_L2;
1397 /* Clear interrupt */
1399 gintsts.b.usbsuspend = 1;
1400 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1405 static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t *core_if)
1407 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1408 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1409 gahbcfg_data_t gahbcfg = {.d32 = 0 };
1413 /* Program GPIO register while entering to xHib */
1414 DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
1416 pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
1417 pcgcctl.b.extnd_hiber_pwrclmp = 0;
1418 DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
1421 gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
1422 gpwrdn.b.restore = 1;
1423 DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
1426 restore_lpm_i2c_regs(core_if);
1428 pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
1429 pcgcctl.b.max_xcvrselect = 1;
1430 pcgcctl.b.ess_reg_restored = 0;
1431 pcgcctl.b.extnd_hiber_switch = 0;
1432 pcgcctl.b.extnd_hiber_pwrclmp = 0;
1433 pcgcctl.b.enbl_extnd_hiber = 1;
1434 DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
1436 gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
1437 gahbcfg.b.glblintrmsk = 1;
1438 DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
1440 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
1441 DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
1443 DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
1444 core_if->gr_backup->gusbcfg_local);
1445 DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
1446 core_if->dr_backup->dcfg);
1449 pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
1450 pcgcctl.b.max_xcvrselect = 1;
1451 pcgcctl.d32 |= 0x608;
1452 DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
1456 pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
1457 pcgcctl.b.max_xcvrselect = 1;
1458 pcgcctl.b.ess_reg_restored = 1;
1459 pcgcctl.b.enbl_extnd_hiber = 1;
1460 pcgcctl.b.rstpdwnmodule = 1;
1461 pcgcctl.b.restoremode = 1;
1462 DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
1464 DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
1469 #ifdef CONFIG_USB_DWC_OTG_LPM
1471 * This function hadles LPM transaction received interrupt.
1473 static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t *core_if)
1475 glpmcfg_data_t lpmcfg;
1476 gintsts_data_t gintsts;
1478 if (!core_if->core_params->lpm_enable) {
1479 DWC_PRINTF("Unexpected LPM interrupt\n");
1482 lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
1483 DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
1485 if (dwc_otg_is_host_mode(core_if)) {
1486 cil_hcd_sleep(core_if);
1489 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1491 lpmcfg.b.hird_thres |= (1 << 4);
1492 lpmcfg.b.en_utmi_sleep = 1;
1494 pcgcctl.b.enbl_sleep_gating = 1;
1495 DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
1497 if (dwc_otg_get_param_besl_enable(core_if)) {
1498 lpmcfg.b.en_besl = 1;
1501 DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
1505 /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
1507 lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
1508 if (lpmcfg.b.prt_sleep_sts) {
1509 /* Save the current state */
1510 core_if->lx_state = DWC_OTG_L1;
1513 /* Clear interrupt */
1515 gintsts.b.lpmtranrcvd = 1;
1516 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1519 #endif /* CONFIG_USB_DWC_OTG_LPM */
1522 * This function returns the Core Interrupt register.
1524 static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t *core_if)
1528 gahbcfg_data_t gahbcfg = {.d32 = 0 };
1529 gintsts_data_t gintsts;
1530 gintmsk_data_t gintmsk;
1531 gintmsk_data_t gintmsk_common = {.d32 = 0 };
1532 gintmsk_common.b.wkupintr = 1;
1533 gintmsk_common.b.sessreqintr = 1;
1534 gintmsk_common.b.conidstschng = 1;
1535 gintmsk_common.b.otgintr = 1;
1536 gintmsk_common.b.modemismatch = 1;
1537 gintmsk_common.b.disconnect = 1;
1538 gintmsk_common.b.usbsuspend = 1;
1539 #ifdef CONFIG_USB_DWC_OTG_LPM
1540 gintmsk_common.b.lpmtranrcvd = 1;
1542 gintmsk_common.b.restoredone = 1;
1543 /** @todo: The port interrupt occurs while in device
1544 * mode. Added code to CIL to clear the interrupt for now!
1546 gintmsk_common.b.portintr = 1;
1548 gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
1549 gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
1550 gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
1553 /* if any common interrupts set */
1554 if (gintsts.d32 & gintmsk_common.d32) {
1555 DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
1556 gintsts.d32, gintmsk.d32);
1559 if (gahbcfg.b.glblintrmsk) {
1560 retval = (gintsts.d32 & gintmsk.d32) & gintmsk_common.d32;
1567 /* MACRO for clearing interupt bits in GPWRDN register */
1568 #define CLEAR_GPWRDN_INTR(__core_if, __intr) \
1570 gpwrdn_data_t gpwrdn = {.d32 = 0}; \
1571 gpwrdn.b.__intr = 1; \
1572 DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
1577 * Common interrupt handler.
1579 * The common interrupts are those that occur in both Host and Device mode.
1580 * This handler handles the following interrupts:
1581 * - Mode Mismatch Interrupt
1582 * - Disconnect Interrupt
1584 * - Connector ID Status Change Interrupt
1585 * - Session Request Interrupt.
1586 * - Resume / Remote Wakeup Detected Interrupt.
1587 * - LPM Transaction Received Interrupt
1588 * - ADP Transaction Received Interrupt
1591 int32_t dwc_otg_handle_common_intr(void *dev)
1594 gintsts_data_t gintsts;
1595 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1596 dwc_otg_device_t *otg_dev = dev;
1597 dwc_otg_core_if_t *core_if = otg_dev->core_if;
1598 gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
1600 if (dwc_otg_check_haps_status(core_if) == -1) {
1601 DWC_WARN("HAPS is disconnected");
1605 if (dwc_otg_is_device_mode(core_if))
1606 core_if->frame_num = dwc_otg_get_frame_number(core_if);
1609 DWC_SPINLOCK(core_if->lock);
1611 if (core_if->power_down == 3 && core_if->xhib == 1) {
1612 DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
1613 retval |= dwc_otg_handle_xhib_exit_intr(core_if);
1616 DWC_SPINUNLOCK(core_if->lock);
1621 if (core_if->hibernation_suspend <= 0) {
1622 gintsts.d32 = dwc_otg_read_common_intr(core_if);
1624 if (gintsts.b.modemismatch) {
1625 retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
1627 if (gintsts.b.otgintr) {
1628 retval |= dwc_otg_handle_otg_intr(core_if);
1630 if (gintsts.b.conidstschng) {
1632 dwc_otg_handle_conn_id_status_change_intr(core_if);
1634 if (gintsts.b.disconnect) {
1635 retval |= dwc_otg_handle_disconnect_intr(core_if);
1637 if (gintsts.b.sessreqintr) {
1638 retval |= dwc_otg_handle_session_req_intr(core_if);
1640 if (gintsts.b.wkupintr) {
1641 retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
1643 if (gintsts.b.usbsuspend) {
1644 retval |= dwc_otg_handle_usb_suspend_intr(core_if);
1646 #ifdef CONFIG_USB_DWC_OTG_LPM
1647 if (gintsts.b.lpmtranrcvd) {
1648 retval |= dwc_otg_handle_lpm_intr(core_if);
1651 if (gintsts.b.restoredone) {
1653 if (core_if->power_down == 2)
1654 core_if->hibernation_suspend = -1;
1655 else if (core_if->power_down == 3 && core_if->xhib == 2) {
1656 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1657 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1658 dctl_data_t dctl = {.d32 = 0 };
1660 DWC_WRITE_REG32(&core_if->
1661 core_global_regs->gintsts,
1664 DWC_DEBUGPL(DBG_ANY,
1665 "RESTORE DONE generated\n");
1667 gpwrdn.b.restore = 1;
1668 DWC_MODIFY_REG32(&core_if->core_global_regs->
1669 gpwrdn, gpwrdn.d32, 0);
1672 pcgcctl.b.rstpdwnmodule = 1;
1673 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
1676 DWC_WRITE_REG32(&core_if->core_global_regs->
1678 core_if->gr_backup->
1680 DWC_WRITE_REG32(&core_if->dev_if->
1681 dev_global_regs->dcfg,
1682 core_if->dr_backup->dcfg);
1683 DWC_WRITE_REG32(&core_if->dev_if->
1684 dev_global_regs->dctl,
1685 core_if->dr_backup->dctl);
1688 dctl.b.pwronprgdone = 1;
1689 DWC_MODIFY_REG32(&core_if->dev_if->
1690 dev_global_regs->dctl, 0,
1694 dwc_otg_restore_global_regs(core_if);
1695 dwc_otg_restore_dev_regs(core_if, 0);
1698 dctl.b.pwronprgdone = 1;
1699 DWC_MODIFY_REG32(&core_if->dev_if->
1700 dev_global_regs->dctl,
1705 pcgcctl.b.enbl_extnd_hiber = 1;
1706 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
1709 /* The core will be in ON STATE */
1710 core_if->lx_state = DWC_OTG_L0;
1713 DWC_SPINUNLOCK(core_if->lock);
1715 && core_if->pcd_cb->resume_wakeup) {
1716 core_if->pcd_cb->resume_wakeup(core_if->
1720 DWC_SPINLOCK(core_if->lock);
1724 gintsts.b.restoredone = 1;
1725 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,
1727 DWC_PRINTF(" --Restore done interrupt received-- \n");
1730 if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
1731 /* The port interrupt occurs while in device mode with HPRT0
1732 * Port Enable/Disable.
1735 gintsts.b.portintr = 1;
1736 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,
1742 DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
1744 if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
1745 CLEAR_GPWRDN_INTR(core_if, disconn_det);
1746 if (gpwrdn.b.linestate == 0) {
1747 dwc_otg_handle_pwrdn_disconnect_intr(core_if);
1750 ("Disconnect detected while linestate is not 0\n");
1755 if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
1756 CLEAR_GPWRDN_INTR(core_if, lnstschng);
1757 /* remote wakeup from hibernation */
1758 if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
1759 dwc_otg_handle_pwrdn_wakeup_detected_intr
1762 DWC_PRINTF("gpwrdn.linestate = %d\n",
1763 gpwrdn.b.linestate);
1767 if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
1768 CLEAR_GPWRDN_INTR(core_if, rst_det);
1769 if (gpwrdn.b.linestate == 0) {
1770 DWC_PRINTF("Reset detected\n");
1772 dwc_otg_device_hibernation_restore(core_if,
1776 if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
1777 CLEAR_GPWRDN_INTR(core_if, srp_det);
1778 dwc_otg_handle_pwrdn_srp_intr(core_if);
1782 /* Handle ADP interrupt here */
1783 if (gpwrdn.b.adp_int) {
1784 DWC_PRINTF("ADP interrupt\n");
1785 CLEAR_GPWRDN_INTR(core_if, adp_int);
1786 dwc_otg_adp_handle_intr(core_if);
1789 if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
1790 DWC_PRINTF("STS CHNG interrupt asserted\n");
1791 CLEAR_GPWRDN_INTR(core_if, sts_chngint);
1792 dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
1797 DWC_SPINUNLOCK(core_if->lock);