1 /* $NetBSD: dwc2_coreintr.c,v 1.11 2016/02/24 22:17:54 skrll Exp $ */ 2 3 /* 4 * core_intr.c - DesignWare HS OTG Controller common interrupt handling 5 * 6 * Copyright (C) 2004-2013 Synopsys, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The names of the above-listed copyright holders may not be used 18 * to endorse or promote products derived from this software without 19 * specific prior written permission. 20 * 21 * ALTERNATIVELY, this software may be distributed under the terms of the 22 * GNU General Public License ("GPL") as published by the Free Software 23 * Foundation; either version 2 of the License, or (at your option) any 24 * later version. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 27 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 28 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 30 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 31 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 33 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 34 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 35 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * This file contains the common interrupt handlers 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: dwc2_coreintr.c,v 1.11 2016/02/24 22:17:54 skrll Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/kernel.h> 48 #include <sys/mutex.h> 49 #include <sys/pool.h> 50 #include <sys/bus.h> 51 #include <sys/callout.h> 52 53 #include <dev/usb/usb.h> 54 #include <dev/usb/usbdi.h> 55 #include <dev/usb/usbdivar.h> 56 #include <dev/usb/usb_mem.h> 57 58 #include <linux/kernel.h> 59 #include <linux/list.h> 60 #include <linux/err.h> 61 62 #include <dwc2/dwc2.h> 63 #include <dwc2/dwc2var.h> 64 65 #include "dwc2_core.h" 66 #include "dwc2_hcd.h" 67 68 #ifdef DWC2_DEBUG 69 static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg) 70 { 71 switch (hsotg->op_state) { 72 case OTG_STATE_A_HOST: 73 return "a_host"; 74 case OTG_STATE_A_SUSPEND: 75 return "a_suspend"; 76 case OTG_STATE_A_PERIPHERAL: 77 return "a_peripheral"; 78 case OTG_STATE_B_PERIPHERAL: 79 return "b_peripheral"; 80 case OTG_STATE_B_HOST: 81 return "b_host"; 82 default: 83 return "unknown"; 84 } 85 } 86 #endif 87 88 /** 89 * dwc2_handle_usb_port_intr - handles OTG PRTINT interrupts. 90 * When the PRTINT interrupt fires, there are certain status bits in the Host 91 * Port that needs to get cleared. 92 * 93 * @hsotg: Programming view of DWC_otg controller 94 */ 95 static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg) 96 { 97 u32 hprt0 = DWC2_READ_4(hsotg, HPRT0); 98 99 if (hprt0 & HPRT0_ENACHG) { 100 hprt0 &= ~HPRT0_ENA; 101 DWC2_WRITE_4(hsotg, HPRT0, hprt0); 102 } 103 } 104 105 /** 106 * dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message 107 * 108 * @hsotg: Programming view of DWC_otg controller 109 */ 110 static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg) 111 { 112 /* Clear interrupt */ 113 DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_MODEMIS); 114 115 dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n", 116 dwc2_is_host_mode(hsotg) ? "Host" : "Device"); 117 } 118 119 /** 120 * dwc2_handle_otg_intr() - Handles the OTG Interrupts. It reads the OTG 121 * Interrupt Register (GOTGINT) to determine what interrupt has occurred. 122 * 123 * @hsotg: Programming view of DWC_otg controller 124 */ 125 static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) 126 { 127 u32 gotgint; 128 u32 gotgctl; 129 u32 gintmsk; 130 131 gotgint = DWC2_READ_4(hsotg, GOTGINT); 132 gotgctl = DWC2_READ_4(hsotg, GOTGCTL); 133 dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint, 134 dwc2_op_state_str(hsotg)); 135 136 if (gotgint & GOTGINT_SES_END_DET) { 137 dev_dbg(hsotg->dev, 138 " ++OTG Interrupt: Session End Detected++ (%s)\n", 139 dwc2_op_state_str(hsotg)); 140 gotgctl = DWC2_READ_4(hsotg, GOTGCTL); 141 142 if (dwc2_is_device_mode(hsotg)) 143 dwc2_hsotg_disconnect(hsotg); 144 145 if (hsotg->op_state == OTG_STATE_B_HOST) { 146 hsotg->op_state = OTG_STATE_B_PERIPHERAL; 147 } else { 148 /* 149 * If not B_HOST and Device HNP still set, HNP did 150 * not succeed! 151 */ 152 if (gotgctl & GOTGCTL_DEVHNPEN) { 153 dev_dbg(hsotg->dev, "Session End Detected\n"); 154 dev_err(hsotg->dev, 155 "Device Not Connected/Responding!\n"); 156 } 157 158 /* 159 * If Session End Detected the B-Cable has been 160 * disconnected 161 */ 162 /* Reset to a clean state */ 163 hsotg->lx_state = DWC2_L0; 164 } 165 166 gotgctl = DWC2_READ_4(hsotg, GOTGCTL); 167 gotgctl &= ~GOTGCTL_DEVHNPEN; 168 DWC2_WRITE_4(hsotg, GOTGCTL, gotgctl); 169 } 170 171 if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) { 172 dev_dbg(hsotg->dev, 173 " ++OTG Interrupt: Session Request Success Status Change++\n"); 174 gotgctl = DWC2_READ_4(hsotg, GOTGCTL); 175 if (gotgctl & GOTGCTL_SESREQSCS) { 176 if (hsotg->core_params->phy_type == 177 DWC2_PHY_TYPE_PARAM_FS 178 && hsotg->core_params->i2c_enable > 0) { 179 hsotg->srp_success = 1; 180 } else { 181 /* Clear Session Request */ 182 gotgctl = DWC2_READ_4(hsotg, GOTGCTL); 183 gotgctl &= ~GOTGCTL_SESREQ; 184 DWC2_WRITE_4(hsotg, GOTGCTL, gotgctl); 185 } 186 } 187 } 188 189 if (gotgint & GOTGINT_HST_NEG_SUC_STS_CHNG) { 190 /* 191 * Print statements during the HNP interrupt handling 192 * can cause it to fail 193 */ 194 gotgctl = DWC2_READ_4(hsotg, GOTGCTL); 195 /* 196 * WA for 3.00a- HW is not setting cur_mode, even sometimes 197 * this does not help 198 */ 199 if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) 200 udelay(100); 201 if (gotgctl & GOTGCTL_HSTNEGSCS) { 202 if (dwc2_is_host_mode(hsotg)) { 203 hsotg->op_state = OTG_STATE_B_HOST; 204 /* 205 * Need to disable SOF interrupt immediately. 206 * When switching from device to host, the PCD 207 * interrupt handler won't handle the interrupt 208 * if host mode is already set. The HCD 209 * interrupt handler won't get called if the 210 * HCD state is HALT. This means that the 211 * interrupt does not get handled and Linux 212 * complains loudly. 213 */ 214 gintmsk = DWC2_READ_4(hsotg, GINTMSK); 215 gintmsk &= ~GINTSTS_SOF; 216 DWC2_WRITE_4(hsotg, GINTMSK, gintmsk); 217 218 /* 219 * Call callback function with spin lock 220 * released 221 */ 222 spin_unlock(&hsotg->lock); 223 224 /* Initialize the Core for Host mode */ 225 dwc2_hcd_start(hsotg); 226 spin_lock(&hsotg->lock); 227 hsotg->op_state = OTG_STATE_B_HOST; 228 } 229 } else { 230 gotgctl = DWC2_READ_4(hsotg, GOTGCTL); 231 gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN); 232 DWC2_WRITE_4(hsotg, GOTGCTL, gotgctl); 233 dev_dbg(hsotg->dev, "HNP Failed\n"); 234 dev_err(hsotg->dev, 235 "Device Not Connected/Responding\n"); 236 } 237 } 238 239 if (gotgint & GOTGINT_HST_NEG_DET) { 240 /* 241 * The disconnect interrupt is set at the same time as 242 * Host Negotiation Detected. During the mode switch all 243 * interrupts are cleared so the disconnect interrupt 244 * handler will not get executed. 245 */ 246 dev_dbg(hsotg->dev, 247 " ++OTG Interrupt: Host Negotiation Detected++ (%s)\n", 248 (dwc2_is_host_mode(hsotg) ? "Host" : "Device")); 249 if (dwc2_is_device_mode(hsotg)) { 250 dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n", 251 hsotg->op_state); 252 spin_unlock(&hsotg->lock); 253 dwc2_hcd_disconnect(hsotg, false); 254 spin_lock(&hsotg->lock); 255 hsotg->op_state = OTG_STATE_A_PERIPHERAL; 256 } else { 257 /* Need to disable SOF interrupt immediately */ 258 gintmsk = DWC2_READ_4(hsotg, GINTMSK); 259 gintmsk &= ~GINTSTS_SOF; 260 DWC2_WRITE_4(hsotg, GINTMSK, gintmsk); 261 spin_unlock(&hsotg->lock); 262 dwc2_hcd_start(hsotg); 263 spin_lock(&hsotg->lock); 264 hsotg->op_state = OTG_STATE_A_HOST; 265 } 266 } 267 268 if (gotgint & GOTGINT_A_DEV_TOUT_CHG) 269 dev_dbg(hsotg->dev, 270 " ++OTG Interrupt: A-Device Timeout Change++\n"); 271 if (gotgint & GOTGINT_DBNCE_DONE) 272 dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n"); 273 274 /* Clear GOTGINT */ 275 DWC2_WRITE_4(hsotg, GOTGINT, gotgint); 276 } 277 278 /** 279 * dwc2_handle_conn_id_status_change_intr() - Handles the Connector ID Status 280 * Change Interrupt 281 * 282 * @hsotg: Programming view of DWC_otg controller 283 * 284 * Reads the OTG Interrupt Register (GOTCTL) to determine whether this is a 285 * Device to Host Mode transition or a Host to Device Mode transition. This only 286 * occurs when the cable is connected/removed from the PHY connector. 287 */ 288 static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg) 289 { 290 u32 gintmsk; 291 292 /* Clear interrupt */ 293 DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_CONIDSTSCHNG); 294 295 /* Need to disable SOF interrupt immediately */ 296 gintmsk = DWC2_READ_4(hsotg, GINTMSK); 297 gintmsk &= ~GINTSTS_SOF; 298 DWC2_WRITE_4(hsotg, GINTMSK, gintmsk); 299 300 dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n", 301 dwc2_is_host_mode(hsotg) ? "Host" : "Device"); 302 303 /* 304 * Need to schedule a work, as there are possible DELAY function calls. 305 * Release lock before scheduling workq as it holds spinlock during 306 * scheduling. 307 */ 308 if (hsotg->wq_otg) { 309 spin_unlock(&hsotg->lock); 310 queue_work(hsotg->wq_otg, &hsotg->wf_otg); 311 spin_lock(&hsotg->lock); 312 } 313 } 314 315 /** 316 * dwc2_handle_session_req_intr() - This interrupt indicates that a device is 317 * initiating the Session Request Protocol to request the host to turn on bus 318 * power so a new session can begin 319 * 320 * @hsotg: Programming view of DWC_otg controller 321 * 322 * This handler responds by turning on bus power. If the DWC_otg controller is 323 * in low power mode, this handler brings the controller out of low power mode 324 * before turning on bus power. 325 */ 326 static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) 327 { 328 int ret; 329 330 /* Clear interrupt */ 331 DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_SESSREQINT); 332 333 dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n", 334 hsotg->lx_state); 335 336 if (dwc2_is_device_mode(hsotg)) { 337 if (hsotg->lx_state == DWC2_L2) { 338 ret = dwc2_exit_hibernation(hsotg, true); 339 if (ret && (ret != -ENOTSUPP)) 340 dev_err(hsotg->dev, 341 "exit hibernation failed\n"); 342 } 343 344 /* 345 * Report disconnect if there is any previous session 346 * established 347 */ 348 dwc2_hsotg_disconnect(hsotg); 349 } 350 } 351 352 /* 353 * This interrupt indicates that the DWC_otg controller has detected a 354 * resume or remote wakeup sequence. If the DWC_otg controller is in 355 * low power mode, the handler must brings the controller out of low 356 * power mode. The controller automatically begins resume signaling. 357 * The handler schedules a time to stop resume signaling. 358 */ 359 static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) 360 { 361 int ret; 362 363 /* Clear interrupt */ 364 DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_WKUPINT); 365 366 dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n"); 367 dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state); 368 369 if (dwc2_is_device_mode(hsotg)) { 370 dev_dbg(hsotg->dev, "DSTS=0x%0x\n", DWC2_READ_4(hsotg, DSTS)); 371 if (hsotg->lx_state == DWC2_L2) { 372 u32 dctl = DWC2_READ_4(hsotg, DCTL); 373 374 /* Clear Remote Wakeup Signaling */ 375 dctl &= ~DCTL_RMTWKUPSIG; 376 DWC2_WRITE_4(hsotg, DCTL, dctl); 377 ret = dwc2_exit_hibernation(hsotg, true); 378 if (ret && (ret != -ENOTSUPP)) 379 dev_err(hsotg->dev, "exit hibernation failed\n"); 380 381 call_gadget(hsotg, resume); 382 } 383 /* Change to L0 state */ 384 hsotg->lx_state = DWC2_L0; 385 } else { 386 if (hsotg->core_params->hibernation) 387 return; 388 389 if (hsotg->lx_state != DWC2_L1) { 390 u32 pcgcctl = DWC2_READ_4(hsotg, PCGCTL); 391 392 /* Restart the Phy Clock */ 393 pcgcctl &= ~PCGCTL_STOPPCLK; 394 DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl); 395 callout_reset(&hsotg->wkp_timer, mstohz(71), 396 dwc2_wakeup_detected, hsotg); 397 } else { 398 /* Change to L0 state */ 399 hsotg->lx_state = DWC2_L0; 400 } 401 } 402 } 403 404 /* 405 * This interrupt indicates that a device has been disconnected from the 406 * root port 407 */ 408 static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg) 409 { 410 DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_DISCONNINT); 411 412 dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n", 413 dwc2_is_host_mode(hsotg) ? "Host" : "Device", 414 dwc2_op_state_str(hsotg)); 415 416 if (hsotg->op_state == OTG_STATE_A_HOST) 417 dwc2_hcd_disconnect(hsotg, false); 418 } 419 420 /* 421 * This interrupt indicates that SUSPEND state has been detected on the USB. 422 * 423 * For HNP the USB Suspend interrupt signals the change from "a_peripheral" 424 * to "a_host". 425 * 426 * When power management is enabled the core will be put in low power mode. 427 */ 428 static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) 429 { 430 u32 dsts; 431 int ret; 432 433 /* Clear interrupt */ 434 DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_USBSUSP); 435 436 dev_dbg(hsotg->dev, "USB SUSPEND\n"); 437 438 if (dwc2_is_device_mode(hsotg)) { 439 /* 440 * Check the Device status register to determine if the Suspend 441 * state is active 442 */ 443 dsts = DWC2_READ_4(hsotg, DSTS); 444 dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts); 445 dev_dbg(hsotg->dev, 446 "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n", 447 !!(dsts & DSTS_SUSPSTS), 448 hsotg->hw_params.power_optimized); 449 if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) { 450 /* Ignore suspend request before enumeration */ 451 if (!dwc2_is_device_connected(hsotg)) { 452 dev_dbg(hsotg->dev, 453 "ignore suspend request before enumeration\n"); 454 return; 455 } 456 457 ret = dwc2_enter_hibernation(hsotg); 458 if (ret) { 459 if (ret != -ENOTSUPP) 460 dev_err(hsotg->dev, 461 "enter hibernation failed\n"); 462 goto skip_power_saving; 463 } 464 465 udelay(100); 466 467 /* Ask phy to be suspended */ 468 if (!IS_ERR_OR_NULL(hsotg->uphy)) 469 usb_phy_set_suspend(hsotg->uphy, true); 470 skip_power_saving: 471 /* 472 * Change to L2 (suspend) state before releasing 473 * spinlock 474 */ 475 hsotg->lx_state = DWC2_L2; 476 477 /* Call gadget suspend callback */ 478 call_gadget(hsotg, suspend); 479 } 480 } else { 481 if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) { 482 dev_dbg(hsotg->dev, "a_peripheral->a_host\n"); 483 484 /* Change to L2 (suspend) state */ 485 hsotg->lx_state = DWC2_L2; 486 /* Clear the a_peripheral flag, back to a_host */ 487 spin_unlock(&hsotg->lock); 488 dwc2_hcd_start(hsotg); 489 spin_lock(&hsotg->lock); 490 hsotg->op_state = OTG_STATE_A_HOST; 491 } 492 } 493 } 494 495 #define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \ 496 GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT | \ 497 GINTSTS_MODEMIS | GINTSTS_DISCONNINT | \ 498 GINTSTS_USBSUSP | GINTSTS_PRTINT) 499 500 /* 501 * This function returns the Core Interrupt register 502 */ 503 static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg) 504 { 505 u32 gintsts; 506 u32 gintmsk; 507 u32 gahbcfg; 508 u32 gintmsk_common = GINTMSK_COMMON; 509 510 gintsts = DWC2_READ_4(hsotg, GINTSTS); 511 gintmsk = DWC2_READ_4(hsotg, GINTMSK); 512 gahbcfg = DWC2_READ_4(hsotg, GAHBCFG); 513 514 /* If any common interrupts set */ 515 if (gintsts & gintmsk_common) 516 dev_dbg(hsotg->dev, "gintsts=%08x gintmsk=%08x\n", 517 gintsts, gintmsk); 518 519 if (gahbcfg & GAHBCFG_GLBL_INTR_EN) 520 return gintsts & gintmsk & gintmsk_common; 521 else 522 return 0; 523 } 524 525 /* 526 * Common interrupt handler 527 * 528 * The common interrupts are those that occur in both Host and Device mode. 529 * This handler handles the following interrupts: 530 * - Mode Mismatch Interrupt 531 * - OTG Interrupt 532 * - Connector ID Status Change Interrupt 533 * - Disconnect Interrupt 534 * - Session Request Interrupt 535 * - Resume / Remote Wakeup Detected Interrupt 536 * - Suspend Interrupt 537 */ 538 irqreturn_t dwc2_handle_common_intr(void *dev) 539 { 540 struct dwc2_hsotg *hsotg = dev; 541 u32 gintsts; 542 irqreturn_t retval = IRQ_NONE; 543 544 if (!dwc2_is_controller_alive(hsotg)) { 545 dev_warn(hsotg->dev, "Controller is dead\n"); 546 goto out; 547 } 548 549 KASSERT(mutex_owned(&hsotg->lock)); 550 551 gintsts = dwc2_read_common_intr(hsotg); 552 if (gintsts & ~GINTSTS_PRTINT) 553 retval = IRQ_HANDLED; 554 555 if (gintsts & GINTSTS_MODEMIS) 556 dwc2_handle_mode_mismatch_intr(hsotg); 557 if (gintsts & GINTSTS_OTGINT) 558 dwc2_handle_otg_intr(hsotg); 559 if (gintsts & GINTSTS_CONIDSTSCHNG) 560 dwc2_handle_conn_id_status_change_intr(hsotg); 561 if (gintsts & GINTSTS_DISCONNINT) 562 dwc2_handle_disconnect_intr(hsotg); 563 if (gintsts & GINTSTS_SESSREQINT) 564 dwc2_handle_session_req_intr(hsotg); 565 if (gintsts & GINTSTS_WKUPINT) 566 dwc2_handle_wakeup_detected_intr(hsotg); 567 if (gintsts & GINTSTS_USBSUSP) 568 dwc2_handle_usb_suspend_intr(hsotg); 569 570 if (gintsts & GINTSTS_PRTINT) { 571 /* 572 * The port interrupt occurs while in device mode with HPRT0 573 * Port Enable/Disable 574 */ 575 if (dwc2_is_device_mode(hsotg)) { 576 dev_dbg(hsotg->dev, 577 " --Port interrupt received in Device mode--\n"); 578 dwc2_handle_usb_port_intr(hsotg); 579 retval = IRQ_HANDLED; 580 } 581 } 582 583 out: 584 return retval; 585 } 586