18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 98c2ecf20Sopenharmony_ci * are met: 108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 128c2ecf20Sopenharmony_ci * without modification. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 148c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 158c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 168c2ecf20Sopenharmony_ci * 3. The names of the above-listed copyright holders may not be used 178c2ecf20Sopenharmony_ci * to endorse or promote products derived from this software without 188c2ecf20Sopenharmony_ci * specific prior written permission. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the 218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software 228c2ecf20Sopenharmony_ci * Foundation; either version 2 of the License, or (at your option) any 238c2ecf20Sopenharmony_ci * later version. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 268c2ecf20Sopenharmony_ci * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 278c2ecf20Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 288c2ecf20Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 298c2ecf20Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 308c2ecf20Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 318c2ecf20Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 328c2ecf20Sopenharmony_ci * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 338c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 348c2ecf20Sopenharmony_ci * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 358c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * This file contains the interrupt handlers for Host mode 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci#include <linux/kernel.h> 428c2ecf20Sopenharmony_ci#include <linux/module.h> 438c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 448c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 458c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 468c2ecf20Sopenharmony_ci#include <linux/io.h> 478c2ecf20Sopenharmony_ci#include <linux/slab.h> 488c2ecf20Sopenharmony_ci#include <linux/usb.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h> 518c2ecf20Sopenharmony_ci#include <linux/usb/ch11.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include "core.h" 548c2ecf20Sopenharmony_ci#include "hcd.h" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 578c2ecf20Sopenharmony_ci * If we get this many NAKs on a split transaction we'll slow down 588c2ecf20Sopenharmony_ci * retransmission. A 1 here means delay after the first NAK. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci#define DWC2_NAKS_BEFORE_DELAY 3 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* This function is for debug only */ 638c2ecf20Sopenharmony_cistatic void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci u16 curr_frame_number = hsotg->frame_number; 668c2ecf20Sopenharmony_ci u16 expected = dwc2_frame_num_inc(hsotg->last_frame_num, 1); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (expected != curr_frame_number) 698c2ecf20Sopenharmony_ci dwc2_sch_vdbg(hsotg, "MISSED SOF %04x != %04x\n", 708c2ecf20Sopenharmony_ci expected, curr_frame_number); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS 738c2ecf20Sopenharmony_ci if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) { 748c2ecf20Sopenharmony_ci if (expected != curr_frame_number) { 758c2ecf20Sopenharmony_ci hsotg->frame_num_array[hsotg->frame_num_idx] = 768c2ecf20Sopenharmony_ci curr_frame_number; 778c2ecf20Sopenharmony_ci hsotg->last_frame_num_array[hsotg->frame_num_idx] = 788c2ecf20Sopenharmony_ci hsotg->last_frame_num; 798c2ecf20Sopenharmony_ci hsotg->frame_num_idx++; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci } else if (!hsotg->dumped_frame_num_array) { 828c2ecf20Sopenharmony_ci int i; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "Frame Last Frame\n"); 858c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "----- ----------\n"); 868c2ecf20Sopenharmony_ci for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) { 878c2ecf20Sopenharmony_ci dev_info(hsotg->dev, "0x%04x 0x%04x\n", 888c2ecf20Sopenharmony_ci hsotg->frame_num_array[i], 898c2ecf20Sopenharmony_ci hsotg->last_frame_num_array[i]); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci hsotg->dumped_frame_num_array = 1; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci#endif 948c2ecf20Sopenharmony_ci hsotg->last_frame_num = curr_frame_number; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg, 988c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 998c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct usb_device *root_hub = dwc2_hsotg_to_hcd(hsotg)->self.root_hub; 1028c2ecf20Sopenharmony_ci struct urb *usb_urb; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!chan->qh) 1058c2ecf20Sopenharmony_ci return; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (chan->qh->dev_speed == USB_SPEED_HIGH) 1088c2ecf20Sopenharmony_ci return; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (!qtd->urb) 1118c2ecf20Sopenharmony_ci return; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci usb_urb = qtd->urb->priv; 1148c2ecf20Sopenharmony_ci if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt) 1158c2ecf20Sopenharmony_ci return; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * The root hub doesn't really have a TT, but Linux thinks it 1198c2ecf20Sopenharmony_ci * does because how could you have a "high speed hub" that 1208c2ecf20Sopenharmony_ci * directly talks directly to low speed devices without a TT? 1218c2ecf20Sopenharmony_ci * It's all lies. Lies, I tell you. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci if (usb_urb->dev->tt->hub == root_hub) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) { 1278c2ecf20Sopenharmony_ci chan->qh->tt_buffer_dirty = 1; 1288c2ecf20Sopenharmony_ci if (usb_hub_clear_tt_buffer(usb_urb)) 1298c2ecf20Sopenharmony_ci /* Clear failed; let's hope things work anyway */ 1308c2ecf20Sopenharmony_ci chan->qh->tt_buffer_dirty = 0; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* 1358c2ecf20Sopenharmony_ci * Handles the start-of-frame interrupt in host mode. Non-periodic 1368c2ecf20Sopenharmony_ci * transactions may be queued to the DWC_otg controller for the current 1378c2ecf20Sopenharmony_ci * (micro)frame. Periodic transactions may be queued to the controller 1388c2ecf20Sopenharmony_ci * for the next (micro)frame. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_cistatic void dwc2_sof_intr(struct dwc2_hsotg *hsotg) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct list_head *qh_entry; 1438c2ecf20Sopenharmony_ci struct dwc2_qh *qh; 1448c2ecf20Sopenharmony_ci enum dwc2_transaction_type tr_type; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* Clear interrupt */ 1478c2ecf20Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_SOF, GINTSTS); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#ifdef DEBUG_SOF 1508c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n"); 1518c2ecf20Sopenharmony_ci#endif 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci dwc2_track_missed_sofs(hsotg); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* Determine whether any periodic QHs should be executed */ 1588c2ecf20Sopenharmony_ci qh_entry = hsotg->periodic_sched_inactive.next; 1598c2ecf20Sopenharmony_ci while (qh_entry != &hsotg->periodic_sched_inactive) { 1608c2ecf20Sopenharmony_ci qh = list_entry(qh_entry, struct dwc2_qh, qh_list_entry); 1618c2ecf20Sopenharmony_ci qh_entry = qh_entry->next; 1628c2ecf20Sopenharmony_ci if (dwc2_frame_num_le(qh->next_active_frame, 1638c2ecf20Sopenharmony_ci hsotg->frame_number)) { 1648c2ecf20Sopenharmony_ci dwc2_sch_vdbg(hsotg, "QH=%p ready fn=%04x, nxt=%04x\n", 1658c2ecf20Sopenharmony_ci qh, hsotg->frame_number, 1668c2ecf20Sopenharmony_ci qh->next_active_frame); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * Move QH to the ready list to be executed next 1708c2ecf20Sopenharmony_ci * (micro)frame 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci list_move_tail(&qh->qh_list_entry, 1738c2ecf20Sopenharmony_ci &hsotg->periodic_sched_ready); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci tr_type = dwc2_hcd_select_transactions(hsotg); 1778c2ecf20Sopenharmony_ci if (tr_type != DWC2_TRANSACTION_NONE) 1788c2ecf20Sopenharmony_ci dwc2_hcd_queue_transactions(hsotg, tr_type); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * Handles the Rx FIFO Level Interrupt, which indicates that there is 1838c2ecf20Sopenharmony_ci * at least one packet in the Rx FIFO. The packets are moved from the FIFO to 1848c2ecf20Sopenharmony_ci * memory if the DWC_otg controller is operating in Slave mode. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u32 grxsts, chnum, bcnt, dpid, pktsts; 1898c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (dbg_perio()) 1928c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n"); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci grxsts = dwc2_readl(hsotg, GRXSTSP); 1958c2ecf20Sopenharmony_ci chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT; 1968c2ecf20Sopenharmony_ci chan = hsotg->hc_ptr_array[chnum]; 1978c2ecf20Sopenharmony_ci if (!chan) { 1988c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "Unable to get corresponding channel\n"); 1998c2ecf20Sopenharmony_ci return; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci bcnt = (grxsts & GRXSTS_BYTECNT_MASK) >> GRXSTS_BYTECNT_SHIFT; 2038c2ecf20Sopenharmony_ci dpid = (grxsts & GRXSTS_DPID_MASK) >> GRXSTS_DPID_SHIFT; 2048c2ecf20Sopenharmony_ci pktsts = (grxsts & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Packet Status */ 2078c2ecf20Sopenharmony_ci if (dbg_perio()) { 2088c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " Ch num = %d\n", chnum); 2098c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " Count = %d\n", bcnt); 2108c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " DPID = %d, chan.dpid = %d\n", dpid, 2118c2ecf20Sopenharmony_ci chan->data_pid_start); 2128c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " PStatus = %d\n", pktsts); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci switch (pktsts) { 2168c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_HCHIN: 2178c2ecf20Sopenharmony_ci /* Read the data into the host buffer */ 2188c2ecf20Sopenharmony_ci if (bcnt > 0) { 2198c2ecf20Sopenharmony_ci dwc2_read_packet(hsotg, chan->xfer_buf, bcnt); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Update the HC fields for the next packet received */ 2228c2ecf20Sopenharmony_ci chan->xfer_count += bcnt; 2238c2ecf20Sopenharmony_ci chan->xfer_buf += bcnt; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_HCHIN_XFER_COMP: 2278c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_DATATOGGLEERR: 2288c2ecf20Sopenharmony_ci case GRXSTS_PKTSTS_HCHHALTED: 2298c2ecf20Sopenharmony_ci /* Handled in interrupt, just ignore data */ 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci default: 2328c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 2338c2ecf20Sopenharmony_ci "RxFIFO Level Interrupt: Unknown status %d\n", pktsts); 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* 2398c2ecf20Sopenharmony_ci * This interrupt occurs when the non-periodic Tx FIFO is half-empty. More 2408c2ecf20Sopenharmony_ci * data packets may be written to the FIFO for OUT transfers. More requests 2418c2ecf20Sopenharmony_ci * may be written to the non-periodic request queue for IN transfers. This 2428c2ecf20Sopenharmony_ci * interrupt is enabled only in Slave mode. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic void dwc2_np_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Non-Periodic TxFIFO Empty Interrupt--\n"); 2478c2ecf20Sopenharmony_ci dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_NON_PERIODIC); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* 2518c2ecf20Sopenharmony_ci * This interrupt occurs when the periodic Tx FIFO is half-empty. More data 2528c2ecf20Sopenharmony_ci * packets may be written to the FIFO for OUT transfers. More requests may be 2538c2ecf20Sopenharmony_ci * written to the periodic request queue for IN transfers. This interrupt is 2548c2ecf20Sopenharmony_ci * enabled only in Slave mode. 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_cistatic void dwc2_perio_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci if (dbg_perio()) 2598c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Periodic TxFIFO Empty Interrupt--\n"); 2608c2ecf20Sopenharmony_ci dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_PERIODIC); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0, 2648c2ecf20Sopenharmony_ci u32 *hprt0_modify) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct dwc2_core_params *params = &hsotg->params; 2678c2ecf20Sopenharmony_ci int do_reset = 0; 2688c2ecf20Sopenharmony_ci u32 usbcfg; 2698c2ecf20Sopenharmony_ci u32 prtspd; 2708c2ecf20Sopenharmony_ci u32 hcfg; 2718c2ecf20Sopenharmony_ci u32 fslspclksel; 2728c2ecf20Sopenharmony_ci u32 hfir; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Every time when port enables calculate HFIR.FrInterval */ 2778c2ecf20Sopenharmony_ci hfir = dwc2_readl(hsotg, HFIR); 2788c2ecf20Sopenharmony_ci hfir &= ~HFIR_FRINT_MASK; 2798c2ecf20Sopenharmony_ci hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT & 2808c2ecf20Sopenharmony_ci HFIR_FRINT_MASK; 2818c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hfir, HFIR); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Check if we need to adjust the PHY clock speed for low power */ 2848c2ecf20Sopenharmony_ci if (!params->host_support_fs_ls_low_power) { 2858c2ecf20Sopenharmony_ci /* Port has been enabled, set the reset change flag */ 2868c2ecf20Sopenharmony_ci hsotg->flags.b.port_reset_change = 1; 2878c2ecf20Sopenharmony_ci return; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 2918c2ecf20Sopenharmony_ci prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) { 2948c2ecf20Sopenharmony_ci /* Low power */ 2958c2ecf20Sopenharmony_ci if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) { 2968c2ecf20Sopenharmony_ci /* Set PHY low power clock select for FS/LS devices */ 2978c2ecf20Sopenharmony_ci usbcfg |= GUSBCFG_PHY_LP_CLK_SEL; 2988c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 2998c2ecf20Sopenharmony_ci do_reset = 1; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci hcfg = dwc2_readl(hsotg, HCFG); 3038c2ecf20Sopenharmony_ci fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >> 3048c2ecf20Sopenharmony_ci HCFG_FSLSPCLKSEL_SHIFT; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (prtspd == HPRT0_SPD_LOW_SPEED && 3078c2ecf20Sopenharmony_ci params->host_ls_low_power_phy_clk) { 3088c2ecf20Sopenharmony_ci /* 6 MHZ */ 3098c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 3108c2ecf20Sopenharmony_ci "FS_PHY programming HCFG to 6 MHz\n"); 3118c2ecf20Sopenharmony_ci if (fslspclksel != HCFG_FSLSPCLKSEL_6_MHZ) { 3128c2ecf20Sopenharmony_ci fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ; 3138c2ecf20Sopenharmony_ci hcfg &= ~HCFG_FSLSPCLKSEL_MASK; 3148c2ecf20Sopenharmony_ci hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT; 3158c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hcfg, HCFG); 3168c2ecf20Sopenharmony_ci do_reset = 1; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci } else { 3198c2ecf20Sopenharmony_ci /* 48 MHZ */ 3208c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 3218c2ecf20Sopenharmony_ci "FS_PHY programming HCFG to 48 MHz\n"); 3228c2ecf20Sopenharmony_ci if (fslspclksel != HCFG_FSLSPCLKSEL_48_MHZ) { 3238c2ecf20Sopenharmony_ci fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ; 3248c2ecf20Sopenharmony_ci hcfg &= ~HCFG_FSLSPCLKSEL_MASK; 3258c2ecf20Sopenharmony_ci hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT; 3268c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hcfg, HCFG); 3278c2ecf20Sopenharmony_ci do_reset = 1; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci } else { 3318c2ecf20Sopenharmony_ci /* Not low power */ 3328c2ecf20Sopenharmony_ci if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) { 3338c2ecf20Sopenharmony_ci usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL; 3348c2ecf20Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 3358c2ecf20Sopenharmony_ci do_reset = 1; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (do_reset) { 3408c2ecf20Sopenharmony_ci *hprt0_modify |= HPRT0_RST; 3418c2ecf20Sopenharmony_ci dwc2_writel(hsotg, *hprt0_modify, HPRT0); 3428c2ecf20Sopenharmony_ci queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work, 3438c2ecf20Sopenharmony_ci msecs_to_jiffies(60)); 3448c2ecf20Sopenharmony_ci } else { 3458c2ecf20Sopenharmony_ci /* Port has been enabled, set the reset change flag */ 3468c2ecf20Sopenharmony_ci hsotg->flags.b.port_reset_change = 1; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* 3518c2ecf20Sopenharmony_ci * There are multiple conditions that can cause a port interrupt. This function 3528c2ecf20Sopenharmony_ci * determines which interrupt conditions have occurred and handles them 3538c2ecf20Sopenharmony_ci * appropriately. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_cistatic void dwc2_port_intr(struct dwc2_hsotg *hsotg) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci u32 hprt0; 3588c2ecf20Sopenharmony_ci u32 hprt0_modify; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Port Interrupt--\n"); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci hprt0 = dwc2_readl(hsotg, HPRT0); 3638c2ecf20Sopenharmony_ci hprt0_modify = hprt0; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * Clear appropriate bits in HPRT0 to clear the interrupt bit in 3678c2ecf20Sopenharmony_ci * GINTSTS 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci hprt0_modify &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | 3708c2ecf20Sopenharmony_ci HPRT0_OVRCURRCHG); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * Port Connect Detected 3748c2ecf20Sopenharmony_ci * Set flag and clear if detected 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci if (hprt0 & HPRT0_CONNDET) { 3778c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hprt0_modify | HPRT0_CONNDET, HPRT0); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 3808c2ecf20Sopenharmony_ci "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n", 3818c2ecf20Sopenharmony_ci hprt0); 3828c2ecf20Sopenharmony_ci dwc2_hcd_connect(hsotg); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* 3858c2ecf20Sopenharmony_ci * The Hub driver asserts a reset when it sees port connect 3868c2ecf20Sopenharmony_ci * status change flag 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* 3918c2ecf20Sopenharmony_ci * Port Enable Changed 3928c2ecf20Sopenharmony_ci * Clear if detected - Set internal flag if disabled 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci if (hprt0 & HPRT0_ENACHG) { 3958c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hprt0_modify | HPRT0_ENACHG, HPRT0); 3968c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 3978c2ecf20Sopenharmony_ci " --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n", 3988c2ecf20Sopenharmony_ci hprt0, !!(hprt0 & HPRT0_ENA)); 3998c2ecf20Sopenharmony_ci if (hprt0 & HPRT0_ENA) { 4008c2ecf20Sopenharmony_ci hsotg->new_connection = true; 4018c2ecf20Sopenharmony_ci dwc2_hprt0_enable(hsotg, hprt0, &hprt0_modify); 4028c2ecf20Sopenharmony_ci } else { 4038c2ecf20Sopenharmony_ci hsotg->flags.b.port_enable_change = 1; 4048c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_fs_enable) { 4058c2ecf20Sopenharmony_ci u32 hcfg; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci hsotg->params.dma_desc_enable = false; 4088c2ecf20Sopenharmony_ci hsotg->new_connection = false; 4098c2ecf20Sopenharmony_ci hcfg = dwc2_readl(hsotg, HCFG); 4108c2ecf20Sopenharmony_ci hcfg &= ~HCFG_DESCDMA; 4118c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hcfg, HCFG); 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Overcurrent Change Interrupt */ 4178c2ecf20Sopenharmony_ci if (hprt0 & HPRT0_OVRCURRCHG) { 4188c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hprt0_modify | HPRT0_OVRCURRCHG, 4198c2ecf20Sopenharmony_ci HPRT0); 4208c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 4218c2ecf20Sopenharmony_ci " --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n", 4228c2ecf20Sopenharmony_ci hprt0); 4238c2ecf20Sopenharmony_ci hsotg->flags.b.port_over_current_change = 1; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* 4288c2ecf20Sopenharmony_ci * Gets the actual length of a transfer after the transfer halts. halt_status 4298c2ecf20Sopenharmony_ci * holds the reason for the halt. 4308c2ecf20Sopenharmony_ci * 4318c2ecf20Sopenharmony_ci * For IN transfers where halt_status is DWC2_HC_XFER_COMPLETE, *short_read 4328c2ecf20Sopenharmony_ci * is set to 1 upon return if less than the requested number of bytes were 4338c2ecf20Sopenharmony_ci * transferred. short_read may also be NULL on entry, in which case it remains 4348c2ecf20Sopenharmony_ci * unchanged. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_cistatic u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg, 4378c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 4388c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, 4398c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status, 4408c2ecf20Sopenharmony_ci int *short_read) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci u32 hctsiz, count, length; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum)); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (halt_status == DWC2_HC_XFER_COMPLETE) { 4478c2ecf20Sopenharmony_ci if (chan->ep_is_in) { 4488c2ecf20Sopenharmony_ci count = (hctsiz & TSIZ_XFERSIZE_MASK) >> 4498c2ecf20Sopenharmony_ci TSIZ_XFERSIZE_SHIFT; 4508c2ecf20Sopenharmony_ci length = chan->xfer_len - count; 4518c2ecf20Sopenharmony_ci if (short_read) 4528c2ecf20Sopenharmony_ci *short_read = (count != 0); 4538c2ecf20Sopenharmony_ci } else if (chan->qh->do_split) { 4548c2ecf20Sopenharmony_ci length = qtd->ssplit_out_xfer_count; 4558c2ecf20Sopenharmony_ci } else { 4568c2ecf20Sopenharmony_ci length = chan->xfer_len; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } else { 4598c2ecf20Sopenharmony_ci /* 4608c2ecf20Sopenharmony_ci * Must use the hctsiz.pktcnt field to determine how much data 4618c2ecf20Sopenharmony_ci * has been transferred. This field reflects the number of 4628c2ecf20Sopenharmony_ci * packets that have been transferred via the USB. This is 4638c2ecf20Sopenharmony_ci * always an integral number of packets if the transfer was 4648c2ecf20Sopenharmony_ci * halted before its normal completion. (Can't use the 4658c2ecf20Sopenharmony_ci * hctsiz.xfersize field because that reflects the number of 4668c2ecf20Sopenharmony_ci * bytes transferred via the AHB, not the USB). 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci count = (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT; 4698c2ecf20Sopenharmony_ci length = (chan->start_pkt_count - count) * chan->max_packet; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return length; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/** 4768c2ecf20Sopenharmony_ci * dwc2_update_urb_state() - Updates the state of the URB after a Transfer 4778c2ecf20Sopenharmony_ci * Complete interrupt on the host channel. Updates the actual_length field 4788c2ecf20Sopenharmony_ci * of the URB based on the number of bytes transferred via the host channel. 4798c2ecf20Sopenharmony_ci * Sets the URB status if the data transfer is finished. 4808c2ecf20Sopenharmony_ci * 4818c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 4828c2ecf20Sopenharmony_ci * @chan: Programming view of host channel 4838c2ecf20Sopenharmony_ci * @chnum: Channel number 4848c2ecf20Sopenharmony_ci * @urb: Processing URB 4858c2ecf20Sopenharmony_ci * @qtd: Queue transfer descriptor 4868c2ecf20Sopenharmony_ci * 4878c2ecf20Sopenharmony_ci * Return: 1 if the data transfer specified by the URB is completely finished, 4888c2ecf20Sopenharmony_ci * 0 otherwise 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_cistatic int dwc2_update_urb_state(struct dwc2_hsotg *hsotg, 4918c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 4928c2ecf20Sopenharmony_ci struct dwc2_hcd_urb *urb, 4938c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci u32 hctsiz; 4968c2ecf20Sopenharmony_ci int xfer_done = 0; 4978c2ecf20Sopenharmony_ci int short_read = 0; 4988c2ecf20Sopenharmony_ci int xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd, 4998c2ecf20Sopenharmony_ci DWC2_HC_XFER_COMPLETE, 5008c2ecf20Sopenharmony_ci &short_read); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (urb->actual_length + xfer_length > urb->length) { 5038c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s(): trimming xfer length\n", __func__); 5048c2ecf20Sopenharmony_ci xfer_length = urb->length - urb->actual_length; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n", 5088c2ecf20Sopenharmony_ci urb->actual_length, xfer_length); 5098c2ecf20Sopenharmony_ci urb->actual_length += xfer_length; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (xfer_length && chan->ep_type == USB_ENDPOINT_XFER_BULK && 5128c2ecf20Sopenharmony_ci (urb->flags & URB_SEND_ZERO_PACKET) && 5138c2ecf20Sopenharmony_ci urb->actual_length >= urb->length && 5148c2ecf20Sopenharmony_ci !(urb->length % chan->max_packet)) { 5158c2ecf20Sopenharmony_ci xfer_done = 0; 5168c2ecf20Sopenharmony_ci } else if (short_read || urb->actual_length >= urb->length) { 5178c2ecf20Sopenharmony_ci xfer_done = 1; 5188c2ecf20Sopenharmony_ci urb->status = 0; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum)); 5228c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n", 5238c2ecf20Sopenharmony_ci __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum); 5248c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " chan->xfer_len %d\n", chan->xfer_len); 5258c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " hctsiz.xfersize %d\n", 5268c2ecf20Sopenharmony_ci (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT); 5278c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " urb->transfer_buffer_length %d\n", urb->length); 5288c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " urb->actual_length %d\n", urb->actual_length); 5298c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " short_read %d, xfer_done %d\n", short_read, 5308c2ecf20Sopenharmony_ci xfer_done); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return xfer_done; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci/* 5368c2ecf20Sopenharmony_ci * Save the starting data toggle for the next transfer. The data toggle is 5378c2ecf20Sopenharmony_ci * saved in the QH for non-control transfers and it's saved in the QTD for 5388c2ecf20Sopenharmony_ci * control transfers. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_civoid dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, 5418c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 5428c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci u32 hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum)); 5458c2ecf20Sopenharmony_ci u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) { 5488c2ecf20Sopenharmony_ci if (WARN(!chan || !chan->qh, 5498c2ecf20Sopenharmony_ci "chan->qh must be specified for non-control eps\n")) 5508c2ecf20Sopenharmony_ci return; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (pid == TSIZ_SC_MC_PID_DATA0) 5538c2ecf20Sopenharmony_ci chan->qh->data_toggle = DWC2_HC_PID_DATA0; 5548c2ecf20Sopenharmony_ci else 5558c2ecf20Sopenharmony_ci chan->qh->data_toggle = DWC2_HC_PID_DATA1; 5568c2ecf20Sopenharmony_ci } else { 5578c2ecf20Sopenharmony_ci if (WARN(!qtd, 5588c2ecf20Sopenharmony_ci "qtd must be specified for control eps\n")) 5598c2ecf20Sopenharmony_ci return; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (pid == TSIZ_SC_MC_PID_DATA0) 5628c2ecf20Sopenharmony_ci qtd->data_toggle = DWC2_HC_PID_DATA0; 5638c2ecf20Sopenharmony_ci else 5648c2ecf20Sopenharmony_ci qtd->data_toggle = DWC2_HC_PID_DATA1; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci/** 5698c2ecf20Sopenharmony_ci * dwc2_update_isoc_urb_state() - Updates the state of an Isochronous URB when 5708c2ecf20Sopenharmony_ci * the transfer is stopped for any reason. The fields of the current entry in 5718c2ecf20Sopenharmony_ci * the frame descriptor array are set based on the transfer state and the input 5728c2ecf20Sopenharmony_ci * halt_status. Completes the Isochronous URB if all the URB frames have been 5738c2ecf20Sopenharmony_ci * completed. 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 5768c2ecf20Sopenharmony_ci * @chan: Programming view of host channel 5778c2ecf20Sopenharmony_ci * @chnum: Channel number 5788c2ecf20Sopenharmony_ci * @halt_status: Reason for halting a host channel 5798c2ecf20Sopenharmony_ci * @qtd: Queue transfer descriptor 5808c2ecf20Sopenharmony_ci * 5818c2ecf20Sopenharmony_ci * Return: DWC2_HC_XFER_COMPLETE if there are more frames remaining to be 5828c2ecf20Sopenharmony_ci * transferred in the URB. Otherwise return DWC2_HC_XFER_URB_COMPLETE. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_cistatic enum dwc2_halt_status dwc2_update_isoc_urb_state( 5858c2ecf20Sopenharmony_ci struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, 5868c2ecf20Sopenharmony_ci int chnum, struct dwc2_qtd *qtd, 5878c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct dwc2_hcd_iso_packet_desc *frame_desc; 5908c2ecf20Sopenharmony_ci struct dwc2_hcd_urb *urb = qtd->urb; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (!urb) 5938c2ecf20Sopenharmony_ci return DWC2_HC_XFER_NO_HALT_STATUS; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci switch (halt_status) { 5988c2ecf20Sopenharmony_ci case DWC2_HC_XFER_COMPLETE: 5998c2ecf20Sopenharmony_ci frame_desc->status = 0; 6008c2ecf20Sopenharmony_ci frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg, 6018c2ecf20Sopenharmony_ci chan, chnum, qtd, halt_status, NULL); 6028c2ecf20Sopenharmony_ci break; 6038c2ecf20Sopenharmony_ci case DWC2_HC_XFER_FRAME_OVERRUN: 6048c2ecf20Sopenharmony_ci urb->error_count++; 6058c2ecf20Sopenharmony_ci if (chan->ep_is_in) 6068c2ecf20Sopenharmony_ci frame_desc->status = -ENOSR; 6078c2ecf20Sopenharmony_ci else 6088c2ecf20Sopenharmony_ci frame_desc->status = -ECOMM; 6098c2ecf20Sopenharmony_ci frame_desc->actual_length = 0; 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci case DWC2_HC_XFER_BABBLE_ERR: 6128c2ecf20Sopenharmony_ci urb->error_count++; 6138c2ecf20Sopenharmony_ci frame_desc->status = -EOVERFLOW; 6148c2ecf20Sopenharmony_ci /* Don't need to update actual_length in this case */ 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci case DWC2_HC_XFER_XACT_ERR: 6178c2ecf20Sopenharmony_ci urb->error_count++; 6188c2ecf20Sopenharmony_ci frame_desc->status = -EPROTO; 6198c2ecf20Sopenharmony_ci frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg, 6208c2ecf20Sopenharmony_ci chan, chnum, qtd, halt_status, NULL); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* Skip whole frame */ 6238c2ecf20Sopenharmony_ci if (chan->qh->do_split && 6248c2ecf20Sopenharmony_ci chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in && 6258c2ecf20Sopenharmony_ci hsotg->params.host_dma) { 6268c2ecf20Sopenharmony_ci qtd->complete_split = 0; 6278c2ecf20Sopenharmony_ci qtd->isoc_split_offset = 0; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci default: 6328c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "Unhandled halt_status (%d)\n", 6338c2ecf20Sopenharmony_ci halt_status); 6348c2ecf20Sopenharmony_ci break; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (++qtd->isoc_frame_index == urb->packet_count) { 6388c2ecf20Sopenharmony_ci /* 6398c2ecf20Sopenharmony_ci * urb->status is not used for isoc transfers. The individual 6408c2ecf20Sopenharmony_ci * frame_desc statuses are used instead. 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, 0); 6438c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_URB_COMPLETE; 6448c2ecf20Sopenharmony_ci } else { 6458c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_COMPLETE; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return halt_status; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci/* 6528c2ecf20Sopenharmony_ci * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic 6538c2ecf20Sopenharmony_ci * QHs, removes the QH from the active non-periodic schedule. If any QTDs are 6548c2ecf20Sopenharmony_ci * still linked to the QH, the QH is added to the end of the inactive 6558c2ecf20Sopenharmony_ci * non-periodic schedule. For periodic QHs, removes the QH from the periodic 6568c2ecf20Sopenharmony_ci * schedule if no more QTDs are linked to the QH. 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_cistatic void dwc2_deactivate_qh(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, 6598c2ecf20Sopenharmony_ci int free_qtd) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci int continue_split = 0; 6628c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (dbg_qh(qh)) 6658c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " %s(%p,%p,%d)\n", __func__, 6668c2ecf20Sopenharmony_ci hsotg, qh, free_qtd); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (list_empty(&qh->qtd_list)) { 6698c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "## QTD list empty ##\n"); 6708c2ecf20Sopenharmony_ci goto no_qtd; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (qtd->complete_split) 6768c2ecf20Sopenharmony_ci continue_split = 1; 6778c2ecf20Sopenharmony_ci else if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_MID || 6788c2ecf20Sopenharmony_ci qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_END) 6798c2ecf20Sopenharmony_ci continue_split = 1; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (free_qtd) { 6828c2ecf20Sopenharmony_ci dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); 6838c2ecf20Sopenharmony_ci continue_split = 0; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cino_qtd: 6878c2ecf20Sopenharmony_ci qh->channel = NULL; 6888c2ecf20Sopenharmony_ci dwc2_hcd_qh_deactivate(hsotg, qh, continue_split); 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci/** 6928c2ecf20Sopenharmony_ci * dwc2_release_channel() - Releases a host channel for use by other transfers 6938c2ecf20Sopenharmony_ci * 6948c2ecf20Sopenharmony_ci * @hsotg: The HCD state structure 6958c2ecf20Sopenharmony_ci * @chan: The host channel to release 6968c2ecf20Sopenharmony_ci * @qtd: The QTD associated with the host channel. This QTD may be 6978c2ecf20Sopenharmony_ci * freed if the transfer is complete or an error has occurred. 6988c2ecf20Sopenharmony_ci * @halt_status: Reason the channel is being released. This status 6998c2ecf20Sopenharmony_ci * determines the actions taken by this function. 7008c2ecf20Sopenharmony_ci * 7018c2ecf20Sopenharmony_ci * Also attempts to select and queue more transactions since at least one host 7028c2ecf20Sopenharmony_ci * channel is available. 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_cistatic void dwc2_release_channel(struct dwc2_hsotg *hsotg, 7058c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 7068c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, 7078c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci enum dwc2_transaction_type tr_type; 7108c2ecf20Sopenharmony_ci u32 haintmsk; 7118c2ecf20Sopenharmony_ci int free_qtd = 0; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 7148c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " %s: channel %d, halt_status %d\n", 7158c2ecf20Sopenharmony_ci __func__, chan->hc_num, halt_status); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci switch (halt_status) { 7188c2ecf20Sopenharmony_ci case DWC2_HC_XFER_URB_COMPLETE: 7198c2ecf20Sopenharmony_ci free_qtd = 1; 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci case DWC2_HC_XFER_AHB_ERR: 7228c2ecf20Sopenharmony_ci case DWC2_HC_XFER_STALL: 7238c2ecf20Sopenharmony_ci case DWC2_HC_XFER_BABBLE_ERR: 7248c2ecf20Sopenharmony_ci free_qtd = 1; 7258c2ecf20Sopenharmony_ci break; 7268c2ecf20Sopenharmony_ci case DWC2_HC_XFER_XACT_ERR: 7278c2ecf20Sopenharmony_ci if (qtd && qtd->error_count >= 3) { 7288c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 7298c2ecf20Sopenharmony_ci " Complete URB with transaction error\n"); 7308c2ecf20Sopenharmony_ci free_qtd = 1; 7318c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, -EPROTO); 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci break; 7348c2ecf20Sopenharmony_ci case DWC2_HC_XFER_URB_DEQUEUE: 7358c2ecf20Sopenharmony_ci /* 7368c2ecf20Sopenharmony_ci * The QTD has already been removed and the QH has been 7378c2ecf20Sopenharmony_ci * deactivated. Don't want to do anything except release the 7388c2ecf20Sopenharmony_ci * host channel and try to queue more transfers. 7398c2ecf20Sopenharmony_ci */ 7408c2ecf20Sopenharmony_ci goto cleanup; 7418c2ecf20Sopenharmony_ci case DWC2_HC_XFER_PERIODIC_INCOMPLETE: 7428c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " Complete URB with I/O error\n"); 7438c2ecf20Sopenharmony_ci free_qtd = 1; 7448c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, -EIO); 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci case DWC2_HC_XFER_NO_HALT_STATUS: 7478c2ecf20Sopenharmony_ci default: 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci dwc2_deactivate_qh(hsotg, chan->qh, free_qtd); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cicleanup: 7548c2ecf20Sopenharmony_ci /* 7558c2ecf20Sopenharmony_ci * Release the host channel for use by other transfers. The cleanup 7568c2ecf20Sopenharmony_ci * function clears the channel interrupt enables and conditions, so 7578c2ecf20Sopenharmony_ci * there's no need to clear the Channel Halted interrupt separately. 7588c2ecf20Sopenharmony_ci */ 7598c2ecf20Sopenharmony_ci if (!list_empty(&chan->hc_list_entry)) 7608c2ecf20Sopenharmony_ci list_del(&chan->hc_list_entry); 7618c2ecf20Sopenharmony_ci dwc2_hc_cleanup(hsotg, chan); 7628c2ecf20Sopenharmony_ci list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (hsotg->params.uframe_sched) { 7658c2ecf20Sopenharmony_ci hsotg->available_host_channels++; 7668c2ecf20Sopenharmony_ci } else { 7678c2ecf20Sopenharmony_ci switch (chan->ep_type) { 7688c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 7698c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 7708c2ecf20Sopenharmony_ci hsotg->non_periodic_channels--; 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci default: 7738c2ecf20Sopenharmony_ci /* 7748c2ecf20Sopenharmony_ci * Don't release reservations for periodic channels 7758c2ecf20Sopenharmony_ci * here. That's done when a periodic transfer is 7768c2ecf20Sopenharmony_ci * descheduled (i.e. when the QH is removed from the 7778c2ecf20Sopenharmony_ci * periodic schedule). 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci haintmsk = dwc2_readl(hsotg, HAINTMSK); 7848c2ecf20Sopenharmony_ci haintmsk &= ~(1 << chan->hc_num); 7858c2ecf20Sopenharmony_ci dwc2_writel(hsotg, haintmsk, HAINTMSK); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* Try to queue more transfers now that there's a free channel */ 7888c2ecf20Sopenharmony_ci tr_type = dwc2_hcd_select_transactions(hsotg); 7898c2ecf20Sopenharmony_ci if (tr_type != DWC2_TRANSACTION_NONE) 7908c2ecf20Sopenharmony_ci dwc2_hcd_queue_transactions(hsotg, tr_type); 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci/* 7948c2ecf20Sopenharmony_ci * Halts a host channel. If the channel cannot be halted immediately because 7958c2ecf20Sopenharmony_ci * the request queue is full, this function ensures that the FIFO empty 7968c2ecf20Sopenharmony_ci * interrupt for the appropriate queue is enabled so that the halt request can 7978c2ecf20Sopenharmony_ci * be queued when there is space in the request queue. 7988c2ecf20Sopenharmony_ci * 7998c2ecf20Sopenharmony_ci * This function may also be called in DMA mode. In that case, the channel is 8008c2ecf20Sopenharmony_ci * simply released since the core always halts the channel automatically in 8018c2ecf20Sopenharmony_ci * DMA mode. 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_cistatic void dwc2_halt_channel(struct dwc2_hsotg *hsotg, 8048c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, struct dwc2_qtd *qtd, 8058c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 8088c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s()\n", __func__); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (hsotg->params.host_dma) { 8118c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 8128c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "DMA enabled\n"); 8138c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, halt_status); 8148c2ecf20Sopenharmony_ci return; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* Slave mode processing */ 8188c2ecf20Sopenharmony_ci dwc2_hc_halt(hsotg, chan, halt_status); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (chan->halt_on_queue) { 8218c2ecf20Sopenharmony_ci u32 gintmsk; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "Halt on queue\n"); 8248c2ecf20Sopenharmony_ci if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL || 8258c2ecf20Sopenharmony_ci chan->ep_type == USB_ENDPOINT_XFER_BULK) { 8268c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "control/bulk\n"); 8278c2ecf20Sopenharmony_ci /* 8288c2ecf20Sopenharmony_ci * Make sure the Non-periodic Tx FIFO empty interrupt 8298c2ecf20Sopenharmony_ci * is enabled so that the non-periodic schedule will 8308c2ecf20Sopenharmony_ci * be processed 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_ci gintmsk = dwc2_readl(hsotg, GINTMSK); 8338c2ecf20Sopenharmony_ci gintmsk |= GINTSTS_NPTXFEMP; 8348c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gintmsk, GINTMSK); 8358c2ecf20Sopenharmony_ci } else { 8368c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "isoc/intr\n"); 8378c2ecf20Sopenharmony_ci /* 8388c2ecf20Sopenharmony_ci * Move the QH from the periodic queued schedule to 8398c2ecf20Sopenharmony_ci * the periodic assigned schedule. This allows the 8408c2ecf20Sopenharmony_ci * halt to be queued when the periodic schedule is 8418c2ecf20Sopenharmony_ci * processed. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci list_move_tail(&chan->qh->qh_list_entry, 8448c2ecf20Sopenharmony_ci &hsotg->periodic_sched_assigned); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* 8478c2ecf20Sopenharmony_ci * Make sure the Periodic Tx FIFO Empty interrupt is 8488c2ecf20Sopenharmony_ci * enabled so that the periodic schedule will be 8498c2ecf20Sopenharmony_ci * processed 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ci gintmsk = dwc2_readl(hsotg, GINTMSK); 8528c2ecf20Sopenharmony_ci gintmsk |= GINTSTS_PTXFEMP; 8538c2ecf20Sopenharmony_ci dwc2_writel(hsotg, gintmsk, GINTMSK); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci/* 8598c2ecf20Sopenharmony_ci * Performs common cleanup for non-periodic transfers after a Transfer 8608c2ecf20Sopenharmony_ci * Complete interrupt. This function should be called after any endpoint type 8618c2ecf20Sopenharmony_ci * specific handling is finished to release the host channel. 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_cistatic void dwc2_complete_non_periodic_xfer(struct dwc2_hsotg *hsotg, 8648c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, 8658c2ecf20Sopenharmony_ci int chnum, struct dwc2_qtd *qtd, 8668c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s()\n", __func__); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci qtd->error_count = 0; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (chan->hcint & HCINTMSK_NYET) { 8738c2ecf20Sopenharmony_ci /* 8748c2ecf20Sopenharmony_ci * Got a NYET on the last transaction of the transfer. This 8758c2ecf20Sopenharmony_ci * means that the endpoint should be in the PING state at the 8768c2ecf20Sopenharmony_ci * beginning of the next transfer. 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "got NYET\n"); 8798c2ecf20Sopenharmony_ci chan->qh->ping_state = 1; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* 8838c2ecf20Sopenharmony_ci * Always halt and release the host channel to make it available for 8848c2ecf20Sopenharmony_ci * more transfers. There may still be more phases for a control 8858c2ecf20Sopenharmony_ci * transfer or more data packets for a bulk transfer at this point, 8868c2ecf20Sopenharmony_ci * but the host channel is still halted. A channel will be reassigned 8878c2ecf20Sopenharmony_ci * to the transfer when the non-periodic schedule is processed after 8888c2ecf20Sopenharmony_ci * the channel is released. This allows transactions to be queued 8898c2ecf20Sopenharmony_ci * properly via dwc2_hcd_queue_transactions, which also enables the 8908c2ecf20Sopenharmony_ci * Tx FIFO Empty interrupt if necessary. 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_ci if (chan->ep_is_in) { 8938c2ecf20Sopenharmony_ci /* 8948c2ecf20Sopenharmony_ci * IN transfers in Slave mode require an explicit disable to 8958c2ecf20Sopenharmony_ci * halt the channel. (In DMA mode, this call simply releases 8968c2ecf20Sopenharmony_ci * the channel.) 8978c2ecf20Sopenharmony_ci */ 8988c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, halt_status); 8998c2ecf20Sopenharmony_ci } else { 9008c2ecf20Sopenharmony_ci /* 9018c2ecf20Sopenharmony_ci * The channel is automatically disabled by the core for OUT 9028c2ecf20Sopenharmony_ci * transfers in Slave mode 9038c2ecf20Sopenharmony_ci */ 9048c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, halt_status); 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* 9098c2ecf20Sopenharmony_ci * Performs common cleanup for periodic transfers after a Transfer Complete 9108c2ecf20Sopenharmony_ci * interrupt. This function should be called after any endpoint type specific 9118c2ecf20Sopenharmony_ci * handling is finished to release the host channel. 9128c2ecf20Sopenharmony_ci */ 9138c2ecf20Sopenharmony_cistatic void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg, 9148c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 9158c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, 9168c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci u32 hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum)); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci qtd->error_count = 0; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (!chan->ep_is_in || (hctsiz & TSIZ_PKTCNT_MASK) == 0) 9238c2ecf20Sopenharmony_ci /* Core halts channel in these cases */ 9248c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, halt_status); 9258c2ecf20Sopenharmony_ci else 9268c2ecf20Sopenharmony_ci /* Flush any outstanding requests from the Tx queue */ 9278c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, halt_status); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg, 9318c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 9328c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci struct dwc2_hcd_iso_packet_desc *frame_desc; 9358c2ecf20Sopenharmony_ci u32 len; 9368c2ecf20Sopenharmony_ci u32 hctsiz; 9378c2ecf20Sopenharmony_ci u32 pid; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (!qtd->urb) 9408c2ecf20Sopenharmony_ci return 0; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; 9438c2ecf20Sopenharmony_ci len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd, 9448c2ecf20Sopenharmony_ci DWC2_HC_XFER_COMPLETE, NULL); 9458c2ecf20Sopenharmony_ci if (!len && !qtd->isoc_split_offset) { 9468c2ecf20Sopenharmony_ci qtd->complete_split = 0; 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci frame_desc->actual_length += len; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (chan->align_buf) { 9538c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "non-aligned buffer\n"); 9548c2ecf20Sopenharmony_ci dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma, 9558c2ecf20Sopenharmony_ci DWC2_KMEM_UNALIGNED_BUF_SIZE, DMA_FROM_DEVICE); 9568c2ecf20Sopenharmony_ci memcpy(qtd->urb->buf + (chan->xfer_dma - qtd->urb->dma), 9578c2ecf20Sopenharmony_ci chan->qh->dw_align_buf, len); 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci qtd->isoc_split_offset += len; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum)); 9638c2ecf20Sopenharmony_ci pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (frame_desc->actual_length >= frame_desc->length || pid == 0) { 9668c2ecf20Sopenharmony_ci frame_desc->status = 0; 9678c2ecf20Sopenharmony_ci qtd->isoc_frame_index++; 9688c2ecf20Sopenharmony_ci qtd->complete_split = 0; 9698c2ecf20Sopenharmony_ci qtd->isoc_split_offset = 0; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (qtd->isoc_frame_index == qtd->urb->packet_count) { 9738c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, 0); 9748c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, 9758c2ecf20Sopenharmony_ci DWC2_HC_XFER_URB_COMPLETE); 9768c2ecf20Sopenharmony_ci } else { 9778c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, 9788c2ecf20Sopenharmony_ci DWC2_HC_XFER_NO_HALT_STATUS); 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci return 1; /* Indicates that channel released */ 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci/* 9858c2ecf20Sopenharmony_ci * Handles a host channel Transfer Complete interrupt. This handler may be 9868c2ecf20Sopenharmony_ci * called in either DMA mode or Slave mode. 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_cistatic void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg, 9898c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 9908c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct dwc2_hcd_urb *urb = qtd->urb; 9938c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status = DWC2_HC_XFER_COMPLETE; 9948c2ecf20Sopenharmony_ci int pipe_type; 9958c2ecf20Sopenharmony_ci int urb_xfer_done; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 9988c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 9998c2ecf20Sopenharmony_ci "--Host Channel %d Interrupt: Transfer Complete--\n", 10008c2ecf20Sopenharmony_ci chnum); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if (!urb) 10038c2ecf20Sopenharmony_ci goto handle_xfercomp_done; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 10088c2ecf20Sopenharmony_ci dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, halt_status); 10098c2ecf20Sopenharmony_ci if (pipe_type == USB_ENDPOINT_XFER_ISOC) 10108c2ecf20Sopenharmony_ci /* Do not disable the interrupt, just clear it */ 10118c2ecf20Sopenharmony_ci return; 10128c2ecf20Sopenharmony_ci goto handle_xfercomp_done; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci /* Handle xfer complete on CSPLIT */ 10168c2ecf20Sopenharmony_ci if (chan->qh->do_split) { 10178c2ecf20Sopenharmony_ci if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in && 10188c2ecf20Sopenharmony_ci hsotg->params.host_dma) { 10198c2ecf20Sopenharmony_ci if (qtd->complete_split && 10208c2ecf20Sopenharmony_ci dwc2_xfercomp_isoc_split_in(hsotg, chan, chnum, 10218c2ecf20Sopenharmony_ci qtd)) 10228c2ecf20Sopenharmony_ci goto handle_xfercomp_done; 10238c2ecf20Sopenharmony_ci } else { 10248c2ecf20Sopenharmony_ci qtd->complete_split = 0; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* Update the QTD and URB states */ 10298c2ecf20Sopenharmony_ci switch (pipe_type) { 10308c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 10318c2ecf20Sopenharmony_ci switch (qtd->control_phase) { 10328c2ecf20Sopenharmony_ci case DWC2_CONTROL_SETUP: 10338c2ecf20Sopenharmony_ci if (urb->length > 0) 10348c2ecf20Sopenharmony_ci qtd->control_phase = DWC2_CONTROL_DATA; 10358c2ecf20Sopenharmony_ci else 10368c2ecf20Sopenharmony_ci qtd->control_phase = DWC2_CONTROL_STATUS; 10378c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 10388c2ecf20Sopenharmony_ci " Control setup transaction done\n"); 10398c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_COMPLETE; 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci case DWC2_CONTROL_DATA: 10428c2ecf20Sopenharmony_ci urb_xfer_done = dwc2_update_urb_state(hsotg, chan, 10438c2ecf20Sopenharmony_ci chnum, urb, qtd); 10448c2ecf20Sopenharmony_ci if (urb_xfer_done) { 10458c2ecf20Sopenharmony_ci qtd->control_phase = DWC2_CONTROL_STATUS; 10468c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 10478c2ecf20Sopenharmony_ci " Control data transfer done\n"); 10488c2ecf20Sopenharmony_ci } else { 10498c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, 10508c2ecf20Sopenharmony_ci qtd); 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_COMPLETE; 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci case DWC2_CONTROL_STATUS: 10558c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " Control transfer complete\n"); 10568c2ecf20Sopenharmony_ci if (urb->status == -EINPROGRESS) 10578c2ecf20Sopenharmony_ci urb->status = 0; 10588c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, urb->status); 10598c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_URB_COMPLETE; 10608c2ecf20Sopenharmony_ci break; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd, 10648c2ecf20Sopenharmony_ci halt_status); 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 10678c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " Bulk transfer complete\n"); 10688c2ecf20Sopenharmony_ci urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb, 10698c2ecf20Sopenharmony_ci qtd); 10708c2ecf20Sopenharmony_ci if (urb_xfer_done) { 10718c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, urb->status); 10728c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_URB_COMPLETE; 10738c2ecf20Sopenharmony_ci } else { 10748c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_COMPLETE; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); 10788c2ecf20Sopenharmony_ci dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd, 10798c2ecf20Sopenharmony_ci halt_status); 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 10828c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " Interrupt transfer complete\n"); 10838c2ecf20Sopenharmony_ci urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb, 10848c2ecf20Sopenharmony_ci qtd); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci /* 10878c2ecf20Sopenharmony_ci * Interrupt URB is done on the first transfer complete 10888c2ecf20Sopenharmony_ci * interrupt 10898c2ecf20Sopenharmony_ci */ 10908c2ecf20Sopenharmony_ci if (urb_xfer_done) { 10918c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, urb->status); 10928c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_URB_COMPLETE; 10938c2ecf20Sopenharmony_ci } else { 10948c2ecf20Sopenharmony_ci halt_status = DWC2_HC_XFER_COMPLETE; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); 10988c2ecf20Sopenharmony_ci dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd, 10998c2ecf20Sopenharmony_ci halt_status); 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 11028c2ecf20Sopenharmony_ci if (dbg_perio()) 11038c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " Isochronous transfer complete\n"); 11048c2ecf20Sopenharmony_ci if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_ALL) 11058c2ecf20Sopenharmony_ci halt_status = dwc2_update_isoc_urb_state(hsotg, chan, 11068c2ecf20Sopenharmony_ci chnum, qtd, 11078c2ecf20Sopenharmony_ci DWC2_HC_XFER_COMPLETE); 11088c2ecf20Sopenharmony_ci dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd, 11098c2ecf20Sopenharmony_ci halt_status); 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cihandle_xfercomp_done: 11148c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_XFERCOMPL); 11158c2ecf20Sopenharmony_ci} 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci/* 11188c2ecf20Sopenharmony_ci * Handles a host channel STALL interrupt. This handler may be called in 11198c2ecf20Sopenharmony_ci * either DMA mode or Slave mode. 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_cistatic void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg, 11228c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 11238c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci struct dwc2_hcd_urb *urb = qtd->urb; 11268c2ecf20Sopenharmony_ci int pipe_type; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: STALL Received--\n", 11298c2ecf20Sopenharmony_ci chnum); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 11328c2ecf20Sopenharmony_ci dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, 11338c2ecf20Sopenharmony_ci DWC2_HC_XFER_STALL); 11348c2ecf20Sopenharmony_ci goto handle_stall_done; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (!urb) 11388c2ecf20Sopenharmony_ci goto handle_stall_halt; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (pipe_type == USB_ENDPOINT_XFER_CONTROL) 11438c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, -EPIPE); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (pipe_type == USB_ENDPOINT_XFER_BULK || 11468c2ecf20Sopenharmony_ci pipe_type == USB_ENDPOINT_XFER_INT) { 11478c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, -EPIPE); 11488c2ecf20Sopenharmony_ci /* 11498c2ecf20Sopenharmony_ci * USB protocol requires resetting the data toggle for bulk 11508c2ecf20Sopenharmony_ci * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT) 11518c2ecf20Sopenharmony_ci * setup command is issued to the endpoint. Anticipate the 11528c2ecf20Sopenharmony_ci * CLEAR_FEATURE command since a STALL has occurred and reset 11538c2ecf20Sopenharmony_ci * the data toggle now. 11548c2ecf20Sopenharmony_ci */ 11558c2ecf20Sopenharmony_ci chan->qh->data_toggle = 0; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cihandle_stall_halt: 11598c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_STALL); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_cihandle_stall_done: 11628c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_STALL); 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci/* 11668c2ecf20Sopenharmony_ci * Updates the state of the URB when a transfer has been stopped due to an 11678c2ecf20Sopenharmony_ci * abnormal condition before the transfer completes. Modifies the 11688c2ecf20Sopenharmony_ci * actual_length field of the URB to reflect the number of bytes that have 11698c2ecf20Sopenharmony_ci * actually been transferred via the host channel. 11708c2ecf20Sopenharmony_ci */ 11718c2ecf20Sopenharmony_cistatic void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg, 11728c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 11738c2ecf20Sopenharmony_ci struct dwc2_hcd_urb *urb, 11748c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd, 11758c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci u32 xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum, 11788c2ecf20Sopenharmony_ci qtd, halt_status, NULL); 11798c2ecf20Sopenharmony_ci u32 hctsiz; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (urb->actual_length + xfer_length > urb->length) { 11828c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__); 11838c2ecf20Sopenharmony_ci xfer_length = urb->length - urb->actual_length; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci urb->actual_length += xfer_length; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum)); 11898c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n", 11908c2ecf20Sopenharmony_ci __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum); 11918c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " chan->start_pkt_count %d\n", 11928c2ecf20Sopenharmony_ci chan->start_pkt_count); 11938c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " hctsiz.pktcnt %d\n", 11948c2ecf20Sopenharmony_ci (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT); 11958c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " chan->max_packet %d\n", chan->max_packet); 11968c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " bytes_transferred %d\n", 11978c2ecf20Sopenharmony_ci xfer_length); 11988c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " urb->actual_length %d\n", 11998c2ecf20Sopenharmony_ci urb->actual_length); 12008c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, " urb->transfer_buffer_length %d\n", 12018c2ecf20Sopenharmony_ci urb->length); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci/* 12058c2ecf20Sopenharmony_ci * Handles a host channel NAK interrupt. This handler may be called in either 12068c2ecf20Sopenharmony_ci * DMA mode or Slave mode. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_cistatic void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg, 12098c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 12108c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci if (!qtd) { 12138c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: qtd is NULL\n", __func__); 12148c2ecf20Sopenharmony_ci return; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (!qtd->urb) { 12188c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "%s: qtd->urb is NULL\n", __func__); 12198c2ecf20Sopenharmony_ci return; 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 12238c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n", 12248c2ecf20Sopenharmony_ci chnum); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* 12278c2ecf20Sopenharmony_ci * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and 12288c2ecf20Sopenharmony_ci * interrupt. Re-start the SSPLIT transfer. 12298c2ecf20Sopenharmony_ci * 12308c2ecf20Sopenharmony_ci * Normally for non-periodic transfers we'll retry right away, but to 12318c2ecf20Sopenharmony_ci * avoid interrupt storms we'll wait before retrying if we've got 12328c2ecf20Sopenharmony_ci * several NAKs. If we didn't do this we'd retry directly from the 12338c2ecf20Sopenharmony_ci * interrupt handler and could end up quickly getting another 12348c2ecf20Sopenharmony_ci * interrupt (another NAK), which we'd retry. Note that we do not 12358c2ecf20Sopenharmony_ci * delay retries for IN parts of control requests, as those are expected 12368c2ecf20Sopenharmony_ci * to complete fairly quickly, and if we delay them we risk confusing 12378c2ecf20Sopenharmony_ci * the device and cause it issue STALL. 12388c2ecf20Sopenharmony_ci * 12398c2ecf20Sopenharmony_ci * Note that in DMA mode software only gets involved to re-send NAKed 12408c2ecf20Sopenharmony_ci * transfers for split transactions, so we only need to apply this 12418c2ecf20Sopenharmony_ci * delaying logic when handling splits. In non-DMA mode presumably we 12428c2ecf20Sopenharmony_ci * might want a similar delay if someone can demonstrate this problem 12438c2ecf20Sopenharmony_ci * affects that code path too. 12448c2ecf20Sopenharmony_ci */ 12458c2ecf20Sopenharmony_ci if (chan->do_split) { 12468c2ecf20Sopenharmony_ci if (chan->complete_split) 12478c2ecf20Sopenharmony_ci qtd->error_count = 0; 12488c2ecf20Sopenharmony_ci qtd->complete_split = 0; 12498c2ecf20Sopenharmony_ci qtd->num_naks++; 12508c2ecf20Sopenharmony_ci qtd->qh->want_wait = qtd->num_naks >= DWC2_NAKS_BEFORE_DELAY && 12518c2ecf20Sopenharmony_ci !(chan->ep_type == USB_ENDPOINT_XFER_CONTROL && 12528c2ecf20Sopenharmony_ci chan->ep_is_in); 12538c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK); 12548c2ecf20Sopenharmony_ci goto handle_nak_done; 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) { 12588c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 12598c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 12608c2ecf20Sopenharmony_ci if (hsotg->params.host_dma && chan->ep_is_in) { 12618c2ecf20Sopenharmony_ci /* 12628c2ecf20Sopenharmony_ci * NAK interrupts are enabled on bulk/control IN 12638c2ecf20Sopenharmony_ci * transfers in DMA mode for the sole purpose of 12648c2ecf20Sopenharmony_ci * resetting the error count after a transaction error 12658c2ecf20Sopenharmony_ci * occurs. The core will continue transferring data. 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci qtd->error_count = 0; 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* 12728c2ecf20Sopenharmony_ci * NAK interrupts normally occur during OUT transfers in DMA 12738c2ecf20Sopenharmony_ci * or Slave mode. For IN transfers, more requests will be 12748c2ecf20Sopenharmony_ci * queued as request queue space is available. 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_ci qtd->error_count = 0; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (!chan->qh->ping_state) { 12798c2ecf20Sopenharmony_ci dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, 12808c2ecf20Sopenharmony_ci qtd, DWC2_HC_XFER_NAK); 12818c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci if (chan->speed == USB_SPEED_HIGH) 12848c2ecf20Sopenharmony_ci chan->qh->ping_state = 1; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci /* 12888c2ecf20Sopenharmony_ci * Halt the channel so the transfer can be re-started from 12898c2ecf20Sopenharmony_ci * the appropriate point or the PING protocol will 12908c2ecf20Sopenharmony_ci * start/continue 12918c2ecf20Sopenharmony_ci */ 12928c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK); 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 12958c2ecf20Sopenharmony_ci qtd->error_count = 0; 12968c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK); 12978c2ecf20Sopenharmony_ci break; 12988c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 12998c2ecf20Sopenharmony_ci /* Should never get called for isochronous transfers */ 13008c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "NACK interrupt for ISOC transfer\n"); 13018c2ecf20Sopenharmony_ci break; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cihandle_nak_done: 13058c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_NAK); 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci/* 13098c2ecf20Sopenharmony_ci * Handles a host channel ACK interrupt. This interrupt is enabled when 13108c2ecf20Sopenharmony_ci * performing the PING protocol in Slave mode, when errors occur during 13118c2ecf20Sopenharmony_ci * either Slave mode or DMA mode, and during Start Split transactions. 13128c2ecf20Sopenharmony_ci */ 13138c2ecf20Sopenharmony_cistatic void dwc2_hc_ack_intr(struct dwc2_hsotg *hsotg, 13148c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 13158c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci struct dwc2_hcd_iso_packet_desc *frame_desc; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 13208c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: ACK Received--\n", 13218c2ecf20Sopenharmony_ci chnum); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (chan->do_split) { 13248c2ecf20Sopenharmony_ci /* Handle ACK on SSPLIT. ACK should not occur in CSPLIT. */ 13258c2ecf20Sopenharmony_ci if (!chan->ep_is_in && 13268c2ecf20Sopenharmony_ci chan->data_pid_start != DWC2_HC_PID_SETUP) 13278c2ecf20Sopenharmony_ci qtd->ssplit_out_xfer_count = chan->xfer_len; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (chan->ep_type != USB_ENDPOINT_XFER_ISOC || chan->ep_is_in) { 13308c2ecf20Sopenharmony_ci qtd->complete_split = 1; 13318c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK); 13328c2ecf20Sopenharmony_ci } else { 13338c2ecf20Sopenharmony_ci /* ISOC OUT */ 13348c2ecf20Sopenharmony_ci switch (chan->xact_pos) { 13358c2ecf20Sopenharmony_ci case DWC2_HCSPLT_XACTPOS_ALL: 13368c2ecf20Sopenharmony_ci break; 13378c2ecf20Sopenharmony_ci case DWC2_HCSPLT_XACTPOS_END: 13388c2ecf20Sopenharmony_ci qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL; 13398c2ecf20Sopenharmony_ci qtd->isoc_split_offset = 0; 13408c2ecf20Sopenharmony_ci break; 13418c2ecf20Sopenharmony_ci case DWC2_HCSPLT_XACTPOS_BEGIN: 13428c2ecf20Sopenharmony_ci case DWC2_HCSPLT_XACTPOS_MID: 13438c2ecf20Sopenharmony_ci /* 13448c2ecf20Sopenharmony_ci * For BEGIN or MID, calculate the length for 13458c2ecf20Sopenharmony_ci * the next microframe to determine the correct 13468c2ecf20Sopenharmony_ci * SSPLIT token, either MID or END 13478c2ecf20Sopenharmony_ci */ 13488c2ecf20Sopenharmony_ci frame_desc = &qtd->urb->iso_descs[ 13498c2ecf20Sopenharmony_ci qtd->isoc_frame_index]; 13508c2ecf20Sopenharmony_ci qtd->isoc_split_offset += 188; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (frame_desc->length - qtd->isoc_split_offset 13538c2ecf20Sopenharmony_ci <= 188) 13548c2ecf20Sopenharmony_ci qtd->isoc_split_pos = 13558c2ecf20Sopenharmony_ci DWC2_HCSPLT_XACTPOS_END; 13568c2ecf20Sopenharmony_ci else 13578c2ecf20Sopenharmony_ci qtd->isoc_split_pos = 13588c2ecf20Sopenharmony_ci DWC2_HCSPLT_XACTPOS_MID; 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci } else { 13638c2ecf20Sopenharmony_ci qtd->error_count = 0; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (chan->qh->ping_state) { 13668c2ecf20Sopenharmony_ci chan->qh->ping_state = 0; 13678c2ecf20Sopenharmony_ci /* 13688c2ecf20Sopenharmony_ci * Halt the channel so the transfer can be re-started 13698c2ecf20Sopenharmony_ci * from the appropriate point. This only happens in 13708c2ecf20Sopenharmony_ci * Slave mode. In DMA mode, the ping_state is cleared 13718c2ecf20Sopenharmony_ci * when the transfer is started because the core 13728c2ecf20Sopenharmony_ci * automatically executes the PING, then the transfer. 13738c2ecf20Sopenharmony_ci */ 13748c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK); 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci /* 13798c2ecf20Sopenharmony_ci * If the ACK occurred when _not_ in the PING state, let the channel 13808c2ecf20Sopenharmony_ci * continue transferring data after clearing the error count 13818c2ecf20Sopenharmony_ci */ 13828c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_ACK); 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/* 13868c2ecf20Sopenharmony_ci * Handles a host channel NYET interrupt. This interrupt should only occur on 13878c2ecf20Sopenharmony_ci * Bulk and Control OUT endpoints and for complete split transactions. If a 13888c2ecf20Sopenharmony_ci * NYET occurs at the same time as a Transfer Complete interrupt, it is 13898c2ecf20Sopenharmony_ci * handled in the xfercomp interrupt handler, not here. This handler may be 13908c2ecf20Sopenharmony_ci * called in either DMA mode or Slave mode. 13918c2ecf20Sopenharmony_ci */ 13928c2ecf20Sopenharmony_cistatic void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, 13938c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 13948c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 13958c2ecf20Sopenharmony_ci{ 13968c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 13978c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NYET Received--\n", 13988c2ecf20Sopenharmony_ci chnum); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci /* 14018c2ecf20Sopenharmony_ci * NYET on CSPLIT 14028c2ecf20Sopenharmony_ci * re-do the CSPLIT immediately on non-periodic 14038c2ecf20Sopenharmony_ci */ 14048c2ecf20Sopenharmony_ci if (chan->do_split && chan->complete_split) { 14058c2ecf20Sopenharmony_ci if (chan->ep_is_in && chan->ep_type == USB_ENDPOINT_XFER_ISOC && 14068c2ecf20Sopenharmony_ci hsotg->params.host_dma) { 14078c2ecf20Sopenharmony_ci qtd->complete_split = 0; 14088c2ecf20Sopenharmony_ci qtd->isoc_split_offset = 0; 14098c2ecf20Sopenharmony_ci qtd->isoc_frame_index++; 14108c2ecf20Sopenharmony_ci if (qtd->urb && 14118c2ecf20Sopenharmony_ci qtd->isoc_frame_index == qtd->urb->packet_count) { 14128c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, 0); 14138c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, 14148c2ecf20Sopenharmony_ci DWC2_HC_XFER_URB_COMPLETE); 14158c2ecf20Sopenharmony_ci } else { 14168c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, 14178c2ecf20Sopenharmony_ci DWC2_HC_XFER_NO_HALT_STATUS); 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci goto handle_nyet_done; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (chan->ep_type == USB_ENDPOINT_XFER_INT || 14238c2ecf20Sopenharmony_ci chan->ep_type == USB_ENDPOINT_XFER_ISOC) { 14248c2ecf20Sopenharmony_ci struct dwc2_qh *qh = chan->qh; 14258c2ecf20Sopenharmony_ci bool past_end; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (!hsotg->params.uframe_sched) { 14288c2ecf20Sopenharmony_ci int frnum = dwc2_hcd_get_frame_number(hsotg); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* Don't have num_hs_transfers; simple logic */ 14318c2ecf20Sopenharmony_ci past_end = dwc2_full_frame_num(frnum) != 14328c2ecf20Sopenharmony_ci dwc2_full_frame_num(qh->next_active_frame); 14338c2ecf20Sopenharmony_ci } else { 14348c2ecf20Sopenharmony_ci int end_frnum; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci /* 14378c2ecf20Sopenharmony_ci * Figure out the end frame based on 14388c2ecf20Sopenharmony_ci * schedule. 14398c2ecf20Sopenharmony_ci * 14408c2ecf20Sopenharmony_ci * We don't want to go on trying again 14418c2ecf20Sopenharmony_ci * and again forever. Let's stop when 14428c2ecf20Sopenharmony_ci * we've done all the transfers that 14438c2ecf20Sopenharmony_ci * were scheduled. 14448c2ecf20Sopenharmony_ci * 14458c2ecf20Sopenharmony_ci * We're going to be comparing 14468c2ecf20Sopenharmony_ci * start_active_frame and 14478c2ecf20Sopenharmony_ci * next_active_frame, both of which 14488c2ecf20Sopenharmony_ci * are 1 before the time the packet 14498c2ecf20Sopenharmony_ci * goes on the wire, so that cancels 14508c2ecf20Sopenharmony_ci * out. Basically if had 1 transfer 14518c2ecf20Sopenharmony_ci * and we saw 1 NYET then we're done. 14528c2ecf20Sopenharmony_ci * We're getting a NYET here so if 14538c2ecf20Sopenharmony_ci * next >= (start + num_transfers) 14548c2ecf20Sopenharmony_ci * we're done. The complexity is that 14558c2ecf20Sopenharmony_ci * for all but ISOC_OUT we skip one 14568c2ecf20Sopenharmony_ci * slot. 14578c2ecf20Sopenharmony_ci */ 14588c2ecf20Sopenharmony_ci end_frnum = dwc2_frame_num_inc( 14598c2ecf20Sopenharmony_ci qh->start_active_frame, 14608c2ecf20Sopenharmony_ci qh->num_hs_transfers); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci if (qh->ep_type != USB_ENDPOINT_XFER_ISOC || 14638c2ecf20Sopenharmony_ci qh->ep_is_in) 14648c2ecf20Sopenharmony_ci end_frnum = 14658c2ecf20Sopenharmony_ci dwc2_frame_num_inc(end_frnum, 1); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci past_end = dwc2_frame_num_le( 14688c2ecf20Sopenharmony_ci end_frnum, qh->next_active_frame); 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (past_end) { 14728c2ecf20Sopenharmony_ci /* Treat this as a transaction error. */ 14738c2ecf20Sopenharmony_ci#if 0 14748c2ecf20Sopenharmony_ci /* 14758c2ecf20Sopenharmony_ci * Todo: Fix system performance so this can 14768c2ecf20Sopenharmony_ci * be treated as an error. Right now complete 14778c2ecf20Sopenharmony_ci * splits cannot be scheduled precisely enough 14788c2ecf20Sopenharmony_ci * due to other system activity, so this error 14798c2ecf20Sopenharmony_ci * occurs regularly in Slave mode. 14808c2ecf20Sopenharmony_ci */ 14818c2ecf20Sopenharmony_ci qtd->error_count++; 14828c2ecf20Sopenharmony_ci#endif 14838c2ecf20Sopenharmony_ci qtd->complete_split = 0; 14848c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, 14858c2ecf20Sopenharmony_ci DWC2_HC_XFER_XACT_ERR); 14868c2ecf20Sopenharmony_ci /* Todo: add support for isoc release */ 14878c2ecf20Sopenharmony_ci goto handle_nyet_done; 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET); 14928c2ecf20Sopenharmony_ci goto handle_nyet_done; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci chan->qh->ping_state = 1; 14968c2ecf20Sopenharmony_ci qtd->error_count = 0; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, qtd, 14998c2ecf20Sopenharmony_ci DWC2_HC_XFER_NYET); 15008c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci /* 15038c2ecf20Sopenharmony_ci * Halt the channel and re-start the transfer so the PING protocol 15048c2ecf20Sopenharmony_ci * will start 15058c2ecf20Sopenharmony_ci */ 15068c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_cihandle_nyet_done: 15098c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_NYET); 15108c2ecf20Sopenharmony_ci} 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci/* 15138c2ecf20Sopenharmony_ci * Handles a host channel babble interrupt. This handler may be called in 15148c2ecf20Sopenharmony_ci * either DMA mode or Slave mode. 15158c2ecf20Sopenharmony_ci */ 15168c2ecf20Sopenharmony_cistatic void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg, 15178c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 15188c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Babble Error--\n", 15218c2ecf20Sopenharmony_ci chnum); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci dwc2_hc_handle_tt_clear(hsotg, chan, qtd); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 15268c2ecf20Sopenharmony_ci dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, 15278c2ecf20Sopenharmony_ci DWC2_HC_XFER_BABBLE_ERR); 15288c2ecf20Sopenharmony_ci goto disable_int; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) { 15328c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, -EOVERFLOW); 15338c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_BABBLE_ERR); 15348c2ecf20Sopenharmony_ci } else { 15358c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum, 15388c2ecf20Sopenharmony_ci qtd, DWC2_HC_XFER_BABBLE_ERR); 15398c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, halt_status); 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_cidisable_int: 15438c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_BBLERR); 15448c2ecf20Sopenharmony_ci} 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci/* 15478c2ecf20Sopenharmony_ci * Handles a host channel AHB error interrupt. This handler is only called in 15488c2ecf20Sopenharmony_ci * DMA mode. 15498c2ecf20Sopenharmony_ci */ 15508c2ecf20Sopenharmony_cistatic void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg, 15518c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 15528c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci struct dwc2_hcd_urb *urb = qtd->urb; 15558c2ecf20Sopenharmony_ci char *pipetype, *speed; 15568c2ecf20Sopenharmony_ci u32 hcchar; 15578c2ecf20Sopenharmony_ci u32 hcsplt; 15588c2ecf20Sopenharmony_ci u32 hctsiz; 15598c2ecf20Sopenharmony_ci u32 hc_dma; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: AHB Error--\n", 15628c2ecf20Sopenharmony_ci chnum); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci if (!urb) 15658c2ecf20Sopenharmony_ci goto handle_ahberr_halt; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci dwc2_hc_handle_tt_clear(hsotg, chan, qtd); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci hcchar = dwc2_readl(hsotg, HCCHAR(chnum)); 15708c2ecf20Sopenharmony_ci hcsplt = dwc2_readl(hsotg, HCSPLT(chnum)); 15718c2ecf20Sopenharmony_ci hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum)); 15728c2ecf20Sopenharmony_ci hc_dma = dwc2_readl(hsotg, HCDMA(chnum)); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum); 15758c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt); 15768c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " hctsiz 0x%08x, hc_dma 0x%08x\n", hctsiz, hc_dma); 15778c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Device address: %d\n", 15788c2ecf20Sopenharmony_ci dwc2_hcd_get_dev_addr(&urb->pipe_info)); 15798c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Endpoint: %d, %s\n", 15808c2ecf20Sopenharmony_ci dwc2_hcd_get_ep_num(&urb->pipe_info), 15818c2ecf20Sopenharmony_ci dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) { 15848c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 15858c2ecf20Sopenharmony_ci pipetype = "CONTROL"; 15868c2ecf20Sopenharmony_ci break; 15878c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 15888c2ecf20Sopenharmony_ci pipetype = "BULK"; 15898c2ecf20Sopenharmony_ci break; 15908c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 15918c2ecf20Sopenharmony_ci pipetype = "INTERRUPT"; 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 15948c2ecf20Sopenharmony_ci pipetype = "ISOCHRONOUS"; 15958c2ecf20Sopenharmony_ci break; 15968c2ecf20Sopenharmony_ci default: 15978c2ecf20Sopenharmony_ci pipetype = "UNKNOWN"; 15988c2ecf20Sopenharmony_ci break; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Endpoint type: %s\n", pipetype); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci switch (chan->speed) { 16048c2ecf20Sopenharmony_ci case USB_SPEED_HIGH: 16058c2ecf20Sopenharmony_ci speed = "HIGH"; 16068c2ecf20Sopenharmony_ci break; 16078c2ecf20Sopenharmony_ci case USB_SPEED_FULL: 16088c2ecf20Sopenharmony_ci speed = "FULL"; 16098c2ecf20Sopenharmony_ci break; 16108c2ecf20Sopenharmony_ci case USB_SPEED_LOW: 16118c2ecf20Sopenharmony_ci speed = "LOW"; 16128c2ecf20Sopenharmony_ci break; 16138c2ecf20Sopenharmony_ci default: 16148c2ecf20Sopenharmony_ci speed = "UNKNOWN"; 16158c2ecf20Sopenharmony_ci break; 16168c2ecf20Sopenharmony_ci } 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Speed: %s\n", speed); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Max packet size: %d (mult %d)\n", 16218c2ecf20Sopenharmony_ci dwc2_hcd_get_maxp(&urb->pipe_info), 16228c2ecf20Sopenharmony_ci dwc2_hcd_get_maxp_mult(&urb->pipe_info)); 16238c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Data buffer length: %d\n", urb->length); 16248c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Transfer buffer: %p, Transfer DMA: %08lx\n", 16258c2ecf20Sopenharmony_ci urb->buf, (unsigned long)urb->dma); 16268c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Setup buffer: %p, Setup DMA: %08lx\n", 16278c2ecf20Sopenharmony_ci urb->setup_packet, (unsigned long)urb->setup_dma); 16288c2ecf20Sopenharmony_ci dev_err(hsotg->dev, " Interval: %d\n", urb->interval); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* Core halts the channel for Descriptor DMA mode */ 16318c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 16328c2ecf20Sopenharmony_ci dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, 16338c2ecf20Sopenharmony_ci DWC2_HC_XFER_AHB_ERR); 16348c2ecf20Sopenharmony_ci goto handle_ahberr_done; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci dwc2_host_complete(hsotg, qtd, -EIO); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cihandle_ahberr_halt: 16408c2ecf20Sopenharmony_ci /* 16418c2ecf20Sopenharmony_ci * Force a channel halt. Don't call dwc2_halt_channel because that won't 16428c2ecf20Sopenharmony_ci * write to the HCCHARn register in DMA mode to force the halt. 16438c2ecf20Sopenharmony_ci */ 16448c2ecf20Sopenharmony_ci dwc2_hc_halt(hsotg, chan, DWC2_HC_XFER_AHB_ERR); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_cihandle_ahberr_done: 16478c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_AHBERR); 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci/* 16518c2ecf20Sopenharmony_ci * Handles a host channel transaction error interrupt. This handler may be 16528c2ecf20Sopenharmony_ci * called in either DMA mode or Slave mode. 16538c2ecf20Sopenharmony_ci */ 16548c2ecf20Sopenharmony_cistatic void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg, 16558c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 16568c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 16598c2ecf20Sopenharmony_ci "--Host Channel %d Interrupt: Transaction Error--\n", chnum); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci dwc2_hc_handle_tt_clear(hsotg, chan, qtd); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) { 16648c2ecf20Sopenharmony_ci dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, 16658c2ecf20Sopenharmony_ci DWC2_HC_XFER_XACT_ERR); 16668c2ecf20Sopenharmony_ci goto handle_xacterr_done; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) { 16708c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 16718c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 16728c2ecf20Sopenharmony_ci qtd->error_count++; 16738c2ecf20Sopenharmony_ci if (!chan->qh->ping_state) { 16748c2ecf20Sopenharmony_ci dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, 16758c2ecf20Sopenharmony_ci qtd, DWC2_HC_XFER_XACT_ERR); 16768c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); 16778c2ecf20Sopenharmony_ci if (!chan->ep_is_in && chan->speed == USB_SPEED_HIGH) 16788c2ecf20Sopenharmony_ci chan->qh->ping_state = 1; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci /* 16828c2ecf20Sopenharmony_ci * Halt the channel so the transfer can be re-started from 16838c2ecf20Sopenharmony_ci * the appropriate point or the PING protocol will start 16848c2ecf20Sopenharmony_ci */ 16858c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR); 16868c2ecf20Sopenharmony_ci break; 16878c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 16888c2ecf20Sopenharmony_ci qtd->error_count++; 16898c2ecf20Sopenharmony_ci if (chan->do_split && chan->complete_split) 16908c2ecf20Sopenharmony_ci qtd->complete_split = 0; 16918c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR); 16928c2ecf20Sopenharmony_ci break; 16938c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 16948c2ecf20Sopenharmony_ci { 16958c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci halt_status = dwc2_update_isoc_urb_state(hsotg, chan, 16988c2ecf20Sopenharmony_ci chnum, qtd, DWC2_HC_XFER_XACT_ERR); 16998c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, halt_status); 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci break; 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_cihandle_xacterr_done: 17058c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_XACTERR); 17068c2ecf20Sopenharmony_ci} 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci/* 17098c2ecf20Sopenharmony_ci * Handles a host channel frame overrun interrupt. This handler may be called 17108c2ecf20Sopenharmony_ci * in either DMA mode or Slave mode. 17118c2ecf20Sopenharmony_ci */ 17128c2ecf20Sopenharmony_cistatic void dwc2_hc_frmovrun_intr(struct dwc2_hsotg *hsotg, 17138c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 17148c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 17158c2ecf20Sopenharmony_ci{ 17168c2ecf20Sopenharmony_ci enum dwc2_halt_status halt_status; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 17198c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Frame Overrun--\n", 17208c2ecf20Sopenharmony_ci chnum); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci dwc2_hc_handle_tt_clear(hsotg, chan, qtd); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) { 17258c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 17268c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 17278c2ecf20Sopenharmony_ci break; 17288c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 17298c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_FRAME_OVERRUN); 17308c2ecf20Sopenharmony_ci break; 17318c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 17328c2ecf20Sopenharmony_ci halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum, 17338c2ecf20Sopenharmony_ci qtd, DWC2_HC_XFER_FRAME_OVERRUN); 17348c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, halt_status); 17358c2ecf20Sopenharmony_ci break; 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_FRMOVRUN); 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci/* 17428c2ecf20Sopenharmony_ci * Handles a host channel data toggle error interrupt. This handler may be 17438c2ecf20Sopenharmony_ci * called in either DMA mode or Slave mode. 17448c2ecf20Sopenharmony_ci */ 17458c2ecf20Sopenharmony_cistatic void dwc2_hc_datatglerr_intr(struct dwc2_hsotg *hsotg, 17468c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 17478c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 17508c2ecf20Sopenharmony_ci "--Host Channel %d Interrupt: Data Toggle Error--\n", chnum); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci if (chan->ep_is_in) 17538c2ecf20Sopenharmony_ci qtd->error_count = 0; 17548c2ecf20Sopenharmony_ci else 17558c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 17568c2ecf20Sopenharmony_ci "Data Toggle Error on OUT transfer, channel %d\n", 17578c2ecf20Sopenharmony_ci chnum); 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci dwc2_hc_handle_tt_clear(hsotg, chan, qtd); 17608c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_DATATGLERR); 17618c2ecf20Sopenharmony_ci} 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci/* 17648c2ecf20Sopenharmony_ci * For debug only. It checks that a valid halt status is set and that 17658c2ecf20Sopenharmony_ci * HCCHARn.chdis is clear. If there's a problem, corrective action is 17668c2ecf20Sopenharmony_ci * taken and a warning is issued. 17678c2ecf20Sopenharmony_ci * 17688c2ecf20Sopenharmony_ci * Return: true if halt status is ok, false otherwise 17698c2ecf20Sopenharmony_ci */ 17708c2ecf20Sopenharmony_cistatic bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg, 17718c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 17728c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 17738c2ecf20Sopenharmony_ci{ 17748c2ecf20Sopenharmony_ci#ifdef DEBUG 17758c2ecf20Sopenharmony_ci u32 hcchar; 17768c2ecf20Sopenharmony_ci u32 hctsiz; 17778c2ecf20Sopenharmony_ci u32 hcintmsk; 17788c2ecf20Sopenharmony_ci u32 hcsplt; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (chan->halt_status == DWC2_HC_XFER_NO_HALT_STATUS) { 17818c2ecf20Sopenharmony_ci /* 17828c2ecf20Sopenharmony_ci * This code is here only as a check. This condition should 17838c2ecf20Sopenharmony_ci * never happen. Ignore the halt if it does occur. 17848c2ecf20Sopenharmony_ci */ 17858c2ecf20Sopenharmony_ci hcchar = dwc2_readl(hsotg, HCCHAR(chnum)); 17868c2ecf20Sopenharmony_ci hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum)); 17878c2ecf20Sopenharmony_ci hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum)); 17888c2ecf20Sopenharmony_ci hcsplt = dwc2_readl(hsotg, HCSPLT(chnum)); 17898c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 17908c2ecf20Sopenharmony_ci "%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n", 17918c2ecf20Sopenharmony_ci __func__); 17928c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 17938c2ecf20Sopenharmony_ci "channel %d, hcchar 0x%08x, hctsiz 0x%08x,\n", 17948c2ecf20Sopenharmony_ci chnum, hcchar, hctsiz); 17958c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 17968c2ecf20Sopenharmony_ci "hcint 0x%08x, hcintmsk 0x%08x, hcsplt 0x%08x,\n", 17978c2ecf20Sopenharmony_ci chan->hcint, hcintmsk, hcsplt); 17988c2ecf20Sopenharmony_ci if (qtd) 17998c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "qtd->complete_split %d\n", 18008c2ecf20Sopenharmony_ci qtd->complete_split); 18018c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, 18028c2ecf20Sopenharmony_ci "%s: no halt status, channel %d, ignoring interrupt\n", 18038c2ecf20Sopenharmony_ci __func__, chnum); 18048c2ecf20Sopenharmony_ci return false; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci /* 18088c2ecf20Sopenharmony_ci * This code is here only as a check. hcchar.chdis should never be set 18098c2ecf20Sopenharmony_ci * when the halt interrupt occurs. Halt the channel again if it does 18108c2ecf20Sopenharmony_ci * occur. 18118c2ecf20Sopenharmony_ci */ 18128c2ecf20Sopenharmony_ci hcchar = dwc2_readl(hsotg, HCCHAR(chnum)); 18138c2ecf20Sopenharmony_ci if (hcchar & HCCHAR_CHDIS) { 18148c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, 18158c2ecf20Sopenharmony_ci "%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n", 18168c2ecf20Sopenharmony_ci __func__, hcchar); 18178c2ecf20Sopenharmony_ci chan->halt_pending = 0; 18188c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, chan->halt_status); 18198c2ecf20Sopenharmony_ci return false; 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci#endif 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci return true; 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci/* 18278c2ecf20Sopenharmony_ci * Handles a host Channel Halted interrupt in DMA mode. This handler 18288c2ecf20Sopenharmony_ci * determines the reason the channel halted and proceeds accordingly. 18298c2ecf20Sopenharmony_ci */ 18308c2ecf20Sopenharmony_cistatic void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg, 18318c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 18328c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 18338c2ecf20Sopenharmony_ci{ 18348c2ecf20Sopenharmony_ci u32 hcintmsk; 18358c2ecf20Sopenharmony_ci int out_nak_enh = 0; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 18388c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 18398c2ecf20Sopenharmony_ci "--Host Channel %d Interrupt: DMA Channel Halted--\n", 18408c2ecf20Sopenharmony_ci chnum); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* 18438c2ecf20Sopenharmony_ci * For core with OUT NAK enhancement, the flow for high-speed 18448c2ecf20Sopenharmony_ci * CONTROL/BULK OUT is handled a little differently 18458c2ecf20Sopenharmony_ci */ 18468c2ecf20Sopenharmony_ci if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_71a) { 18478c2ecf20Sopenharmony_ci if (chan->speed == USB_SPEED_HIGH && !chan->ep_is_in && 18488c2ecf20Sopenharmony_ci (chan->ep_type == USB_ENDPOINT_XFER_CONTROL || 18498c2ecf20Sopenharmony_ci chan->ep_type == USB_ENDPOINT_XFER_BULK)) { 18508c2ecf20Sopenharmony_ci out_nak_enh = 1; 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE || 18558c2ecf20Sopenharmony_ci (chan->halt_status == DWC2_HC_XFER_AHB_ERR && 18568c2ecf20Sopenharmony_ci !hsotg->params.dma_desc_enable)) { 18578c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) 18588c2ecf20Sopenharmony_ci dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, 18598c2ecf20Sopenharmony_ci chan->halt_status); 18608c2ecf20Sopenharmony_ci else 18618c2ecf20Sopenharmony_ci /* 18628c2ecf20Sopenharmony_ci * Just release the channel. A dequeue can happen on a 18638c2ecf20Sopenharmony_ci * transfer timeout. In the case of an AHB Error, the 18648c2ecf20Sopenharmony_ci * channel was forced to halt because there's no way to 18658c2ecf20Sopenharmony_ci * gracefully recover. 18668c2ecf20Sopenharmony_ci */ 18678c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, 18688c2ecf20Sopenharmony_ci chan->halt_status); 18698c2ecf20Sopenharmony_ci return; 18708c2ecf20Sopenharmony_ci } 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum)); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci if (chan->hcint & HCINTMSK_XFERCOMPL) { 18758c2ecf20Sopenharmony_ci /* 18768c2ecf20Sopenharmony_ci * Todo: This is here because of a possible hardware bug. Spec 18778c2ecf20Sopenharmony_ci * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT 18788c2ecf20Sopenharmony_ci * interrupt w/ACK bit set should occur, but I only see the 18798c2ecf20Sopenharmony_ci * XFERCOMP bit, even with it masked out. This is a workaround 18808c2ecf20Sopenharmony_ci * for that behavior. Should fix this when hardware is fixed. 18818c2ecf20Sopenharmony_ci */ 18828c2ecf20Sopenharmony_ci if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && !chan->ep_is_in) 18838c2ecf20Sopenharmony_ci dwc2_hc_ack_intr(hsotg, chan, chnum, qtd); 18848c2ecf20Sopenharmony_ci dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd); 18858c2ecf20Sopenharmony_ci } else if (chan->hcint & HCINTMSK_STALL) { 18868c2ecf20Sopenharmony_ci dwc2_hc_stall_intr(hsotg, chan, chnum, qtd); 18878c2ecf20Sopenharmony_ci } else if ((chan->hcint & HCINTMSK_XACTERR) && 18888c2ecf20Sopenharmony_ci !hsotg->params.dma_desc_enable) { 18898c2ecf20Sopenharmony_ci if (out_nak_enh) { 18908c2ecf20Sopenharmony_ci if (chan->hcint & 18918c2ecf20Sopenharmony_ci (HCINTMSK_NYET | HCINTMSK_NAK | HCINTMSK_ACK)) { 18928c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 18938c2ecf20Sopenharmony_ci "XactErr with NYET/NAK/ACK\n"); 18948c2ecf20Sopenharmony_ci qtd->error_count = 0; 18958c2ecf20Sopenharmony_ci } else { 18968c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 18978c2ecf20Sopenharmony_ci "XactErr without NYET/NAK/ACK\n"); 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci /* 19028c2ecf20Sopenharmony_ci * Must handle xacterr before nak or ack. Could get a xacterr 19038c2ecf20Sopenharmony_ci * at the same time as either of these on a BULK/CONTROL OUT 19048c2ecf20Sopenharmony_ci * that started with a PING. The xacterr takes precedence. 19058c2ecf20Sopenharmony_ci */ 19068c2ecf20Sopenharmony_ci dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); 19078c2ecf20Sopenharmony_ci } else if ((chan->hcint & HCINTMSK_XCS_XACT) && 19088c2ecf20Sopenharmony_ci hsotg->params.dma_desc_enable) { 19098c2ecf20Sopenharmony_ci dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); 19108c2ecf20Sopenharmony_ci } else if ((chan->hcint & HCINTMSK_AHBERR) && 19118c2ecf20Sopenharmony_ci hsotg->params.dma_desc_enable) { 19128c2ecf20Sopenharmony_ci dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd); 19138c2ecf20Sopenharmony_ci } else if (chan->hcint & HCINTMSK_BBLERR) { 19148c2ecf20Sopenharmony_ci dwc2_hc_babble_intr(hsotg, chan, chnum, qtd); 19158c2ecf20Sopenharmony_ci } else if (chan->hcint & HCINTMSK_FRMOVRUN) { 19168c2ecf20Sopenharmony_ci dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd); 19178c2ecf20Sopenharmony_ci } else if (!out_nak_enh) { 19188c2ecf20Sopenharmony_ci if (chan->hcint & HCINTMSK_NYET) { 19198c2ecf20Sopenharmony_ci /* 19208c2ecf20Sopenharmony_ci * Must handle nyet before nak or ack. Could get a nyet 19218c2ecf20Sopenharmony_ci * at the same time as either of those on a BULK/CONTROL 19228c2ecf20Sopenharmony_ci * OUT that started with a PING. The nyet takes 19238c2ecf20Sopenharmony_ci * precedence. 19248c2ecf20Sopenharmony_ci */ 19258c2ecf20Sopenharmony_ci dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd); 19268c2ecf20Sopenharmony_ci } else if ((chan->hcint & HCINTMSK_NAK) && 19278c2ecf20Sopenharmony_ci !(hcintmsk & HCINTMSK_NAK)) { 19288c2ecf20Sopenharmony_ci /* 19298c2ecf20Sopenharmony_ci * If nak is not masked, it's because a non-split IN 19308c2ecf20Sopenharmony_ci * transfer is in an error state. In that case, the nak 19318c2ecf20Sopenharmony_ci * is handled by the nak interrupt handler, not here. 19328c2ecf20Sopenharmony_ci * Handle nak here for BULK/CONTROL OUT transfers, which 19338c2ecf20Sopenharmony_ci * halt on a NAK to allow rewinding the buffer pointer. 19348c2ecf20Sopenharmony_ci */ 19358c2ecf20Sopenharmony_ci dwc2_hc_nak_intr(hsotg, chan, chnum, qtd); 19368c2ecf20Sopenharmony_ci } else if ((chan->hcint & HCINTMSK_ACK) && 19378c2ecf20Sopenharmony_ci !(hcintmsk & HCINTMSK_ACK)) { 19388c2ecf20Sopenharmony_ci /* 19398c2ecf20Sopenharmony_ci * If ack is not masked, it's because a non-split IN 19408c2ecf20Sopenharmony_ci * transfer is in an error state. In that case, the ack 19418c2ecf20Sopenharmony_ci * is handled by the ack interrupt handler, not here. 19428c2ecf20Sopenharmony_ci * Handle ack here for split transfers. Start splits 19438c2ecf20Sopenharmony_ci * halt on ACK. 19448c2ecf20Sopenharmony_ci */ 19458c2ecf20Sopenharmony_ci dwc2_hc_ack_intr(hsotg, chan, chnum, qtd); 19468c2ecf20Sopenharmony_ci } else { 19478c2ecf20Sopenharmony_ci if (chan->ep_type == USB_ENDPOINT_XFER_INT || 19488c2ecf20Sopenharmony_ci chan->ep_type == USB_ENDPOINT_XFER_ISOC) { 19498c2ecf20Sopenharmony_ci /* 19508c2ecf20Sopenharmony_ci * A periodic transfer halted with no other 19518c2ecf20Sopenharmony_ci * channel interrupts set. Assume it was halted 19528c2ecf20Sopenharmony_ci * by the core because it could not be completed 19538c2ecf20Sopenharmony_ci * in its scheduled (micro)frame. 19548c2ecf20Sopenharmony_ci */ 19558c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 19568c2ecf20Sopenharmony_ci "%s: Halt channel %d (assume incomplete periodic transfer)\n", 19578c2ecf20Sopenharmony_ci __func__, chnum); 19588c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, 19598c2ecf20Sopenharmony_ci DWC2_HC_XFER_PERIODIC_INCOMPLETE); 19608c2ecf20Sopenharmony_ci } else { 19618c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 19628c2ecf20Sopenharmony_ci "%s: Channel %d - ChHltd set, but reason is unknown\n", 19638c2ecf20Sopenharmony_ci __func__, chnum); 19648c2ecf20Sopenharmony_ci dev_err(hsotg->dev, 19658c2ecf20Sopenharmony_ci "hcint 0x%08x, intsts 0x%08x\n", 19668c2ecf20Sopenharmony_ci chan->hcint, 19678c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GINTSTS)); 19688c2ecf20Sopenharmony_ci goto error; 19698c2ecf20Sopenharmony_ci } 19708c2ecf20Sopenharmony_ci } 19718c2ecf20Sopenharmony_ci } else { 19728c2ecf20Sopenharmony_ci dev_info(hsotg->dev, 19738c2ecf20Sopenharmony_ci "NYET/NAK/ACK/other in non-error case, 0x%08x\n", 19748c2ecf20Sopenharmony_ci chan->hcint); 19758c2ecf20Sopenharmony_cierror: 19768c2ecf20Sopenharmony_ci /* Failthrough: use 3-strikes rule */ 19778c2ecf20Sopenharmony_ci qtd->error_count++; 19788c2ecf20Sopenharmony_ci dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, 19798c2ecf20Sopenharmony_ci qtd, DWC2_HC_XFER_XACT_ERR); 19808c2ecf20Sopenharmony_ci /* 19818c2ecf20Sopenharmony_ci * We can get here after a completed transaction 19828c2ecf20Sopenharmony_ci * (urb->actual_length >= urb->length) which was not reported 19838c2ecf20Sopenharmony_ci * as completed. If that is the case, and we do not abort 19848c2ecf20Sopenharmony_ci * the transfer, a transfer of size 0 will be enqueued 19858c2ecf20Sopenharmony_ci * subsequently. If urb->actual_length is not DMA-aligned, 19868c2ecf20Sopenharmony_ci * the buffer will then point to an unaligned address, and 19878c2ecf20Sopenharmony_ci * the resulting behavior is undefined. Bail out in that 19888c2ecf20Sopenharmony_ci * situation. 19898c2ecf20Sopenharmony_ci */ 19908c2ecf20Sopenharmony_ci if (qtd->urb->actual_length >= qtd->urb->length) 19918c2ecf20Sopenharmony_ci qtd->error_count = 3; 19928c2ecf20Sopenharmony_ci dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); 19938c2ecf20Sopenharmony_ci dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR); 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci} 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci/* 19988c2ecf20Sopenharmony_ci * Handles a host channel Channel Halted interrupt 19998c2ecf20Sopenharmony_ci * 20008c2ecf20Sopenharmony_ci * In slave mode, this handler is called only when the driver specifically 20018c2ecf20Sopenharmony_ci * requests a halt. This occurs during handling other host channel interrupts 20028c2ecf20Sopenharmony_ci * (e.g. nak, xacterr, stall, nyet, etc.). 20038c2ecf20Sopenharmony_ci * 20048c2ecf20Sopenharmony_ci * In DMA mode, this is the interrupt that occurs when the core has finished 20058c2ecf20Sopenharmony_ci * processing a transfer on a channel. Other host channel interrupts (except 20068c2ecf20Sopenharmony_ci * ahberr) are disabled in DMA mode. 20078c2ecf20Sopenharmony_ci */ 20088c2ecf20Sopenharmony_cistatic void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg, 20098c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, int chnum, 20108c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd) 20118c2ecf20Sopenharmony_ci{ 20128c2ecf20Sopenharmony_ci if (dbg_hc(chan)) 20138c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: Channel Halted--\n", 20148c2ecf20Sopenharmony_ci chnum); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci if (hsotg->params.host_dma) { 20178c2ecf20Sopenharmony_ci dwc2_hc_chhltd_intr_dma(hsotg, chan, chnum, qtd); 20188c2ecf20Sopenharmony_ci } else { 20198c2ecf20Sopenharmony_ci if (!dwc2_halt_status_ok(hsotg, chan, chnum, qtd)) 20208c2ecf20Sopenharmony_ci return; 20218c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, qtd, chan->halt_status); 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci} 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci/* 20268c2ecf20Sopenharmony_ci * Check if the given qtd is still the top of the list (and thus valid). 20278c2ecf20Sopenharmony_ci * 20288c2ecf20Sopenharmony_ci * If dwc2_hcd_qtd_unlink_and_free() has been called since we grabbed 20298c2ecf20Sopenharmony_ci * the qtd from the top of the list, this will return false (otherwise true). 20308c2ecf20Sopenharmony_ci */ 20318c2ecf20Sopenharmony_cistatic bool dwc2_check_qtd_still_ok(struct dwc2_qtd *qtd, struct dwc2_qh *qh) 20328c2ecf20Sopenharmony_ci{ 20338c2ecf20Sopenharmony_ci struct dwc2_qtd *cur_head; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci if (!qh) 20368c2ecf20Sopenharmony_ci return false; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci cur_head = list_first_entry(&qh->qtd_list, struct dwc2_qtd, 20398c2ecf20Sopenharmony_ci qtd_list_entry); 20408c2ecf20Sopenharmony_ci return (cur_head == qtd); 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci/* Handles interrupt for a specific Host Channel */ 20448c2ecf20Sopenharmony_cistatic void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) 20458c2ecf20Sopenharmony_ci{ 20468c2ecf20Sopenharmony_ci struct dwc2_qtd *qtd; 20478c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan; 20488c2ecf20Sopenharmony_ci u32 hcint, hcintraw, hcintmsk; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci chan = hsotg->hc_ptr_array[chnum]; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci hcintraw = dwc2_readl(hsotg, HCINT(chnum)); 20538c2ecf20Sopenharmony_ci hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum)); 20548c2ecf20Sopenharmony_ci hcint = hcintraw & hcintmsk; 20558c2ecf20Sopenharmony_ci dwc2_writel(hsotg, hcint, HCINT(chnum)); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci if (!chan) { 20588c2ecf20Sopenharmony_ci dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n"); 20598c2ecf20Sopenharmony_ci return; 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci if (dbg_hc(chan)) { 20638c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "--Host Channel Interrupt--, Channel %d\n", 20648c2ecf20Sopenharmony_ci chnum); 20658c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 20668c2ecf20Sopenharmony_ci " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", 20678c2ecf20Sopenharmony_ci hcintraw, hcintmsk, hcint); 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci /* 20718c2ecf20Sopenharmony_ci * If we got an interrupt after someone called 20728c2ecf20Sopenharmony_ci * dwc2_hcd_endpoint_disable() we don't want to crash below 20738c2ecf20Sopenharmony_ci */ 20748c2ecf20Sopenharmony_ci if (!chan->qh) { 20758c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "Interrupt on disabled channel\n"); 20768c2ecf20Sopenharmony_ci return; 20778c2ecf20Sopenharmony_ci } 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci chan->hcint = hcintraw; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci /* 20828c2ecf20Sopenharmony_ci * If the channel was halted due to a dequeue, the qtd list might 20838c2ecf20Sopenharmony_ci * be empty or at least the first entry will not be the active qtd. 20848c2ecf20Sopenharmony_ci * In this case, take a shortcut and just release the channel. 20858c2ecf20Sopenharmony_ci */ 20868c2ecf20Sopenharmony_ci if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) { 20878c2ecf20Sopenharmony_ci /* 20888c2ecf20Sopenharmony_ci * If the channel was halted, this should be the only 20898c2ecf20Sopenharmony_ci * interrupt unmasked 20908c2ecf20Sopenharmony_ci */ 20918c2ecf20Sopenharmony_ci WARN_ON(hcint != HCINTMSK_CHHLTD); 20928c2ecf20Sopenharmony_ci if (hsotg->params.dma_desc_enable) 20938c2ecf20Sopenharmony_ci dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, 20948c2ecf20Sopenharmony_ci chan->halt_status); 20958c2ecf20Sopenharmony_ci else 20968c2ecf20Sopenharmony_ci dwc2_release_channel(hsotg, chan, NULL, 20978c2ecf20Sopenharmony_ci chan->halt_status); 20988c2ecf20Sopenharmony_ci return; 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci if (list_empty(&chan->qh->qtd_list)) { 21028c2ecf20Sopenharmony_ci /* 21038c2ecf20Sopenharmony_ci * TODO: Will this ever happen with the 21048c2ecf20Sopenharmony_ci * DWC2_HC_XFER_URB_DEQUEUE handling above? 21058c2ecf20Sopenharmony_ci */ 21068c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, "## no QTD queued for channel %d ##\n", 21078c2ecf20Sopenharmony_ci chnum); 21088c2ecf20Sopenharmony_ci dev_dbg(hsotg->dev, 21098c2ecf20Sopenharmony_ci " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", 21108c2ecf20Sopenharmony_ci chan->hcint, hcintmsk, hcint); 21118c2ecf20Sopenharmony_ci chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS; 21128c2ecf20Sopenharmony_ci disable_hc_int(hsotg, chnum, HCINTMSK_CHHLTD); 21138c2ecf20Sopenharmony_ci chan->hcint = 0; 21148c2ecf20Sopenharmony_ci return; 21158c2ecf20Sopenharmony_ci } 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci qtd = list_first_entry(&chan->qh->qtd_list, struct dwc2_qtd, 21188c2ecf20Sopenharmony_ci qtd_list_entry); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (!hsotg->params.host_dma) { 21218c2ecf20Sopenharmony_ci if ((hcint & HCINTMSK_CHHLTD) && hcint != HCINTMSK_CHHLTD) 21228c2ecf20Sopenharmony_ci hcint &= ~HCINTMSK_CHHLTD; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_XFERCOMPL) { 21268c2ecf20Sopenharmony_ci dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd); 21278c2ecf20Sopenharmony_ci /* 21288c2ecf20Sopenharmony_ci * If NYET occurred at same time as Xfer Complete, the NYET is 21298c2ecf20Sopenharmony_ci * handled by the Xfer Complete interrupt handler. Don't want 21308c2ecf20Sopenharmony_ci * to call the NYET interrupt handler in this case. 21318c2ecf20Sopenharmony_ci */ 21328c2ecf20Sopenharmony_ci hcint &= ~HCINTMSK_NYET; 21338c2ecf20Sopenharmony_ci } 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_CHHLTD) { 21368c2ecf20Sopenharmony_ci dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd); 21378c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21388c2ecf20Sopenharmony_ci goto exit; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_AHBERR) { 21418c2ecf20Sopenharmony_ci dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd); 21428c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21438c2ecf20Sopenharmony_ci goto exit; 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_STALL) { 21468c2ecf20Sopenharmony_ci dwc2_hc_stall_intr(hsotg, chan, chnum, qtd); 21478c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21488c2ecf20Sopenharmony_ci goto exit; 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_NAK) { 21518c2ecf20Sopenharmony_ci dwc2_hc_nak_intr(hsotg, chan, chnum, qtd); 21528c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21538c2ecf20Sopenharmony_ci goto exit; 21548c2ecf20Sopenharmony_ci } 21558c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_ACK) { 21568c2ecf20Sopenharmony_ci dwc2_hc_ack_intr(hsotg, chan, chnum, qtd); 21578c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21588c2ecf20Sopenharmony_ci goto exit; 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_NYET) { 21618c2ecf20Sopenharmony_ci dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd); 21628c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21638c2ecf20Sopenharmony_ci goto exit; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_XACTERR) { 21668c2ecf20Sopenharmony_ci dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); 21678c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21688c2ecf20Sopenharmony_ci goto exit; 21698c2ecf20Sopenharmony_ci } 21708c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_BBLERR) { 21718c2ecf20Sopenharmony_ci dwc2_hc_babble_intr(hsotg, chan, chnum, qtd); 21728c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21738c2ecf20Sopenharmony_ci goto exit; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_FRMOVRUN) { 21768c2ecf20Sopenharmony_ci dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd); 21778c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21788c2ecf20Sopenharmony_ci goto exit; 21798c2ecf20Sopenharmony_ci } 21808c2ecf20Sopenharmony_ci if (hcint & HCINTMSK_DATATGLERR) { 21818c2ecf20Sopenharmony_ci dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd); 21828c2ecf20Sopenharmony_ci if (!dwc2_check_qtd_still_ok(qtd, chan->qh)) 21838c2ecf20Sopenharmony_ci goto exit; 21848c2ecf20Sopenharmony_ci } 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ciexit: 21878c2ecf20Sopenharmony_ci chan->hcint = 0; 21888c2ecf20Sopenharmony_ci} 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci/* 21918c2ecf20Sopenharmony_ci * This interrupt indicates that one or more host channels has a pending 21928c2ecf20Sopenharmony_ci * interrupt. There are multiple conditions that can cause each host channel 21938c2ecf20Sopenharmony_ci * interrupt. This function determines which conditions have occurred for each 21948c2ecf20Sopenharmony_ci * host channel interrupt and handles them appropriately. 21958c2ecf20Sopenharmony_ci */ 21968c2ecf20Sopenharmony_cistatic void dwc2_hc_intr(struct dwc2_hsotg *hsotg) 21978c2ecf20Sopenharmony_ci{ 21988c2ecf20Sopenharmony_ci u32 haint; 21998c2ecf20Sopenharmony_ci int i; 22008c2ecf20Sopenharmony_ci struct dwc2_host_chan *chan, *chan_tmp; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci haint = dwc2_readl(hsotg, HAINT); 22038c2ecf20Sopenharmony_ci if (dbg_perio()) { 22048c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "%s()\n", __func__); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, "HAINT=%08x\n", haint); 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci /* 22108c2ecf20Sopenharmony_ci * According to USB 2.0 spec section 11.18.8, a host must 22118c2ecf20Sopenharmony_ci * issue complete-split transactions in a microframe for a 22128c2ecf20Sopenharmony_ci * set of full-/low-speed endpoints in the same relative 22138c2ecf20Sopenharmony_ci * order as the start-splits were issued in a microframe for. 22148c2ecf20Sopenharmony_ci */ 22158c2ecf20Sopenharmony_ci list_for_each_entry_safe(chan, chan_tmp, &hsotg->split_order, 22168c2ecf20Sopenharmony_ci split_order_list_entry) { 22178c2ecf20Sopenharmony_ci int hc_num = chan->hc_num; 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci if (haint & (1 << hc_num)) { 22208c2ecf20Sopenharmony_ci dwc2_hc_n_intr(hsotg, hc_num); 22218c2ecf20Sopenharmony_ci haint &= ~(1 << hc_num); 22228c2ecf20Sopenharmony_ci } 22238c2ecf20Sopenharmony_ci } 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci for (i = 0; i < hsotg->params.host_channels; i++) { 22268c2ecf20Sopenharmony_ci if (haint & (1 << i)) 22278c2ecf20Sopenharmony_ci dwc2_hc_n_intr(hsotg, i); 22288c2ecf20Sopenharmony_ci } 22298c2ecf20Sopenharmony_ci} 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci/* This function handles interrupts for the HCD */ 22328c2ecf20Sopenharmony_ciirqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg) 22338c2ecf20Sopenharmony_ci{ 22348c2ecf20Sopenharmony_ci u32 gintsts, dbg_gintsts; 22358c2ecf20Sopenharmony_ci irqreturn_t retval = IRQ_NONE; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci if (!dwc2_is_controller_alive(hsotg)) { 22388c2ecf20Sopenharmony_ci dev_warn(hsotg->dev, "Controller is dead\n"); 22398c2ecf20Sopenharmony_ci return retval; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci spin_lock(&hsotg->lock); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci /* Check if HOST Mode */ 22458c2ecf20Sopenharmony_ci if (dwc2_is_host_mode(hsotg)) { 22468c2ecf20Sopenharmony_ci gintsts = dwc2_read_core_intr(hsotg); 22478c2ecf20Sopenharmony_ci if (!gintsts) { 22488c2ecf20Sopenharmony_ci spin_unlock(&hsotg->lock); 22498c2ecf20Sopenharmony_ci return retval; 22508c2ecf20Sopenharmony_ci } 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci retval = IRQ_HANDLED; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci dbg_gintsts = gintsts; 22558c2ecf20Sopenharmony_ci#ifndef DEBUG_SOF 22568c2ecf20Sopenharmony_ci dbg_gintsts &= ~GINTSTS_SOF; 22578c2ecf20Sopenharmony_ci#endif 22588c2ecf20Sopenharmony_ci if (!dbg_perio()) 22598c2ecf20Sopenharmony_ci dbg_gintsts &= ~(GINTSTS_HCHINT | GINTSTS_RXFLVL | 22608c2ecf20Sopenharmony_ci GINTSTS_PTXFEMP); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci /* Only print if there are any non-suppressed interrupts left */ 22638c2ecf20Sopenharmony_ci if (dbg_gintsts) 22648c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 22658c2ecf20Sopenharmony_ci "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n", 22668c2ecf20Sopenharmony_ci gintsts); 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_SOF) 22698c2ecf20Sopenharmony_ci dwc2_sof_intr(hsotg); 22708c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_RXFLVL) 22718c2ecf20Sopenharmony_ci dwc2_rx_fifo_level_intr(hsotg); 22728c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_NPTXFEMP) 22738c2ecf20Sopenharmony_ci dwc2_np_tx_fifo_empty_intr(hsotg); 22748c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_PRTINT) 22758c2ecf20Sopenharmony_ci dwc2_port_intr(hsotg); 22768c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_HCHINT) 22778c2ecf20Sopenharmony_ci dwc2_hc_intr(hsotg); 22788c2ecf20Sopenharmony_ci if (gintsts & GINTSTS_PTXFEMP) 22798c2ecf20Sopenharmony_ci dwc2_perio_tx_fifo_empty_intr(hsotg); 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci if (dbg_gintsts) { 22828c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 22838c2ecf20Sopenharmony_ci "DWC OTG HCD Finished Servicing Interrupts\n"); 22848c2ecf20Sopenharmony_ci dev_vdbg(hsotg->dev, 22858c2ecf20Sopenharmony_ci "DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n", 22868c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GINTSTS), 22878c2ecf20Sopenharmony_ci dwc2_readl(hsotg, GINTMSK)); 22888c2ecf20Sopenharmony_ci } 22898c2ecf20Sopenharmony_ci } 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci spin_unlock(&hsotg->lock); 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci return retval; 22948c2ecf20Sopenharmony_ci} 2295