Merge branch develop-3.10 into develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / drivers / usb / dwc_otg_310 / dwc_otg_cil_intr.c
1 /* ==========================================================================
2  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
3  * $Revision: #35 $
4  * $Date: 2012/12/21 $
5  * $Change: 2131568 $
6  *
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.
10  *
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.
20  *
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
31  * DAMAGE.
32  * ========================================================================== */
33
34 /** @file
35  *
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.
39  *
40  * This file contains the Common Interrupt handlers.
41  */
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"
49
50 #ifdef DEBUG
51 inline const char *op_state_str(dwc_otg_core_if_t *core_if)
52 {
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")))));
58 }
59 #endif
60
61 /** This function will log a debug message
62  *
63  * @param core_if Programming view of DWC_otg controller.
64  */
65 int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t *core_if)
66 {
67         gintsts_data_t gintsts;
68         DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
69                  dwc_otg_mode(core_if) ? "Host" : "Device");
70
71         /* Clear interrupt */
72         gintsts.d32 = 0;
73         gintsts.b.modemismatch = 1;
74         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
75         return 1;
76 }
77
78 /**
79  * This function handles the OTG Interrupts. It reads the OTG
80  * Interrupt Register (GOTGINT) to determine what interrupt has
81  * occurred.
82  *
83  * @param core_if Programming view of DWC_otg controller.
84  */
85 int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *core_if)
86 {
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;
91         gpwrdn_data_t gpwrdn;
92         dctl_data_t dctl = {.d32 = 0 };
93
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));
98
99         if (gotgint.b.sesenddet) {
100                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
101                             "Session End Detected++ (%s)\n",
102                             op_state_str(core_if));
103
104                 /* do soft disconnect */
105                 dctl.d32 =
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,
109                                 dctl.d32);
110                 dwc_otg_disable_global_interrupts(core_if);
111                 core_if->otg_dev->pcd->vbus_status = USB_BC_TYPE_DISCNT;
112
113                 DWC_PRINTF("********session end ,soft disconnect***********\n");
114
115                 gotgctl.d32 = DWC_READ_REG32(&global_regs->gotgctl);
116
117                 if (core_if->op_state == B_HOST) {
118                         cil_pcd_start(core_if);
119                         core_if->op_state = B_PERIPHERAL;
120                 } else {
121                         /* If not B_HOST and Device HNP still set. HNP
122                          * Did not succeed!*/
123                         if (gotgctl.b.devhnpen) {
124                                 DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
125                                 __DWC_ERROR
126                                     ("Device Not Connected/Responding!\n");
127                         }
128
129                         /* If Session End Detected the B-Cable has
130                          * been disconnected. */
131                         /* Reset PCD and Gadget driver to a
132                          * clean state. */
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);
137
138                         if (core_if->otg_ver) {
139                                 /** PET testing*/
140                                 gotgctl.d32 = 0;
141                                 gotgctl.b.devhnpen = 1;
142                                 DWC_MODIFY_REG32(&global_regs->gotgctl,
143                                                  gotgctl.d32, 0);
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,
148                                                                    core_if, 3000,
149                                                                    "initate SRP");
150                                         core_if->test_mode = 0;
151                                 } else if (core_if->adp_enable) {
152                                         if (core_if->power_down == 2) {
153                                                 gpwrdn.d32 = 0;
154                                                 gpwrdn.b.pwrdnswtch = 1;
155                                                 DWC_MODIFY_REG32
156                                                     (&core_if->core_global_regs->gpwrdn,
157                                                      gpwrdn.d32, 0);
158                                         }
159
160                                         gpwrdn.d32 = 0;
161                                         gpwrdn.b.pmuintsel = 1;
162                                         gpwrdn.b.pmuactv = 1;
163                                         DWC_MODIFY_REG32(&core_if->
164                                                          core_global_regs->
165                                                          gpwrdn, 0, gpwrdn.d32);
166                                         dwc_otg_adp_sense_start(core_if);
167                                 }
168                         }
169                 }
170                 if (core_if->otg_ver == 0) {
171                         gotgctl.d32 = 0;
172                         gotgctl.b.devhnpen = 1;
173                         DWC_MODIFY_REG32(&global_regs->gotgctl, gotgctl.d32, 0);
174                 }
175         }
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) {
181
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;
186                         } else {
187                                 DWC_SPINUNLOCK(core_if->lock);
188                                 cil_pcd_resume(core_if);
189                                 DWC_SPINLOCK(core_if->lock);
190                                 /* Clear Session Request */
191                                 gotgctl.d32 = 0;
192                                 gotgctl.b.sesreq = 1;
193                                 DWC_MODIFY_REG32(&global_regs->gotgctl,
194                                                  gotgctl.d32, 0);
195                         }
196                 }
197         }
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)
205                         dwc_udelay(100);
206                 if (gotgctl.b.hstnegscs) {
207                         if (dwc_otg_is_host_mode(core_if)) {
208                                 core_if->op_state = B_HOST;
209                                 /*
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
217                                  * complains loudly.
218                                  */
219                                 gintmsk.d32 = 0;
220                                 gintmsk.b.sofintr = 1;
221                                 /* gintmsk.b.usbsuspend = 1; */
222                                 DWC_MODIFY_REG32(&global_regs->gintmsk,
223                                                  gintmsk.d32, 0);
224                                 /* Call callback function with spin lock released */
225                                 DWC_SPINUNLOCK(core_if->lock);
226                                 cil_pcd_stop(core_if);
227                                 /*
228                                  * Initialize the Core for Host mode.
229                                  */
230                                 cil_hcd_start(core_if);
231                                 DWC_SPINLOCK(core_if->lock);
232                         }
233                 } else {
234                         gotgctl.d32 = 0;
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");
240                 }
241         }
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.
247                  */
248                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
249                             "Host Negotiation Detected++ (%s)\n",
250                             (dwc_otg_is_host_mode(core_if) ? "Host" :
251                              "Device"));
252                 if (dwc_otg_is_device_mode(core_if)) {
253                         DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
254                                     core_if->op_state);
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;
260                 } else {
261                         /*
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
268                          * complains loudly.
269                          */
270                         gintmsk.d32 = 0;
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;
278                 }
279         }
280         if (gotgint.b.adevtoutchng) {
281                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
282                             "A-Device Timeout Change++\n");
283         }
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);
289         }
290
291         /* Clear GOTGINT */
292         DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, gotgint.d32);
293
294         return 1;
295 }
296
297 void w_conn_id_status_change(void *p)
298 {
299         dwc_otg_core_if_t *core_if = p;
300         uint32_t count = 0;
301         gotgctl_data_t gotgctl = {.d32 = 0 };
302         dwc_otg_pcd_t *pcd = core_if->otg_dev->pcd;
303
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);
307
308         /* B-Device connector (Device Mode) */
309         if (gotgctl.b.conidsts) {
310                 gotgctl_data_t gotgctl_local;
311
312                 /* Wait for switch to device mode. */
313                 while (!dwc_otg_is_device_mode(core_if)) {
314                         gotgctl_local.d32 =
315                             DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
316                         DWC_DEBUGPL(DBG_ANY,
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)
322                                 goto host;
323                         if (++count > 10000)
324                                 break;
325                 }
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);
337         } else {
338 host:
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" :
343                                      "Peripheral"));
344                         dwc_mdelay(1);  /* vahrama previously was 100 */
345                         if (++count > 10000)
346                                 break;
347                 }
348                 DWC_ASSERT(++count < 10000,
349                            "Connection id status change timed out");
350                 core_if->op_state = A_HOST;
351
352                 cancel_delayed_work(&pcd->check_vbus_work);
353
354                 /*
355                  * Initialize the Core for Host mode.
356                  */
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);
361                 else
362                         dwc_otg_core_init(core_if);
363                 dwc_otg_enable_global_interrupts(core_if);
364                 cil_hcd_start(core_if);
365         }
366 }
367
368 /**
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
372  * Transition.
373  *
374  * This only occurs when the cable is connected/removed from the PHY
375  * connector.
376  *
377  * @param core_if Programming view of DWC_otg controller.
378  */
379 int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *core_if)
380 {
381
382         /*
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.
388          */
389         gintmsk_data_t gintmsk = {.d32 = 0 };
390         gintsts_data_t gintsts = {.d32 = 0 };
391
392         if (core_if->usb_mode != USB_MODE_NORMAL)
393                 goto out;
394
395         gintmsk.b.sofintr = 1;
396         DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
397         DWC_DEBUGPL(DBG_CIL,
398                     " ++Connector ID Status Change Interrupt++  (%s)\n",
399                     (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
400
401         DWC_SPINUNLOCK(core_if->lock);
402
403         /*
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
406          */
407
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);
411 out:
412         /* Set flag and clear interrupt */
413         gintsts.b.conidstschng = 1;
414         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
415
416         return 1;
417 }
418
419 /**
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.
425  *
426  * @param core_if Programming view of DWC_otg controller.
427  */
428 int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t *core_if)
429 {
430         gintsts_data_t gintsts;
431
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");
437                 gotgctl.d32 =
438                     DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
439                 if (gotgctl.b.sesreqscs)
440                         DWC_PRINTF("SRP Success\n");
441                 else
442                         DWC_PRINTF("SRP Fail\n");
443                 if (core_if->otg_ver) {
444                         gotgctl.d32 = 0;
445                         gotgctl.b.devhnpen = 1;
446                         DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl,
447                                          gotgctl.d32, 0);
448                 }
449         } else {
450                 hprt0_data_t hprt0;
451                 DWC_PRINTF("SRP: Host mode\n");
452
453                 /* Turn on the port power bit. */
454                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
455                 hprt0.b.prtpwr = 1;
456                 DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
457
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);
461         }
462 #endif
463
464         /* Clear interrupt */
465         gintsts.d32 = 0;
466         gintsts.b.sessreqintr = 1;
467         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
468
469         return 1;
470 }
471
472 void w_wakeup_detected(void *data)
473 {
474         dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) data;
475         /*
476          * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
477          * so that OPT tests pass with all PHYs).
478          */
479         hprt0_data_t hprt0 = {.d32 = 0 };
480 #if 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);
485         dwc_udelay(10);
486 #endif
487         hprt0.d32 = dwc_otg_read_hprt0(core_if);
488         DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
489         dwc_mdelay(70);
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));
494
495         cil_hcd_resume(core_if);
496
497         /** Change to L0 state*/
498         core_if->lx_state = DWC_OTG_L0;
499 }
500
501 static inline void rk_dwc_otg_phy_soft_reset(dwc_otg_core_if_t *core_if)
502 {
503         struct dwc_otg_platform_data *pldata;
504         guid_data_t guid;
505
506         pldata = core_if->otg_dev->pldata;
507         guid.d32 = core_if->core_global_regs->guid;
508
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.
516                  */
517                 rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, true);
518                 udelay(50);
519                 rk3288_cru_set_soft_reset(RK3288_SOFT_RST_USBHOST1PHY, false);
520                 udelay(50);
521
522                 pldata->phy_suspend(pldata, USB_PHY_SUSPEND);
523                 udelay(50);
524                 pldata->phy_suspend(pldata, USB_PHY_ENABLED);
525                 udelay(100);
526         }
527 }
528
529 /**
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.
535  */
536 int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t *core_if)
537 {
538         gintsts_data_t gintsts;
539
540         DWC_DEBUGPL(DBG_ANY,
541                     "++Resume and Remote Wakeup Detected Interrupt++\n");
542
543         DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
544
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 };
554
555                                 power.d32 = DWC_READ_REG32(core_if->pcgcctl);
556                                 DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
557                                             power.d32);
558
559                                 power.b.stoppclk = 0;
560                                 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
561
562                                 power.b.pwrclmp = 0;
563                                 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
564
565                                 power.b.rstpdwnmodule = 0;
566                                 DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
567                         }
568 #endif
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);
573
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->
577                                                                p);
578                         }
579                         DWC_SPINLOCK(core_if->lock);
580                 } else {
581                         glpmcfg_data_t lpmcfg;
582                         pcgcctl_data_t pcgcctl = {.d32 = 0 };
583
584                         lpmcfg.d32 =
585                             DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
586                         lpmcfg.b.hird_thres &= (~(1 << 4));
587                         lpmcfg.b.en_utmi_sleep = 0;
588
589                         /* Clear Enbl_L1Gating bit. */
590                         pcgcctl.b.enbl_sleep_gating = 1;
591                         DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
592
593                         DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
594                                         lpmcfg.d32);
595                 }
596                 /** Change to L0 state*/
597                 core_if->lx_state = DWC_OTG_L0;
598         } else {
599                 if (core_if->lx_state != DWC_OTG_L1) {
600                         pcgcctl_data_t pcgcctl = {.d32 = 0 };
601
602                         /* Restart the Phy Clock */
603                         pcgcctl.b.stoppclk = 1;
604                         DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0);
605                         udelay(10);
606
607                         rk_dwc_otg_phy_soft_reset(core_if);
608
609                         DWC_TASK_SCHEDULE(core_if->wkp_tasklet);
610                 } else {
611                         /** Change to L0 state*/
612                         core_if->lx_state = DWC_OTG_L0;
613                 }
614         }
615
616         /* Clear interrupt */
617         gintsts.d32 = 0;
618         gintsts.b.wkupintr = 1;
619         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
620
621         return 1;
622 }
623
624 /**
625  * This interrupt indicates that the Wakeup Logic has detected a
626  * Device disconnect.
627  */
628 static int32_t dwc_otg_handle_pwrdn_disconnect_intr(dwc_otg_core_if_t *core_if)
629 {
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);
633
634         DWC_PRINTF("%s called\n", __FUNCTION__);
635
636         if (!core_if->hibernation_suspend) {
637                 DWC_PRINTF("Already exited from Hibernation\n");
638                 return 1;
639         }
640
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);
644         dwc_udelay(10);
645
646         /* Reset the core */
647         gpwrdn.d32 = 0;
648         gpwrdn.b.pwrdnrstn = 1;
649         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
650         dwc_udelay(10);
651
652         /* Disable power clamps */
653         gpwrdn.d32 = 0;
654         gpwrdn.b.pwrdnclmp = 1;
655         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
656
657         /* Remove reset the core signal */
658         gpwrdn.d32 = 0;
659         gpwrdn.b.pwrdnrstn = 1;
660         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
661         dwc_udelay(10);
662
663         /* Disable PMU interrupt */
664         gpwrdn.d32 = 0;
665         gpwrdn.b.pmuintsel = 1;
666         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
667
668         core_if->hibernation_suspend = 0;
669
670         /* Disable PMU */
671         gpwrdn.d32 = 0;
672         gpwrdn.b.pmuactv = 1;
673         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
674         dwc_udelay(10);
675
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);
681         } else {
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);
686         }
687
688         return 1;
689 }
690
691 /**
692  * This interrupt indicates that the Wakeup Logic has detected a
693  * remote wakeup sequence.
694  */
695 static int32_t dwc_otg_handle_pwrdn_wakeup_detected_intr(dwc_otg_core_if_t *
696                                                          core_if)
697 {
698         gpwrdn_data_t gpwrdn = {.d32 = 0 };
699         DWC_DEBUGPL(DBG_ANY,
700                     "++Powerdown Remote Wakeup Detected Interrupt++\n");
701
702         if (!core_if->hibernation_suspend) {
703                 DWC_PRINTF("Already exited from Hibernation\n");
704                 return 1;
705         }
706
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);
712                 }
713         } else {
714                 if ((core_if->power_down == 2)
715                     && (core_if->hibernation_suspend == 1)) {
716                         dwc_otg_host_hibernation_restore(core_if, 1, 0);
717                 }
718         }
719         return 1;
720 }
721
722 static int32_t dwc_otg_handle_pwrdn_idsts_change(dwc_otg_device_t *otg_dev)
723 {
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;
727
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");
733                         return 1;
734                 }
735                 DWC_DEBUGPL(DBG_ANY,
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,
740                                  0);
741                 dwc_udelay(10);
742
743                 /* Reset the core */
744                 gpwrdn.d32 = 0;
745                 gpwrdn.b.pwrdnrstn = 1;
746                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
747                                  0);
748                 dwc_udelay(10);
749
750                 /* Disable power clamps */
751                 gpwrdn.d32 = 0;
752                 gpwrdn.b.pwrdnclmp = 1;
753                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
754                                  0);
755
756                 /* Remove reset the core signal */
757                 gpwrdn.d32 = 0;
758                 gpwrdn.b.pwrdnrstn = 1;
759                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
760                                  gpwrdn.d32);
761                 dwc_udelay(10);
762
763                 /* Disable PMU interrupt */
764                 gpwrdn.d32 = 0;
765                 gpwrdn.b.pmuintsel = 1;
766                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
767                                  0);
768
769                 /*Indicates that we are exiting from hibernation */
770                 core_if->hibernation_suspend = 0;
771
772                 /* Disable PMU */
773                 gpwrdn.d32 = 0;
774                 gpwrdn.b.pmuactv = 1;
775                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
776                                  0);
777                 dwc_udelay(10);
778
779                 gpwrdn.d32 = core_if->gr_backup->gpwrdn_local;
780                 if (gpwrdn.b.dis_vbus == 1) {
781                         gpwrdn.d32 = 0;
782                         gpwrdn.b.dis_vbus = 1;
783                         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
784                                          gpwrdn.d32, 0);
785                 }
786
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);
792                 } else {
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);
797                 }
798         }
799
800         if (core_if->adp_enable) {
801                 uint8_t is_host = 0;
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;
807 #endif
808 #ifndef DWC_DEVICE_ONLY
809                 if (!gpwrdn_temp.b.idsts) {
810                         core_if->lock = otg_dev->hcd->lock;
811                         is_host = 1;
812                 }
813 #endif
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;
829
830                 /* Disable PMU and restart ADP */
831                 gpwrdn_temp.d32 = 0;
832                 gpwrdn_temp.b.pmuactv = 1;
833                 gpwrdn_temp.b.pmuintsel = 1;
834                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
835                                  0);
836                 DWC_PRINTF("Check point 1\n");
837                 dwc_mdelay(110);
838                 dwc_otg_adp_start(core_if, is_host);
839                 DWC_SPINLOCK(core_if->lock);
840         }
841
842         return 1;
843 }
844
845 static int32_t dwc_otg_handle_pwrdn_session_change(dwc_otg_core_if_t *core_if)
846 {
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__);
850
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");
855                         return 1;
856                 }
857
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 */
865                         return 1;
866                 }
867
868                 /* Switch on the voltage to the core */
869                 gpwrdn.d32 = 0;
870                 gpwrdn.b.pwrdnswtch = 1;
871                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
872                                  0);
873                 dwc_udelay(10);
874
875                 /* Reset the core */
876                 gpwrdn.d32 = 0;
877                 gpwrdn.b.pwrdnrstn = 1;
878                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
879                                  0);
880                 dwc_udelay(10);
881
882                 /* Disable power clamps */
883                 gpwrdn.d32 = 0;
884                 gpwrdn.b.pwrdnclmp = 1;
885                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
886                                  0);
887
888                 /* Remove reset the core signal */
889                 gpwrdn.d32 = 0;
890                 gpwrdn.b.pwrdnrstn = 1;
891                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
892                                  gpwrdn.d32);
893                 dwc_udelay(10);
894
895                 /* Disable PMU interrupt */
896                 gpwrdn.d32 = 0;
897                 gpwrdn.b.pmuintsel = 1;
898                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
899                                  0);
900                 dwc_udelay(10);
901
902                 /*Indicates that we are exiting from hibernation */
903                 core_if->hibernation_suspend = 0;
904
905                 /* Disable PMU */
906                 gpwrdn.d32 = 0;
907                 gpwrdn.b.pmuactv = 1;
908                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
909                                  0);
910                 dwc_udelay(10);
911
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);
916
917                 if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ||
918                     otg_cap_param == DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE) {
919                         /*
920                          * Initiate SRP after initial ADP probe.
921                          */
922                         dwc_otg_initiate_srp(core_if);
923                 }
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 */
929                 gpwrdn.d32 = 0;
930                 gpwrdn.b.pmuintsel = 1;
931                 gpwrdn.b.pmuactv = 1;
932                 DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32,
933                                  0);
934
935                 /*
936                  * Initialize the Core for Device mode.
937                  */
938                 core_if->op_state = B_PERIPHERAL;
939                 cil_pcd_start(core_if);
940                 dwc_otg_enable_global_interrupts(core_if);
941         }
942
943         return 1;
944 }
945
946 /**
947  * This interrupt indicates that the Wakeup Logic has detected a
948  * status change either on IDDIG or BSessVld.
949  */
950 static uint32_t dwc_otg_handle_pwrdn_stschng_intr(dwc_otg_device_t *otg_dev)
951 {
952         int retval;
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;
956
957         DWC_PRINTF("%s called\n", __FUNCTION__);
958
959         if (core_if->power_down == 2) {
960                 if (core_if->hibernation_suspend <= 0) {
961                         DWC_PRINTF("Already exited from Hibernation\n");
962                         return 1;
963                 } else
964                         gpwrdn_temp.d32 = core_if->gr_backup->gpwrdn_local;
965
966         } else {
967                 gpwrdn_temp.d32 = core_if->adp.gpwrdn;
968         }
969
970         gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
971
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);
976         }
977
978         return retval;
979 }
980
981 /**
982  * This interrupt indicates that the Wakeup Logic has detected a
983  * SRP.
984  */
985 static int32_t dwc_otg_handle_pwrdn_srp_intr(dwc_otg_core_if_t *core_if)
986 {
987         gpwrdn_data_t gpwrdn = {.d32 = 0 };
988
989         DWC_PRINTF("%s called\n", __FUNCTION__);
990
991         if (!core_if->hibernation_suspend) {
992                 DWC_PRINTF("Already exited from Hibernation\n");
993                 return 1;
994         }
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);
999         }
1000 #endif
1001
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);
1005         dwc_udelay(10);
1006
1007         /* Reset the core */
1008         gpwrdn.d32 = 0;
1009         gpwrdn.b.pwrdnrstn = 1;
1010         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1011         dwc_udelay(10);
1012
1013         /* Disable power clamps */
1014         gpwrdn.d32 = 0;
1015         gpwrdn.b.pwrdnclmp = 1;
1016         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1017
1018         /* Remove reset the core signal */
1019         gpwrdn.d32 = 0;
1020         gpwrdn.b.pwrdnrstn = 1;
1021         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
1022         dwc_udelay(10);
1023
1024         /* Disable PMU interrupt */
1025         gpwrdn.d32 = 0;
1026         gpwrdn.b.pmuintsel = 1;
1027         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1028
1029         /* Indicates that we are exiting from hibernation */
1030         core_if->hibernation_suspend = 0;
1031
1032         /* Disable PMU */
1033         gpwrdn.d32 = 0;
1034         gpwrdn.b.pmuactv = 1;
1035         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1036         dwc_udelay(10);
1037
1038         /* Programm Disable VBUS to 0 */
1039         gpwrdn.d32 = 0;
1040         gpwrdn.b.dis_vbus = 1;
1041         DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
1042
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);
1048
1049         return 1;
1050 }
1051
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)
1055 {
1056         pcgcctl_data_t pcgcctl;
1057         DWC_DEBUGPL(DBG_ANY, "++Restore Done Interrupt++\n");
1058
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 };
1063                 /*
1064                  * If restore mode is Remote Wakeup,
1065                  * unmask Remote Wakeup interrupt.
1066                  */
1067                 gintmsk.b.wkupintr = 1;
1068                 DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk,
1069                                  0, gintmsk.d32);
1070         }
1071
1072         return 1;
1073 }
1074
1075 /**
1076  * This interrupt indicates that a device has been disconnected from
1077  * the root port.
1078  */
1079 int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t *core_if)
1080 {
1081         gintsts_data_t gintsts;
1082
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));
1086
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
1091                  * start the PCD. */
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 };
1099                 gotgctl.d32 =
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.
1105                          */
1106                 } else if (gotgctl.b.devhnpen == 0) {
1107                         /* If in device mode Disconnect and stop the HCD, then
1108                          * start the PCD. */
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;
1114                 } else {
1115                         DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
1116                 }
1117         } else {
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,
1129                                                  gpwrdn.d32);
1130                                 dwc_otg_adp_probe_start(core_if);
1131
1132                                 /* Power off the core */
1133                                 if (core_if->power_down == 2) {
1134                                         gpwrdn.d32 = 0;
1135                                         gpwrdn.b.pwrdnswtch = 1;
1136                                         DWC_MODIFY_REG32
1137                                             (&core_if->core_global_regs->gpwrdn,
1138                                              gpwrdn.d32, 0);
1139                                 }
1140                         }
1141                 }
1142         }
1143 #endif
1144         /* Change to L3(OFF) state */
1145         core_if->lx_state = DWC_OTG_L3;
1146
1147         gintsts.d32 = 0;
1148         gintsts.b.disconnect = 1;
1149         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1150         return 1;
1151 }
1152
1153 /**
1154  * This interrupt indicates that SUSPEND state has been detected on
1155  * the USB.
1156  *
1157  * For HNP the USB Suspend interrupt signals the change from
1158  * "a_peripheral" to "a_host".
1159  *
1160  * When power management is enabled the core will be put in low power
1161  * mode.
1162  */
1163 int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t *core_if)
1164 {
1165         dsts_data_t dsts;
1166         gintsts_data_t gintsts;
1167         dcfg_data_t dcfg;
1168
1169         DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
1170
1171         if ((core_if->otg_ver == 1) && (core_if->op_state == A_PERIPHERAL))
1172                 dwc_mdelay(200);        /* vahrama - WA - see BU's mail */
1173
1174         if (dwc_otg_is_device_mode(core_if)) {
1175                 /* Check the Device status register to determine if the Suspend
1176                  * state is active. */
1177                 dsts.d32 =
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);
1183
1184 #ifdef PARTIAL_POWER_DOWN
1185 /** @todo Add a module parameter for power management. */
1186
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");
1190
1191                         power.b.pwrclmp = 1;
1192                         DWC_WRITE_REG32(core_if->pcgcctl, power.d32);
1193
1194                         power.b.rstpdwnmodule = 1;
1195                         DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
1196
1197                         power.b.stoppclk = 1;
1198                         DWC_MODIFY_REG32(core_if->pcgcctl, 0, power.d32);
1199
1200                 } else {
1201                         DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
1202                 }
1203 #endif
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) {
1207                         dcfg.d32 =
1208                             DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
1209                                            dcfg);
1210                         DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",
1211                                     core_if->lx_state);
1212                         DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",
1213                                     dcfg.b.devaddr);
1214
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 };
1219
1220                                 /* Change to L2(suspend) state */
1221                                 core_if->lx_state = DWC_OTG_L2;
1222
1223                                 /* Clear interrupt in gintsts */
1224                                 gintsts.d32 = 0;
1225                                 gintsts.b.usbsuspend = 1;
1226                                 DWC_WRITE_REG32(&core_if->
1227                                                 core_global_regs->gintsts,
1228                                                 gintsts.d32);
1229                                 DWC_PRINTF("Start of hibernation completed\n");
1230                                 dwc_otg_save_global_regs(core_if);
1231                                 dwc_otg_save_dev_regs(core_if);
1232
1233                                 gusbcfg.d32 =
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 */
1239                                         pcgcctl.d32 = 0;
1240                                         pcgcctl.b.stoppclk = 1;
1241                                         DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1242                                                          pcgcctl.d32);
1243                                         dwc_udelay(10);
1244                                         gpwrdn.b.pmuactv = 1;
1245                                         DWC_MODIFY_REG32
1246                                             (&core_if->core_global_regs->gpwrdn,
1247                                              0, gpwrdn.d32);
1248                                 } else {
1249                                         /* UTMI+ Interface */
1250                                         gpwrdn.b.pmuactv = 1;
1251                                         DWC_MODIFY_REG32
1252                                             (&core_if->core_global_regs->gpwrdn,
1253                                              0, gpwrdn.d32);
1254                                         dwc_udelay(10);
1255                                         pcgcctl.b.stoppclk = 1;
1256                                         DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1257                                                          pcgcctl.d32);
1258                                         dwc_udelay(10);
1259                                 }
1260
1261                                 /* Set flag to indicate that we are in hibernation */
1262                                 core_if->hibernation_suspend = 1;
1263                                 /* Enable interrupts from wake up logic */
1264                                 gpwrdn.d32 = 0;
1265                                 gpwrdn.b.pmuintsel = 1;
1266                                 DWC_MODIFY_REG32(&core_if->
1267                                                  core_global_regs->gpwrdn, 0,
1268                                                  gpwrdn.d32);
1269                                 dwc_udelay(10);
1270
1271                                 /* Unmask device mode interrupts in GPWRDN */
1272                                 gpwrdn.d32 = 0;
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,
1278                                                  gpwrdn.d32);
1279                                 dwc_udelay(10);
1280
1281                                 /* Enable Power Down Clamp */
1282                                 gpwrdn.d32 = 0;
1283                                 gpwrdn.b.pwrdnclmp = 1;
1284                                 DWC_MODIFY_REG32(&core_if->
1285                                                  core_global_regs->gpwrdn, 0,
1286                                                  gpwrdn.d32);
1287                                 dwc_udelay(10);
1288
1289                                 /* Switch off VDD */
1290                                 gpwrdn.d32 = 0;
1291                                 gpwrdn.b.pwrdnswtch = 1;
1292                                 DWC_MODIFY_REG32(&core_if->
1293                                                  core_global_regs->gpwrdn, 0,
1294                                                  gpwrdn.d32);
1295
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->
1299                                                    gpwrdn);
1300                                 DWC_PRINTF("Hibernation completed\n");
1301
1302                                 return 1;
1303                         }
1304                 } else if (core_if->power_down == 3) {
1305                         pcgcctl_data_t pcgcctl = {.d32 = 0 };
1306                         dcfg.d32 =
1307                             DWC_READ_REG32(&core_if->dev_if->dev_global_regs->
1308                                            dcfg);
1309                         DWC_DEBUGPL(DBG_ANY, "lx_state = %08x\n",
1310                                     core_if->lx_state);
1311                         DWC_DEBUGPL(DBG_ANY, " device address = %08d\n",
1312                                     dcfg.b.devaddr);
1313
1314                         if (core_if->lx_state != DWC_OTG_L3 && dcfg.b.devaddr) {
1315                                 DWC_DEBUGPL(DBG_ANY,
1316                                             "Start entering to extended hibernation\n");
1317                                 core_if->xhib = 1;
1318
1319                                 /* Clear interrupt in gintsts */
1320                                 gintsts.d32 = 0;
1321                                 gintsts.b.usbsuspend = 1;
1322                                 DWC_WRITE_REG32(&core_if->
1323                                                 core_global_regs->gintsts,
1324                                                 gintsts.d32);
1325
1326                                 dwc_otg_save_global_regs(core_if);
1327                                 dwc_otg_save_dev_regs(core_if);
1328
1329                                 /* Wait for 10 PHY clocks */
1330                                 dwc_udelay(10);
1331
1332                                 /* Program GPIO register while entering to xHib */
1333                                 DWC_WRITE_REG32(&core_if->core_global_regs->
1334                                                 ggpio, 0x1);
1335
1336                                 pcgcctl.b.enbl_extnd_hiber = 1;
1337                                 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1338                                                  pcgcctl.d32);
1339                                 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1340                                                  pcgcctl.d32);
1341
1342                                 pcgcctl.d32 = 0;
1343                                 pcgcctl.b.extnd_hiber_pwrclmp = 1;
1344                                 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1345                                                  pcgcctl.d32);
1346
1347                                 pcgcctl.d32 = 0;
1348                                 pcgcctl.b.extnd_hiber_switch = 1;
1349                                 core_if->gr_backup->xhib_gpwrdn =
1350                                     DWC_READ_REG32(&core_if->core_global_regs->
1351                                                    gpwrdn);
1352                                 core_if->gr_backup->xhib_pcgcctl =
1353                                     DWC_READ_REG32(core_if->pcgcctl) | pcgcctl.
1354                                     d32;
1355                                 DWC_MODIFY_REG32(core_if->pcgcctl, 0,
1356                                                  pcgcctl.d32);
1357
1358                                 DWC_DEBUGPL(DBG_ANY,
1359                                             "Finished entering to extended hibernation\n");
1360
1361                                 return 1;
1362                         }
1363                 }
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 };
1368                         gotgctl.d32 =
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 };
1372                                 dwc_mdelay(5);
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);
1379                         }
1380                 }
1381         } else {
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;
1390                 }
1391         }
1392
1393         /* Change to L2(suspend) state */
1394         core_if->lx_state = DWC_OTG_L2;
1395
1396         /* Clear interrupt */
1397         gintsts.d32 = 0;
1398         gintsts.b.usbsuspend = 1;
1399         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1400
1401         return 1;
1402 }
1403
1404 static int32_t dwc_otg_handle_xhib_exit_intr(dwc_otg_core_if_t *core_if)
1405 {
1406         gpwrdn_data_t gpwrdn = {.d32 = 0 };
1407         pcgcctl_data_t pcgcctl = {.d32 = 0 };
1408         gahbcfg_data_t gahbcfg = {.d32 = 0 };
1409
1410         dwc_udelay(10);
1411
1412         /* Program GPIO register while entering to xHib */
1413         DWC_WRITE_REG32(&core_if->core_global_regs->ggpio, 0x0);
1414
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);
1418         dwc_udelay(10);
1419
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);
1423         dwc_udelay(10);
1424
1425         restore_lpm_i2c_regs(core_if);
1426
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);
1434
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);
1438
1439         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
1440         DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0x1 << 16);
1441
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);
1446
1447         pcgcctl.d32 = 0;
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);
1452         dwc_udelay(10);
1453
1454         pcgcctl.d32 = 0;
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);
1462
1463         DWC_DEBUGPL(DBG_ANY, "%s called\n", __FUNCTION__);
1464
1465         return 1;
1466 }
1467
1468 #ifdef CONFIG_USB_DWC_OTG_LPM
1469 /**
1470  * This function hadles LPM transaction received interrupt.
1471  */
1472 static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t *core_if)
1473 {
1474         glpmcfg_data_t lpmcfg;
1475         gintsts_data_t gintsts;
1476
1477         if (!core_if->core_params->lpm_enable) {
1478                 DWC_PRINTF("Unexpected LPM interrupt\n");
1479         }
1480
1481         lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg);
1482         DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
1483
1484         if (dwc_otg_is_host_mode(core_if)) {
1485                 cil_hcd_sleep(core_if);
1486         } else {
1487
1488                 pcgcctl_data_t pcgcctl = {.d32 = 0 };
1489
1490                 lpmcfg.b.hird_thres |= (1 << 4);
1491                 lpmcfg.b.en_utmi_sleep = 1;
1492
1493                 pcgcctl.b.enbl_sleep_gating = 1;
1494                 DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
1495
1496                 if (dwc_otg_get_param_besl_enable(core_if)) {
1497                         lpmcfg.b.en_besl = 1;
1498                 }
1499
1500                 DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg,
1501                                 lpmcfg.d32);
1502         }
1503
1504         /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */
1505         dwc_udelay(10);
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;
1510         }
1511
1512         /* Clear interrupt  */
1513         gintsts.d32 = 0;
1514         gintsts.b.lpmtranrcvd = 1;
1515         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32);
1516         return 1;
1517 }
1518 #endif /* CONFIG_USB_DWC_OTG_LPM */
1519
1520 /**
1521  * This function returns the Core Interrupt register.
1522  */
1523 static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t *core_if)
1524 {
1525         uint32_t retval;
1526
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;
1540 #endif
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!
1544          */
1545         gintmsk_common.b.portintr = 1;
1546
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);
1550
1551 #ifdef DEBUG
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);
1556         }
1557 #endif
1558         if (gahbcfg.b.glblintrmsk) {
1559                 retval = (gintsts.d32 & gintmsk.d32) & gintmsk_common.d32;
1560                 return retval;
1561         } else {
1562                 return 0;
1563         }
1564 }
1565
1566 /* MACRO for clearing interupt bits in GPWRDN register */
1567 #define CLEAR_GPWRDN_INTR(__core_if, __intr) \
1568 do { \
1569                 gpwrdn_data_t gpwrdn = {.d32 = 0}; \
1570                 gpwrdn.b.__intr = 1; \
1571                 DWC_MODIFY_REG32(&__core_if->core_global_regs->gpwrdn, \
1572                 0, gpwrdn.d32); \
1573 } while (0)
1574
1575 /**
1576  * Common interrupt handler.
1577  *
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
1582  * - OTG 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
1588  *
1589  */
1590 int32_t dwc_otg_handle_common_intr(void *dev)
1591 {
1592         int retval = 0;
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);
1598
1599         if (dwc_otg_check_haps_status(core_if) == -1) {
1600                 DWC_WARN("HAPS is disconnected");
1601                 return retval;
1602         }
1603
1604         if (dwc_otg_is_device_mode(core_if))
1605                 core_if->frame_num = dwc_otg_get_frame_number(core_if);
1606
1607         if (core_if->lock)
1608                 DWC_SPINLOCK(core_if->lock);
1609
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);
1613                 core_if->xhib = 2;
1614                 if (core_if->lock)
1615                         DWC_SPINUNLOCK(core_if->lock);
1616
1617                 return retval;
1618         }
1619
1620         if (core_if->hibernation_suspend <= 0) {
1621                 gintsts.d32 = dwc_otg_read_common_intr(core_if);
1622
1623                 if (gintsts.b.modemismatch) {
1624                         retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
1625                 }
1626                 if (gintsts.b.otgintr) {
1627                         retval |= dwc_otg_handle_otg_intr(core_if);
1628                 }
1629                 if (gintsts.b.conidstschng) {
1630                         retval |=
1631                             dwc_otg_handle_conn_id_status_change_intr(core_if);
1632                 }
1633                 if (gintsts.b.disconnect) {
1634                         retval |= dwc_otg_handle_disconnect_intr(core_if);
1635                 }
1636                 if (gintsts.b.sessreqintr) {
1637                         retval |= dwc_otg_handle_session_req_intr(core_if);
1638                 }
1639                 if (gintsts.b.wkupintr) {
1640                         retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
1641                 }
1642                 if (gintsts.b.usbsuspend) {
1643                         retval |= dwc_otg_handle_usb_suspend_intr(core_if);
1644                 }
1645 #ifdef CONFIG_USB_DWC_OTG_LPM
1646                 if (gintsts.b.lpmtranrcvd) {
1647                         retval |= dwc_otg_handle_lpm_intr(core_if);
1648                 }
1649 #endif
1650                 if (gintsts.b.restoredone) {
1651                         gintsts.d32 = 0;
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 };
1658
1659                                 DWC_WRITE_REG32(&core_if->
1660                                                 core_global_regs->gintsts,
1661                                                 0xFFFFFFFF);
1662
1663                                 DWC_DEBUGPL(DBG_ANY,
1664                                             "RESTORE DONE generated\n");
1665
1666                                 gpwrdn.b.restore = 1;
1667                                 DWC_MODIFY_REG32(&core_if->core_global_regs->
1668                                                  gpwrdn, gpwrdn.d32, 0);
1669                                 dwc_udelay(10);
1670
1671                                 pcgcctl.b.rstpdwnmodule = 1;
1672                                 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
1673                                                  0);
1674
1675                                 DWC_WRITE_REG32(&core_if->core_global_regs->
1676                                                 gusbcfg,
1677                                                 core_if->gr_backup->
1678                                                 gusbcfg_local);
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);
1685                                 dwc_udelay(50);
1686
1687                                 dctl.b.pwronprgdone = 1;
1688                                 DWC_MODIFY_REG32(&core_if->dev_if->
1689                                                  dev_global_regs->dctl, 0,
1690                                                  dctl.d32);
1691                                 dwc_udelay(10);
1692
1693                                 dwc_otg_restore_global_regs(core_if);
1694                                 dwc_otg_restore_dev_regs(core_if, 0);
1695
1696                                 dctl.d32 = 0;
1697                                 dctl.b.pwronprgdone = 1;
1698                                 DWC_MODIFY_REG32(&core_if->dev_if->
1699                                                  dev_global_regs->dctl,
1700                                                  dctl.d32, 0);
1701                                 dwc_udelay(10);
1702
1703                                 pcgcctl.d32 = 0;
1704                                 pcgcctl.b.enbl_extnd_hiber = 1;
1705                                 DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32,
1706                                                  0);
1707
1708                                 /* The core will be in ON STATE */
1709                                 core_if->lx_state = DWC_OTG_L0;
1710                                 core_if->xhib = 0;
1711
1712                                 DWC_SPINUNLOCK(core_if->lock);
1713                                 if (core_if->pcd_cb
1714                                     && core_if->pcd_cb->resume_wakeup) {
1715                                         core_if->pcd_cb->resume_wakeup(core_if->
1716                                                                        pcd_cb->
1717                                                                        p);
1718                                 }
1719                                 DWC_SPINLOCK(core_if->lock);
1720
1721                         }
1722
1723                         gintsts.b.restoredone = 1;
1724                         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,
1725                                         gintsts.d32);
1726                         DWC_PRINTF(" --Restore done interrupt received-- \n");
1727                         retval |= 1;
1728                 }
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.
1732                          */
1733                         gintsts.d32 = 0;
1734                         gintsts.b.portintr = 1;
1735                         DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,
1736                                         gintsts.d32);
1737                         retval |= 1;
1738
1739                 }
1740         } else {
1741                 DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
1742
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);
1747                         } else {
1748                                 DWC_PRINTF
1749                                     ("Disconnect detected while linestate is not 0\n");
1750                         }
1751
1752                         retval |= 1;
1753                 }
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
1759                                     (core_if);
1760                         } else {
1761                                 DWC_PRINTF("gpwrdn.linestate = %d\n",
1762                                            gpwrdn.b.linestate);
1763                         }
1764                         retval |= 1;
1765                 }
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");
1770                                 retval |=
1771                                     dwc_otg_device_hibernation_restore(core_if,
1772                                                                        0, 1);
1773                         }
1774                 }
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);
1778                         retval |= 1;
1779                 }
1780         }
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);
1786                 retval |= 1;
1787         }
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);
1792
1793                 retval |= 1;
1794         }
1795         if (core_if->lock)
1796                 DWC_SPINUNLOCK(core_if->lock);
1797
1798         return retval;
1799 }