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 if (core_if->usb_mode != USB_MODE_NORMAL)
395 gintmsk.b.sofintr = 1;
396 DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
398 " ++Connector ID Status Change Interrupt++ (%s)\n",
399 (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
401 DWC_SPINUNLOCK(core_if->lock);
404 * Need to schedule a work, as there are possible DELAY function calls
405 * Release lock before scheduling workq as it holds spinlock during scheduling
408 /*DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
409 core_if, "connection id status change");*/
410 DWC_SPINLOCK(core_if->lock);
412 /* Set flag and clear interrupt */
413 gintsts.b.conidstschng = 1;
414 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
420 * This interrupt indicates that a device is initiating the Session
421 * Request Protocol to request the host to turn on bus power so a new
422 * session can begin. The handler responds by turning on bus power. If
423 * the DWC_otg controller is in low power mode, the handler brings the
424 * controller out of low power mode before turning on bus power.
426 * @param core_if Programming view of DWC_otg controller.
428 int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t *core_if)
430 gintsts_data_t gintsts;
432 #ifndef DWC_HOST_ONLY
433 DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
434 if (dwc_otg_is_device_mode(core_if)) {
435 gotgctl_data_t gotgctl = {.d32 = 0 };
436 DWC_PRINTF("SRP: Device mode\n");
438 DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
439 if (gotgctl.b.sesreqscs)
440 DWC_PRINTF("SRP Success\n");
442 DWC_PRINTF("SRP Fail\n");
443 if (core_if->otg_ver) {
445 gotgctl.b.devhnpen = 1;
446 DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
451 DWC_PRINTF("SRP: Host mode\n");
453 /* Turn on the port power bit. */
454 hprt0.d32 = dwc_otg_read_hprt0(core_if);
456 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
458 /* Start the Connection timer. So a message can be displayed
459 * if connect does not occur within 10 seconds. */
460 cil_hcd_session_start(core_if);
464 /* Clear interrupt */
466 gintsts.b.sessreqintr = 1;
467 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
472 void w_wakeup_detected(void *data)
474 dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) data;
476 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
477 * so that OPT tests pass with all PHYs).
479 hprt0_data_t hprt0 = {.d32 = 0 };
481 pcgcctl_data_t pcgcctl = {.d32 = 0 };
482 /* Restart the Phy Clock */
483 pcgcctl.b.stoppclk = 1;
484 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
487 hprt0.d32 = dwc_otg_read_hprt0(core_if);
488 DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
490 hprt0.b.prtres = 0; /* Resume */
491 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
492 DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
493 DWC_READ_REG32(core_if->host_if->hprt0));
495 cil_hcd_resume(core_if);
497 /** Change to L0 state*/
498 core_if->lx_state = DWC_OTG_L0;
501 static inline void rk_dwc_otg_phy_soft_reset(dwc_otg_core_if_t *core_if)
503 struct dwc_otg_platform_data *pldata;
506 pldata = core_if->otg_dev->pldata;
507 guid.d32 = core_if->core_global_regs->guid;
509 if ((cpu_is_rk3288()) && ((guid.d32 & 0x01) == 0)) {
510 /* only used for HOST20, OTG HOST do not need.
511 * first, do soft reset usb phy, and then usb phy
512 * can drive resume signal.
513 * second, set usb phy into suspend mode and
514 * normal mode once time, and then usb phy can
515 * send SOFs immediately after resume.
517 rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, true);
519 rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, false);
522 pldata->phy_suspend(pldata, USB_PHY_SUSPEND);
524 pldata->phy_suspend(pldata, USB_PHY_ENABLED);
530 * This interrupt indicates that the DWC_otg controller has detected a
531 * resume or remote wakeup sequence. If the DWC_otg controller is in
532 * low power mode, the handler must brings the controller out of low
533 * power mode. The controller automatically begins resume
534 * signaling. The handler schedules a time to stop resume signaling.
536 int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t *core_if)
538 gintsts_data_t gintsts;
541 "++Resume and Remote Wakeup Detected Interrupt++\n");
543 DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
545 if (dwc_otg_is_device_mode(core_if)) {
546 dctl_data_t dctl = {.d32 = 0 };
547 DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
548 DWC_READ_REG32(&core_if->dev_if->
549 dev_global_regs->dsts));
550 if (core_if->lx_state == DWC_OTG_L2) {
551 #ifdef PARTIAL_POWER_DOWN
552 if (core_if->hwcfg4.b.power_optimiz) {
553 pcgcctl_data_t power = {.d32 = 0 };
555 power.d32 = DWC_READ_REG32(core_if->pcgcctl);
556 DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
559 power.b.stoppclk = 0;
560 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
563 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
565 power.b.rstpdwnmodule = 0;
566 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
569 /* Clear the Remote Wakeup Signaling */
570 dctl.b.rmtwkupsig = 1;
571 DWC_MODIFY_REG32(&core_if->dev_if->
572 dev_global_regs->dctl, dctl.d32, 0);
574 DWC_SPINUNLOCK(core_if->lock);
575 if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
576 core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
579 DWC_SPINLOCK(core_if->lock);
581 glpmcfg_data_t lpmcfg;
582 pcgcctl_data_t pcgcctl = {.d32 = 0 };
585 DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
586 lpmcfg.b.hird_thres &= (~(1 << 4));
587 lpmcfg.b.en_utmi_sleep = 0;
589 /* Clear Enbl_L1Gating bit. */
590 pcgcctl.b.enbl_sleep_gating = 1;
591 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
593 DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
596 /** Change to L0 state*/
597 core_if->lx_state = DWC_OTG_L0;
599 if (core_if->lx_state != DWC_OTG_L1) {
600 pcgcctl_data_t pcgcctl = {.d32 = 0 };
602 /* Restart the Phy Clock */
603 pcgcctl.b.stoppclk = 1;
604 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
607 rk_dwc_otg_phy_soft_reset(core_if);
609 DWC_TASK_SCHEDULE(core_if->wkp_tasklet);
611 /** Change to L0 state*/
612 core_if->lx_state = DWC_OTG_L0;
616 /* Clear interrupt */
618 gintsts.b.wkupintr = 1;
619 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
625 * This interrupt indicates that the Wakeup Logic has detected a
628 static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
630 gpwrdn_data_t gpwrdn = {.d32 = 0 };
631 gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
632 gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
634 DWC_PRINTF("%s called\n", __FUNCTION__);
636 if (!core_if->hibernation_suspend) {
637 DWC_PRINTF("Already exited from Hibernation\n");
641 /* Switch on the voltage to the core */
642 gpwrdn.b.pwrdnswtch = 1;
643 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
648 gpwrdn.b.pwrdnrstn = 1;
649 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
652 /* Disable power clamps */
654 gpwrdn.b.pwrdnclmp = 1;
655 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
657 /* Remove reset the core signal */
659 gpwrdn.b.pwrdnrstn = 1;
660 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
663 /* Disable PMU interrupt */
665 gpwrdn.b.pmuintsel = 1;
666 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
668 core_if->hibernation_suspend = 0;
672 gpwrdn.b.pmuactv = 1;
673 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
676 if (gpwrdn_temp.b.idsts) {
677 core_if->op_state = B_PERIPHERAL;
678 dwc_otg_core_init(core_if);
679 dwc_otg_enable_global_interrupts(core_if);
680 cil_pcd_start(core_if);
682 core_if->op_state = A_HOST;
683 dwc_otg_core_init(core_if);
684 dwc_otg_enable_global_interrupts(core_if);
685 cil_hcd_start(core_if);
692 * This interrupt indicates that the Wakeup Logic has detected a
693 * remote wakeup sequence.
695 static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t *
698 gpwrdn_data_t gpwrdn = {.d32 = 0 };
700 "++Powerdown Remote Wakeup Detected Interrupt++\n");
702 if (!core_if->hibernation_suspend) {
703 DWC_PRINTF("Already exited from Hibernation\n");
707 gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
708 if (gpwrdn.b.idsts) { /* Device Mode */
709 if ((core_if->power_down == 2)
710 && (core_if->hibernation_suspend == 1)) {
711 dwc_otg_device_hibernation_restore(core_if, 0, 0);
714 if ((core_if->power_down == 2)
715 && (core_if->hibernation_suspend == 1)) {
716 dwc_otg_host_hibernation_restore(core_if, 1, 0);
722 static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
724 gpwrdn_data_t gpwrdn = {.d32 = 0 };
725 gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
726 dwc_otg_core_if_t *core_if = otg_dev->core_if;
728 DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
729 gpwrdn_temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
730 if (core_if->power_down == 2) {
731 if (!core_if->hibernation_suspend) {
732 DWC_PRINTF("Already exited from Hibernation\n");
736 "Exit from hibernation on ID sts change\n");
737 /* Switch on the voltage to the core */
738 gpwrdn.b.pwrdnswtch = 1;
739 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
745 gpwrdn.b.pwrdnrstn = 1;
746 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
750 /* Disable power clamps */
752 gpwrdn.b.pwrdnclmp = 1;
753 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
756 /* Remove reset the core signal */
758 gpwrdn.b.pwrdnrstn = 1;
759 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
763 /* Disable PMU interrupt */
765 gpwrdn.b.pmuintsel = 1;
766 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
769 /*Indicates that we are exiting from hibernation */
770 core_if->hibernation_suspend = 0;
774 gpwrdn.b.pmuactv = 1;
775 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
779 gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
780 if (gpwrdn.b.dis_vbus == 1) {
782 gpwrdn.b.dis_vbus = 1;
783 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
787 if (gpwrdn_temp.b.idsts) {
788 core_if->op_state = B_PERIPHERAL;
789 dwc_otg_core_init(core_if);
790 dwc_otg_enable_global_interrupts(core_if);
791 cil_pcd_start(core_if);
793 core_if->op_state = A_HOST;
794 dwc_otg_core_init(core_if);
795 dwc_otg_enable_global_interrupts(core_if);
796 cil_hcd_start(core_if);
800 if (core_if->adp_enable) {
802 DWC_SPINUNLOCK(core_if->lock);
803 /* Change the core_if's lock to hcd/pcd lock depend on mode? */
804 #ifndef DWC_HOST_ONLY
805 if (gpwrdn_temp.b.idsts)
806 core_if->lock = otg_dev->pcd->lock;
808 #ifndef DWC_DEVICE_ONLY
809 if (!gpwrdn_temp.b.idsts) {
810 core_if->lock = otg_dev->hcd->lock;
814 DWC_PRINTF("RESTART ADP\n");
815 if (core_if->adp.probe_enabled)
816 dwc_otg_adp_probe_stop(core_if);
817 if (core_if->adp.sense_enabled)
818 dwc_otg_adp_sense_stop(core_if);
819 if (core_if->adp.sense_timer_started)
820 DWC_TIMER_CANCEL(core_if->adp.sense_timer);
821 if (core_if->adp.vbuson_timer_started)
822 DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
823 core_if->adp.probe_timer_values[0] = -1;
824 core_if->adp.probe_timer_values[1] = -1;
825 core_if->adp.sense_timer_started = 0;
826 core_if->adp.vbuson_timer_started = 0;
827 core_if->adp.probe_counter = 0;
828 core_if->adp.gpwrdn = 0;
830 /* Disable PMU and restart ADP */
832 gpwrdn_temp.b.pmuactv = 1;
833 gpwrdn_temp.b.pmuintsel = 1;
834 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
836 DWC_PRINTF("Check point 1\n");
838 dwc_otg_adp_start(core_if, is_host);
839 DWC_SPINLOCK(core_if->lock);
845 static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t *core_if)
847 gpwrdn_data_t gpwrdn = {.d32 = 0 };
848 int32_t otg_cap_param = core_if->core_params->otg_cap;
849 DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
851 gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
852 if (core_if->power_down == 2) {
853 if (!core_if->hibernation_suspend) {
854 DWC_PRINTF("Already exited from Hibernation\n");
858 if ((otg_cap_param != DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
859 otg_cap_param != DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) &&
860 gpwrdn.b.bsessvld == 0) {
861 /* Save gpwrdn register for further usage if stschng interrupt */
862 core_if->gr_backup->gpwrdn_local =
863 DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
864 /*Exit from ISR and wait for stschng interrupt with bsessvld = 1 */
868 /* Switch on the voltage to the core */
870 gpwrdn.b.pwrdnswtch = 1;
871 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
877 gpwrdn.b.pwrdnrstn = 1;
878 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
882 /* Disable power clamps */
884 gpwrdn.b.pwrdnclmp = 1;
885 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
888 /* Remove reset the core signal */
890 gpwrdn.b.pwrdnrstn = 1;
891 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
895 /* Disable PMU interrupt */
897 gpwrdn.b.pmuintsel = 1;
898 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
902 /*Indicates that we are exiting from hibernation */
903 core_if->hibernation_suspend = 0;
907 gpwrdn.b.pmuactv = 1;
908 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
912 core_if->op_state = B_PERIPHERAL;
913 dwc_otg_core_init(core_if);
914 dwc_otg_enable_global_interrupts(core_if);
915 cil_pcd_start(core_if);
917 if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
918 otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
920 * Initiate SRP after initial ADP probe.
922 dwc_otg_initiate_srp(core_if);
924 } else if (core_if->adp_enable) {
925 dwc_otg_adp_probe_stop(core_if);
926 if (DWC_WORKQ_PENDING(core_if->wq_otg))
927 core_if->stop_adpprb = 1;
928 /* Disable Power Down Logic */
930 gpwrdn.b.pmuintsel = 1;
931 gpwrdn.b.pmuactv = 1;
932 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
936 * Initialize the Core for Device mode.
938 core_if->op_state = B_PERIPHERAL;
939 cil_pcd_start(core_if);
940 dwc_otg_enable_global_interrupts(core_if);
947 * This interrupt indicates that the Wakeup Logic has detected a
948 * status change either on IDDIG or BSessVld.
950 static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
953 gpwrdn_data_t gpwrdn = {.d32 = 0 };
954 gpwrdn_data_t gpwrdn_temp = {.d32 = 0 };
955 dwc_otg_core_if_t *core_if = otg_dev->core_if;
957 DWC_PRINTF("%s called\n", __FUNCTION__);
959 if (core_if->power_down == 2) {
960 if (core_if->hibernation_suspend <= 0) {
961 DWC_PRINTF("Already exited from Hibernation\n");
964 gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
967 gpwrdn_temp.d32 = core_if->adp.gpwrdn;
970 gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
972 if (gpwrdn.b.idsts ^ gpwrdn_temp.b.idsts) {
973 retval = dwc_otg_handle_pwrdn_idsts_change(otg_dev);
974 } else if (gpwrdn.b.bsessvld ^ gpwrdn_temp.b.bsessvld) {
975 retval = dwc_otg_handle_pwrdn_session_change(core_if);
982 * This interrupt indicates that the Wakeup Logic has detected a
985 static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t *core_if)
987 gpwrdn_data_t gpwrdn = {.d32 = 0 };
989 DWC_PRINTF("%s called\n", __FUNCTION__);
991 if (!core_if->hibernation_suspend) {
992 DWC_PRINTF("Already exited from Hibernation\n");
995 #ifdef DWC_DEV_SRPCAP
996 if (core_if->pwron_timer_started) {
997 core_if->pwron_timer_started = 0;
998 DWC_TIMER_CANCEL(core_if->pwron_timer);
1002 /* Switch on the voltage to the core */
1003 gpwrdn.b.pwrdnswtch = 1;
1004 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1007 /* Reset the core */
1009 gpwrdn.b.pwrdnrstn = 1;
1010 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1013 /* Disable power clamps */
1015 gpwrdn.b.pwrdnclmp = 1;
1016 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1018 /* Remove reset the core signal */
1020 gpwrdn.b.pwrdnrstn = 1;
1021 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
1024 /* Disable PMU interrupt */
1026 gpwrdn.b.pmuintsel = 1;
1027 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1029 /* Indicates that we are exiting from hibernation */
1030 core_if->hibernation_suspend = 0;
1034 gpwrdn.b.pmuactv = 1;
1035 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1038 /* Programm Disable VBUS to 0 */
1040 gpwrdn.b.dis_vbus = 1;
1041 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1043 /*Initialize the core as Host */
1044 core_if->op_state = A_HOST;
1045 dwc_otg_core_init(core_if);
1046 dwc_otg_enable_global_interrupts(core_if);
1047 cil_hcd_start(core_if);
1052 /** This interrupt indicates that restore command after Hibernation
1053 * was completed by the core. */
1054 int32_t dwc_otg_handle_restore_done_intr(dwc_otg_core_if_t *core_if)
1056 pcgcctl_data_t pcgcctl;
1057 DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
1059 /* TODO De-assert restore signal. 8.a */
1060 pcgcctl.d32 = DWC_READ_REG32(core_if->pcgcctl);
1061 if (pcgcctl.b.restoremode == 1) {
1062 gintmsk_data_t gintmsk = {.d32 = 0 };
1064 * If restore mode is Remote Wakeup,
1065 * unmask Remote Wakeup interrupt.
1067 gintmsk.b.wkupintr = 1;
1068 DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
1076 * This interrupt indicates that a device has been disconnected from
1079 int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t *core_if)
1081 gintsts_data_t gintsts;
1083 DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
1084 (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
1085 op_state_str(core_if));
1087 /** @todo Consolidate this if statement. */
1088 #ifndef DWC_HOST_ONLY
1089 if (core_if->op_state == B_HOST) {
1090 /* If in device mode Disconnect and stop the HCD, then
1092 DWC_SPINUNLOCK(core_if->lock);
1093 cil_hcd_disconnect(core_if);
1094 cil_pcd_start(core_if);
1095 DWC_SPINLOCK(core_if->lock);
1096 core_if->op_state = B_PERIPHERAL;
1097 } else if (dwc_otg_is_device_mode(core_if)) {
1098 gotgctl_data_t gotgctl = {.d32 = 0 };
1100 DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
1101 if (gotgctl.b.hstsethnpen == 1) {
1102 /* Do nothing, if HNP in process the OTG
1103 * interrupt "Host Negotiation Detected"
1104 * interrupt will do the mode switch.
1106 } else if (gotgctl.b.devhnpen == 0) {
1107 /* If in device mode Disconnect and stop the HCD, then
1109 DWC_SPINUNLOCK(core_if->lock);
1110 cil_hcd_disconnect(core_if);
1111 cil_pcd_start(core_if);
1112 DWC_SPINLOCK(core_if->lock);
1113 core_if->op_state = B_PERIPHERAL;
1115 DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
1118 if (core_if->op_state == A_HOST) {
1119 /* A-Cable still connected but device disconnected. */
1120 cil_hcd_disconnect(core_if);
1121 if (core_if->adp_enable) {
1122 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1123 cil_hcd_stop(core_if);
1124 /* Enable Power Down Logic */
1125 gpwrdn.b.pmuintsel = 1;
1126 gpwrdn.b.pmuactv = 1;
1127 DWC_MODIFY_REG32(&core_if->
1128 core_global_regs->gpwrdn, 0,
1130 dwc_otg_adp_probe_start(core_if);
1132 /* Power off the core */
1133 if (core_if->power_down == 2) {
1135 gpwrdn.b.pwrdnswtch = 1;
1137 (&core_if->core_global_regs->gpwrdn,
1144 /* Change to L3(OFF) state */
1145 core_if->lx_state = DWC_OTG_L3;
1148 gintsts.b.disconnect = 1;
1149 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1154 * This interrupt indicates that SUSPEND state has been detected on
1157 * For HNP the USB Suspend interrupt signals the change from
1158 * "a_peripheral" to "a_host".
1160 * When power management is enabled the core will be put in low power
1163 int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t *core_if)
1166 gintsts_data_t gintsts;
1169 DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
1171 if ((core_if->otg_ver == 1) && (core_if->op_state == A_PERIPHERAL))
1172 dwc_mdelay(200); /* vahrama - WA - see BU's mail */
1174 if (dwc_otg_is_device_mode(core_if)) {
1175 /* Check the Device status register to determine if the Suspend
1176 * state is active. */
1178 DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts);
1179 DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
1180 DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
1181 "HWCFG4.power Optimize=%d\n",
1182 dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
1184 #ifdef PARTIAL_POWER_DOWN
1185 /** @todo Add a module parameter for power management. */
1187 if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
1188 pcgcctl_data_t power = {.d32 = 0 };
1189 DWC_DEBUGPL(DBG_CIL, "suspend\n");
1191 power.b.pwrclmp = 1;
1192 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
1194 power.b.rstpdwnmodule = 1;
1195 DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
1197 power.b.stoppclk = 1;
1198 DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
1201 DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
1204 /* PCD callback for suspend. Release the lock inside of callback function */
1205 cil_pcd_suspend(core_if);
1206 if (core_if->power_down == 2) {
1208 DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
1210 DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",
1212 DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",
1215 if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
1216 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1217 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1218 gusbcfg_data_t gusbcfg = {.d32 = 0 };
1220 /* Change to L2(suspend) state */
1221 core_if->lx_state = DWC_OTG_L2;
1223 /* Clear interrupt in gintsts */
1225 gintsts.b.usbsuspend = 1;
1226 DWC_WRITE_REG32(&core_if->
1227 core_global_regs->gintsts,
1229 DWC_PRINTF("Start of hibernation completed\n");
1230 dwc_otg_save_global_regs(core_if);
1231 dwc_otg_save_dev_regs(core_if);
1234 DWC_READ_REG32(&core_if->
1235 core_global_regs->gusbcfg);
1236 if (gusbcfg.b.ulpi_utmi_sel == 1) {
1237 /* ULPI interface */
1238 /* Suspend the Phy Clock */
1240 pcgcctl.b.stoppclk = 1;
1241 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1244 gpwrdn.b.pmuactv = 1;
1246 (&core_if->core_global_regs->gpwrdn,
1249 /* UTMI+ Interface */
1250 gpwrdn.b.pmuactv = 1;
1252 (&core_if->core_global_regs->gpwrdn,
1255 pcgcctl.b.stoppclk = 1;
1256 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1261 /* Set flag to indicate that we are in hibernation */
1262 core_if->hibernation_suspend = 1;
1263 /* Enable interrupts from wake up logic */
1265 gpwrdn.b.pmuintsel = 1;
1266 DWC_MODIFY_REG32(&core_if->
1267 core_global_regs->gpwrdn, 0,
1271 /* Unmask device mode interrupts in GPWRDN */
1273 gpwrdn.b.rst_det_msk = 1;
1274 gpwrdn.b.lnstchng_msk = 1;
1275 gpwrdn.b.sts_chngint_msk = 1;
1276 DWC_MODIFY_REG32(&core_if->
1277 core_global_regs->gpwrdn, 0,
1281 /* Enable Power Down Clamp */
1283 gpwrdn.b.pwrdnclmp = 1;
1284 DWC_MODIFY_REG32(&core_if->
1285 core_global_regs->gpwrdn, 0,
1289 /* Switch off VDD */
1291 gpwrdn.b.pwrdnswtch = 1;
1292 DWC_MODIFY_REG32(&core_if->
1293 core_global_regs->gpwrdn, 0,
1296 /* Save gpwrdn register for further usage if stschng interrupt */
1297 core_if->gr_backup->gpwrdn_local =
1298 DWC_READ_REG32(&core_if->core_global_regs->
1300 DWC_PRINTF("Hibernation completed\n");
1304 } else if (core_if->power_down == 3) {
1305 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1307 DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
1309 DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",
1311 DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",
1314 if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
1315 DWC_DEBUGPL(DBG_ANY,
1316 "Start entering to extended hibernation\n");
1319 /* Clear interrupt in gintsts */
1321 gintsts.b.usbsuspend = 1;
1322 DWC_WRITE_REG32(&core_if->
1323 core_global_regs->gintsts,
1326 dwc_otg_save_global_regs(core_if);
1327 dwc_otg_save_dev_regs(core_if);
1329 /* Wait for 10 PHY clocks */
1332 /* Program GPIO register while entering to xHib */
1333 DWC_WRITE_REG32(&core_if->core_global_regs->
1336 pcgcctl.b.enbl_extnd_hiber = 1;
1337 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1339 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1343 pcgcctl.b.extnd_hiber_pwrclmp = 1;
1344 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1348 pcgcctl.b.extnd_hiber_switch = 1;
1349 core_if->gr_backup->xhib_gpwrdn =
1350 DWC_READ_REG32(&core_if->core_global_regs->
1352 core_if->gr_backup->xhib_pcgcctl =
1353 DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.
1355 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1358 DWC_DEBUGPL(DBG_ANY,
1359 "Finished entering to extended hibernation\n");
1364 if ((core_if->otg_ver == 1)
1365 && (core_if->core_params->otg_cap ==
1366 DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE)) {
1367 gotgctl_data_t gotgctl = {.d32 = 0 };
1369 DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
1370 if (gotgctl.b.devhnpen && core_if->otg_ver == 1) {
1371 gotgctl_data_t gotgctl = {.d32 = 0 };
1373 /**@todo Is the gotgctl.devhnpen cleared
1374 * by a USB Reset? */
1375 gotgctl.b.devhnpen = 1;
1376 gotgctl.b.hnpreq = 1;
1377 DWC_WRITE_REG32(&core_if->core_global_regs->
1378 gotgctl, gotgctl.d32);
1382 if (core_if->op_state == A_PERIPHERAL) {
1383 DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
1384 /* Clear the a_peripheral flag, back to a_host. */
1385 DWC_SPINUNLOCK(core_if->lock);
1386 cil_pcd_stop(core_if);
1387 cil_hcd_start(core_if);
1388 DWC_SPINLOCK(core_if->lock);
1389 core_if->op_state = A_HOST;
1393 /* Change to L2(suspend) state */
1394 core_if->lx_state = DWC_OTG_L2;
1396 /* Clear interrupt */
1398 gintsts.b.usbsuspend = 1;
1399 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1404 static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t *core_if)
1406 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1407 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1408 gahbcfg_data_t gahbcfg = {.d32 = 0 };
1412 /* Program GPIO register while entering to xHib */
1413 DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
1415 pcgcctl.d32 = core_if->gr_backup->xhib_pcgcctl;
1416 pcgcctl.b.extnd_hiber_pwrclmp = 0;
1417 DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
1420 gpwrdn.d32 = core_if->gr_backup->xhib_gpwrdn;
1421 gpwrdn.b.restore = 1;
1422 DWC_WRITE_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32);
1425 restore_lpm_i2c_regs(core_if);
1427 pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
1428 pcgcctl.b.max_xcvrselect = 1;
1429 pcgcctl.b.ess_reg_restored = 0;
1430 pcgcctl.b.extnd_hiber_switch = 0;
1431 pcgcctl.b.extnd_hiber_pwrclmp = 0;
1432 pcgcctl.b.enbl_extnd_hiber = 1;
1433 DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
1435 gahbcfg.d32 = core_if->gr_backup->gahbcfg_local;
1436 gahbcfg.b.glblintrmsk = 1;
1437 DWC_WRITE_REG32(&core_if->core_global_regs->gahbcfg, gahbcfg.d32);
1439 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
1440 DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
1442 DWC_WRITE_REG32(&core_if->core_global_regs->gusbcfg,
1443 core_if->gr_backup->gusbcfg_local);
1444 DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dcfg,
1445 core_if->dr_backup->dcfg);
1448 pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
1449 pcgcctl.b.max_xcvrselect = 1;
1450 pcgcctl.d32 |= 0x608;
1451 DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
1455 pcgcctl.d32 = core_if->gr_backup->pcgcctl_local & (0x3FFFF << 14);
1456 pcgcctl.b.max_xcvrselect = 1;
1457 pcgcctl.b.ess_reg_restored = 1;
1458 pcgcctl.b.enbl_extnd_hiber = 1;
1459 pcgcctl.b.rstpdwnmodule = 1;
1460 pcgcctl.b.restoremode = 1;
1461 DWC_WRITE_REG32(core_if->pcgcctl, pcgcctl.d32);
1463 DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
1468 #ifdef CONFIG_USB_DWC_OTG_LPM
1470 * This function hadles LPM transaction received interrupt.
1472 static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t *core_if)
1474 glpmcfg_data_t lpmcfg;
1475 gintsts_data_t gintsts;
1477 if (!core_if->core_params->lpm_enable) {
1478 DWC_PRINTF("Unexpected LPM interrupt\n");
1481 lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
1482 DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
1484 if (dwc_otg_is_host_mode(core_if)) {
1485 cil_hcd_sleep(core_if);
1488 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1490 lpmcfg.b.hird_thres |= (1 << 4);
1491 lpmcfg.b.en_utmi_sleep = 1;
1493 pcgcctl.b.enbl_sleep_gating = 1;
1494 DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
1496 if (dwc_otg_get_param_besl_enable(core_if)) {
1497 lpmcfg.b.en_besl = 1;
1500 DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
1504 /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
1506 lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
1507 if (lpmcfg.b.prt_sleep_sts) {
1508 /* Save the current state */
1509 core_if->lx_state = DWC_OTG_L1;
1512 /* Clear interrupt */
1514 gintsts.b.lpmtranrcvd = 1;
1515 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1518 #endif /* CONFIG_USB_DWC_OTG_LPM */
1521 * This function returns the Core Interrupt register.
1523 static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t *core_if)
1527 gahbcfg_data_t gahbcfg = {.d32 = 0 };
1528 gintsts_data_t gintsts;
1529 gintmsk_data_t gintmsk;
1530 gintmsk_data_t gintmsk_common = {.d32 = 0 };
1531 gintmsk_common.b.wkupintr = 1;
1532 gintmsk_common.b.sessreqintr = 1;
1533 gintmsk_common.b.conidstschng = 1;
1534 gintmsk_common.b.otgintr = 1;
1535 gintmsk_common.b.modemismatch = 1;
1536 gintmsk_common.b.disconnect = 1;
1537 gintmsk_common.b.usbsuspend = 1;
1538 #ifdef CONFIG_USB_DWC_OTG_LPM
1539 gintmsk_common.b.lpmtranrcvd = 1;
1541 gintmsk_common.b.restoredone = 1;
1542 /** @todo: The port interrupt occurs while in device
1543 * mode. Added code to CIL to clear the interrupt for now!
1545 gintmsk_common.b.portintr = 1;
1547 gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
1548 gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
1549 gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
1552 /* if any common interrupts set */
1553 if (gintsts.d32 & gintmsk_common.d32) {
1554 DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
1555 gintsts.d32, gintmsk.d32);
1558 if (gahbcfg.b.glblintrmsk) {
1559 retval = (gintsts.d32 & gintmsk.d32) & gintmsk_common.d32;
1566 /* MACRO for clearing interupt bits in GPWRDN register */
1567 #define CLEAR_GPWRDN_INTR(__core_if, __intr) \
1569 gpwrdn_data_t gpwrdn = {.d32 = 0}; \
1570 gpwrdn.b.__intr = 1; \
1571 DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
1576 * Common interrupt handler.
1578 * The common interrupts are those that occur in both Host and Device mode.
1579 * This handler handles the following interrupts:
1580 * - Mode Mismatch Interrupt
1581 * - Disconnect Interrupt
1583 * - Connector ID Status Change Interrupt
1584 * - Session Request Interrupt.
1585 * - Resume / Remote Wakeup Detected Interrupt.
1586 * - LPM Transaction Received Interrupt
1587 * - ADP Transaction Received Interrupt
1590 int32_t dwc_otg_handle_common_intr(void *dev)
1593 gintsts_data_t gintsts;
1594 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1595 dwc_otg_device_t *otg_dev = dev;
1596 dwc_otg_core_if_t *core_if = otg_dev->core_if;
1597 gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
1599 if (dwc_otg_check_haps_status(core_if) == -1) {
1600 DWC_WARN("HAPS is disconnected");
1604 if (dwc_otg_is_device_mode(core_if))
1605 core_if->frame_num = dwc_otg_get_frame_number(core_if);
1608 DWC_SPINLOCK(core_if->lock);
1610 if (core_if->power_down == 3 && core_if->xhib == 1) {
1611 DWC_DEBUGPL(DBG_ANY, "Exiting from xHIB state\n");
1612 retval |= dwc_otg_handle_xhib_exit_intr(core_if);
1615 DWC_SPINUNLOCK(core_if->lock);
1620 if (core_if->hibernation_suspend <= 0) {
1621 gintsts.d32 = dwc_otg_read_common_intr(core_if);
1623 if (gintsts.b.modemismatch) {
1624 retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
1626 if (gintsts.b.otgintr) {
1627 retval |= dwc_otg_handle_otg_intr(core_if);
1629 if (gintsts.b.conidstschng) {
1631 dwc_otg_handle_conn_id_status_change_intr(core_if);
1633 if (gintsts.b.disconnect) {
1634 retval |= dwc_otg_handle_disconnect_intr(core_if);
1636 if (gintsts.b.sessreqintr) {
1637 retval |= dwc_otg_handle_session_req_intr(core_if);
1639 if (gintsts.b.wkupintr) {
1640 retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
1642 if (gintsts.b.usbsuspend) {
1643 retval |= dwc_otg_handle_usb_suspend_intr(core_if);
1645 #ifdef CONFIG_USB_DWC_OTG_LPM
1646 if (gintsts.b.lpmtranrcvd) {
1647 retval |= dwc_otg_handle_lpm_intr(core_if);
1650 if (gintsts.b.restoredone) {
1652 if (core_if->power_down == 2)
1653 core_if->hibernation_suspend = -1;
1654 else if (core_if->power_down == 3 && core_if->xhib == 2) {
1655 gpwrdn_data_t gpwrdn = {.d32 = 0 };
1656 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1657 dctl_data_t dctl = {.d32 = 0 };
1659 DWC_WRITE_REG32(&core_if->
1660 core_global_regs->gintsts,
1663 DWC_DEBUGPL(DBG_ANY,
1664 "RESTORE DONE generated\n");
1666 gpwrdn.b.restore = 1;
1667 DWC_MODIFY_REG32(&core_if->core_global_regs->
1668 gpwrdn, gpwrdn.d32, 0);
1671 pcgcctl.b.rstpdwnmodule = 1;
1672 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
1675 DWC_WRITE_REG32(&core_if->core_global_regs->
1677 core_if->gr_backup->
1679 DWC_WRITE_REG32(&core_if->dev_if->
1680 dev_global_regs->dcfg,
1681 core_if->dr_backup->dcfg);
1682 DWC_WRITE_REG32(&core_if->dev_if->
1683 dev_global_regs->dctl,
1684 core_if->dr_backup->dctl);
1687 dctl.b.pwronprgdone = 1;
1688 DWC_MODIFY_REG32(&core_if->dev_if->
1689 dev_global_regs->dctl, 0,
1693 dwc_otg_restore_global_regs(core_if);
1694 dwc_otg_restore_dev_regs(core_if, 0);
1697 dctl.b.pwronprgdone = 1;
1698 DWC_MODIFY_REG32(&core_if->dev_if->
1699 dev_global_regs->dctl,
1704 pcgcctl.b.enbl_extnd_hiber = 1;
1705 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
1708 /* The core will be in ON STATE */
1709 core_if->lx_state = DWC_OTG_L0;
1712 DWC_SPINUNLOCK(core_if->lock);
1714 && core_if->pcd_cb->resume_wakeup) {
1715 core_if->pcd_cb->resume_wakeup(core_if->
1719 DWC_SPINLOCK(core_if->lock);
1723 gintsts.b.restoredone = 1;
1724 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,
1726 DWC_PRINTF(" --Restore done interrupt received-- \n");
1729 if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
1730 /* The port interrupt occurs while in device mode with HPRT0
1731 * Port Enable/Disable.
1734 gintsts.b.portintr = 1;
1735 DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,
1741 DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
1743 if (gpwrdn.b.disconn_det && gpwrdn.b.disconn_det_msk) {
1744 CLEAR_GPWRDN_INTR(core_if, disconn_det);
1745 if (gpwrdn.b.linestate == 0) {
1746 dwc_otg_handle_pwrdn_disconnect_intr(core_if);
1749 ("Disconnect detected while linestate is not 0\n");
1754 if (gpwrdn.b.lnstschng && gpwrdn.b.lnstchng_msk) {
1755 CLEAR_GPWRDN_INTR(core_if, lnstschng);
1756 /* remote wakeup from hibernation */
1757 if (gpwrdn.b.linestate == 2 || gpwrdn.b.linestate == 1) {
1758 dwc_otg_handle_pwrdn_wakeup_detected_intr
1761 DWC_PRINTF("gpwrdn.linestate = %d\n",
1762 gpwrdn.b.linestate);
1766 if (gpwrdn.b.rst_det && gpwrdn.b.rst_det_msk) {
1767 CLEAR_GPWRDN_INTR(core_if, rst_det);
1768 if (gpwrdn.b.linestate == 0) {
1769 DWC_PRINTF("Reset detected\n");
1771 dwc_otg_device_hibernation_restore(core_if,
1775 if (gpwrdn.b.srp_det && gpwrdn.b.srp_det_msk) {
1776 CLEAR_GPWRDN_INTR(core_if, srp_det);
1777 dwc_otg_handle_pwrdn_srp_intr(core_if);
1781 /* Handle ADP interrupt here */
1782 if (gpwrdn.b.adp_int) {
1783 DWC_PRINTF("ADP interrupt\n");
1784 CLEAR_GPWRDN_INTR(core_if, adp_int);
1785 dwc_otg_adp_handle_intr(core_if);
1788 if (gpwrdn.b.sts_chngint && gpwrdn.b.sts_chngint_msk) {
1789 DWC_PRINTF("STS CHNG interrupt asserted\n");
1790 CLEAR_GPWRDN_INTR(core_if, sts_chngint);
1791 dwc_otg_handle_pwrdn_stschng_intr(otg_dev);
1796 DWC_SPINUNLOCK(core_if->lock);