/* * This work is to fix IOT problem. * 1. PC(Lenovo MT-M5852-B88) + USB Host PCI-e TI(TUSB7340) or Fresco, * --> PC enter SLERP/HIBERNATION --> USER wake up PC --> PC can not detect device. * 2. PC(Lenovo MT-M5852-B88) + USB Host PCI-e Fresco, * --> PC COLD reboot --> PC can not detect device. * The root cause is that device try to link host too early. XHCI host does not ready to linkup. * So create a delayed work to re-tran when device is stuck at RxDetect. */ void check_ltssm_work(struct work_struct *data) { //struct musb *musb = container_of(to_delayed_work(data), struct musb, check_ltssm_work); #ifndef CONFIG_USBIF_COMPLIANCE os_printk(K_INFO, "%s %x\n", __func__, sts_ltssm); if(sts_ltssm == RXDET_SUCCESS_INTR) { sts_ltssm = 0; mu3d_hal_u3dev_dis(); mdelay(10); mu3d_hal_u3dev_en(); } #endif }
static inline void mtu3d_u3_ltssm_intr_handler(struct musb *musb, u32 dwLtssmValue) { static u32 soft_conn_num = 0; if (dwLtssmValue & SS_DISABLE_INTR) { os_printk(K_INFO, "LTSSM: SS_DISABLE_INTR [%d] & Set SOFT_CONN=1\n", soft_conn_num++); //enable U2 link. after host reset, HS/FS EP0 configuration is applied in musb_g_reset os_clrmsk(U3D_SSUSB_U2_CTRL_0P, SSUSB_U2_PORT_PDN); os_setmsk(U3D_POWER_MANAGEMENT, SOFT_CONN); } if (dwLtssmValue & ENTER_U0_INTR) { soft_conn_num = 0; //do not apply U3 EP0 setting again, if the speed is already U3 //LTSSM may go to recovery and back to U0 if (musb->g.speed != USB_SPEED_SUPER) { os_printk(K_INFO, "LTSSM: ENTER_U0_INTR %d\n", musb->g.speed); musb_conifg_ep0(musb); } } if (dwLtssmValue & VBUS_FALL_INTR) { os_printk(K_INFO, "LTSSM: VBUS_FALL_INTR\n"); mu3d_hal_pdn_ip_port(1, 1, 1, 1); mu3d_hal_u3dev_dis(); } if (dwLtssmValue & VBUS_RISE_INTR) { os_printk(K_INFO, "LTSSM: VBUS_RISE_INTR\n"); mu3d_hal_u3dev_en(); } if (dwLtssmValue & ENTER_U3_INTR) { os_printk(K_INFO, "LTSSM: ENTER_U3_INTR\n"); mu3d_hal_pdn_ip_port(0, 0, 1, 0); } if (dwLtssmValue & EXIT_U3_INTR) { os_printk(K_INFO, "LTSSM: EXIT_U3_INTR\n"); mu3d_hal_pdn_ip_port(1, 0, 1, 0); } #ifndef POWER_SAVING_MODE if (dwLtssmValue & U3_RESUME_INTR) { os_printk(K_INFO, "LTSSM: RESUME_INTR\n"); mu3d_hal_pdn_ip_port(1, 0, 1, 0); os_writel(U3D_LINK_POWER_CONTROL, os_readl(U3D_LINK_POWER_CONTROL) | UX_EXIT); } #endif /*7.5.12.2 Hot Reset Requirements * 1. A downstream port shall reset its Link Error Count as defined in Section 7.4.2. * 2. A downstream port shall reset its PM timers and the associated U1 and U2 timeout values to zero. * 3. The port Configuration information shall remain unchanged (refer to Section 8.4.6 for details). * 4. The port shall maintain its transmitter specifications defined in Table 6-10. * 5. The port shall maintain its low-impedance receiver termination (RRX-DC) defined in Table 6-13. */ if (dwLtssmValue & HOT_RST_INTR) { DEV_INT32 link_err_cnt; DEV_INT32 timeout_val; os_printk(K_INFO, "LTSSM: HOT_RST_INTR\n"); /* Clear link error count */ link_err_cnt=os_readl(U3D_LINK_ERR_COUNT); os_printk(K_INFO, "LTSSM: link_err_cnt=%x\n", link_err_cnt); os_writel(U3D_LINK_ERR_COUNT, CLR_LINK_ERR_CNT); /* Clear U1 & U2 Enable*/ os_clrmsk(U3D_LINK_POWER_CONTROL, (SW_U1_ACCEPT_ENABLE|SW_U2_ACCEPT_ENABLE)); musb->g.pwr_params.bU1Enabled = 0; musb->g.pwr_params.bU2Enabled = 0; /* Reset U1 & U2 timeout value*/ timeout_val = os_readl(U3D_LINK_UX_INACT_TIMER); os_printk(K_INFO, "LTSSM: timer_val =%x\n", timeout_val); timeout_val &= ~ (U1_INACT_TIMEOUT_VALUE | DEV_U2_INACT_TIMEOUT_VALUE); os_writel(U3D_LINK_UX_INACT_TIMER, timeout_val); } if (dwLtssmValue & SS_INACTIVE_INTR) os_printk(K_INFO, "LTSSM: SS_INACTIVE_INTR\n"); if (dwLtssmValue & RECOVERY_INTR) os_printk(K_DEBUG, "LTSSM: RECOVERY_INTR\n"); /* A completion of a Warm Reset shall result in the following. * 1. A downstream port shall reset its Link Error Count. * 2. Port configuration information of an upstream port shall be reset to default values. Refer to * Sections 8.4.5 and 8.4.6 for details. * 3. The PHY level variables (such as Rx equalization settings) shall be reinitialized or retrained. * 4. The LTSSM of a port shall transition to U0 through RxDetect and Polling. */ if (dwLtssmValue & WARM_RST_INTR) { DEV_INT32 link_err_cnt; os_printk(K_INFO, "LTSSM: WARM_RST_INTR\n"); /* Clear link error count */ link_err_cnt=os_readl(U3D_LINK_ERR_COUNT); os_printk(K_INFO, "LTSSM: link_err_cnt=%x\n", link_err_cnt); os_writel(U3D_LINK_ERR_COUNT, CLR_LINK_ERR_CNT); } if (dwLtssmValue & ENTER_U2_INTR) os_printk(K_DEBUG, "LTSSM: ENTER_U2_INTR\n"); if (dwLtssmValue & ENTER_U1_INTR) os_printk(K_DEBUG, "LTSSM: ENTER_U1_INTR\n"); if (dwLtssmValue & RXDET_SUCCESS_INTR) os_printk(K_INFO, "LTSSM: RXDET_SUCCESS_INTR\n"); }