162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2011 Samsung Electronics Co., Ltd. 462306a36Sopenharmony_ci * http://www.samsung.com 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2008 Openmoko, Inc. 762306a36Sopenharmony_ci * Copyright 2008 Simtec Electronics 862306a36Sopenharmony_ci * Ben Dooks <ben@simtec.co.uk> 962306a36Sopenharmony_ci * http://armlinux.simtec.co.uk/ 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * S3C USB2.0 High-speed / OtG driver 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/spinlock.h> 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2062306a36Sopenharmony_ci#include <linux/mutex.h> 2162306a36Sopenharmony_ci#include <linux/seq_file.h> 2262306a36Sopenharmony_ci#include <linux/delay.h> 2362306a36Sopenharmony_ci#include <linux/io.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/usb/ch9.h> 2762306a36Sopenharmony_ci#include <linux/usb/gadget.h> 2862306a36Sopenharmony_ci#include <linux/usb/phy.h> 2962306a36Sopenharmony_ci#include <linux/usb/composite.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "core.h" 3362306a36Sopenharmony_ci#include "hw.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* conversion functions */ 3662306a36Sopenharmony_cistatic inline struct dwc2_hsotg_req *our_req(struct usb_request *req) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci return container_of(req, struct dwc2_hsotg_req, req); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic inline struct dwc2_hsotg_ep *our_ep(struct usb_ep *ep) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci return container_of(ep, struct dwc2_hsotg_ep, ep); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci return container_of(gadget, struct dwc2_hsotg, gadget); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic inline void dwc2_set_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci dwc2_writel(hsotg, dwc2_readl(hsotg, offset) | val, offset); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic inline void dwc2_clear_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci dwc2_writel(hsotg, dwc2_readl(hsotg, offset) & ~val, offset); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic inline struct dwc2_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg, 6262306a36Sopenharmony_ci u32 ep_index, u32 dir_in) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci if (dir_in) 6562306a36Sopenharmony_ci return hsotg->eps_in[ep_index]; 6662306a36Sopenharmony_ci else 6762306a36Sopenharmony_ci return hsotg->eps_out[ep_index]; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* forward declaration of functions */ 7162306a36Sopenharmony_cistatic void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/** 7462306a36Sopenharmony_ci * using_dma - return the DMA status of the driver. 7562306a36Sopenharmony_ci * @hsotg: The driver state. 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * Return true if we're using DMA. 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * Currently, we have the DMA support code worked into everywhere 8062306a36Sopenharmony_ci * that needs it, but the AMBA DMA implementation in the hardware can 8162306a36Sopenharmony_ci * only DMA from 32bit aligned addresses. This means that gadgets such 8262306a36Sopenharmony_ci * as the CDC Ethernet cannot work as they often pass packets which are 8362306a36Sopenharmony_ci * not 32bit aligned. 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * Unfortunately the choice to use DMA or not is global to the controller 8662306a36Sopenharmony_ci * and seems to be only settable when the controller is being put through 8762306a36Sopenharmony_ci * a core reset. This means we either need to fix the gadgets to take 8862306a36Sopenharmony_ci * account of DMA alignment, or add bounce buffers (yuerk). 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * g_using_dma is set depending on dts flag. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cistatic inline bool using_dma(struct dwc2_hsotg *hsotg) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci return hsotg->params.g_dma; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * using_desc_dma - return the descriptor DMA status of the driver. 9962306a36Sopenharmony_ci * @hsotg: The driver state. 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * Return true if we're using descriptor DMA. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_cistatic inline bool using_desc_dma(struct dwc2_hsotg *hsotg) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return hsotg->params.g_dma_desc; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/** 10962306a36Sopenharmony_ci * dwc2_gadget_incr_frame_num - Increments the targeted frame number. 11062306a36Sopenharmony_ci * @hs_ep: The endpoint 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * This function will also check if the frame number overruns DSTS_SOFFN_LIMIT. 11362306a36Sopenharmony_ci * If an overrun occurs it will wrap the value and set the frame_overrun flag. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cistatic inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 11862306a36Sopenharmony_ci u16 limit = DSTS_SOFFN_LIMIT; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (hsotg->gadget.speed != USB_SPEED_HIGH) 12162306a36Sopenharmony_ci limit >>= 3; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci hs_ep->target_frame += hs_ep->interval; 12462306a36Sopenharmony_ci if (hs_ep->target_frame > limit) { 12562306a36Sopenharmony_ci hs_ep->frame_overrun = true; 12662306a36Sopenharmony_ci hs_ep->target_frame &= limit; 12762306a36Sopenharmony_ci } else { 12862306a36Sopenharmony_ci hs_ep->frame_overrun = false; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/** 13362306a36Sopenharmony_ci * dwc2_gadget_dec_frame_num_by_one - Decrements the targeted frame number 13462306a36Sopenharmony_ci * by one. 13562306a36Sopenharmony_ci * @hs_ep: The endpoint. 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * This function used in service interval based scheduling flow to calculate 13862306a36Sopenharmony_ci * descriptor frame number filed value. For service interval mode frame 13962306a36Sopenharmony_ci * number in descriptor should point to last (u)frame in the interval. 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_cistatic inline void dwc2_gadget_dec_frame_num_by_one(struct dwc2_hsotg_ep *hs_ep) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 14562306a36Sopenharmony_ci u16 limit = DSTS_SOFFN_LIMIT; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (hsotg->gadget.speed != USB_SPEED_HIGH) 14862306a36Sopenharmony_ci limit >>= 3; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (hs_ep->target_frame) 15162306a36Sopenharmony_ci hs_ep->target_frame -= 1; 15262306a36Sopenharmony_ci else 15362306a36Sopenharmony_ci hs_ep->target_frame = limit; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/** 15762306a36Sopenharmony_ci * dwc2_hsotg_en_gsint - enable one or more of the general interrupt 15862306a36Sopenharmony_ci * @hsotg: The device state 15962306a36Sopenharmony_ci * @ints: A bitmask of the interrupts to enable 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_cistatic void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci u32 gsintmsk = dwc2_readl(hsotg, GINTMSK); 16462306a36Sopenharmony_ci u32 new_gsintmsk; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci new_gsintmsk = gsintmsk | ints; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (new_gsintmsk != gsintmsk) { 16962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); 17062306a36Sopenharmony_ci dwc2_writel(hsotg, new_gsintmsk, GINTMSK); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/** 17562306a36Sopenharmony_ci * dwc2_hsotg_disable_gsint - disable one or more of the general interrupt 17662306a36Sopenharmony_ci * @hsotg: The device state 17762306a36Sopenharmony_ci * @ints: A bitmask of the interrupts to enable 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistatic void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci u32 gsintmsk = dwc2_readl(hsotg, GINTMSK); 18262306a36Sopenharmony_ci u32 new_gsintmsk; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci new_gsintmsk = gsintmsk & ~ints; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (new_gsintmsk != gsintmsk) 18762306a36Sopenharmony_ci dwc2_writel(hsotg, new_gsintmsk, GINTMSK); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/** 19162306a36Sopenharmony_ci * dwc2_hsotg_ctrl_epint - enable/disable an endpoint irq 19262306a36Sopenharmony_ci * @hsotg: The device state 19362306a36Sopenharmony_ci * @ep: The endpoint index 19462306a36Sopenharmony_ci * @dir_in: True if direction is in. 19562306a36Sopenharmony_ci * @en: The enable value, true to enable 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * Set or clear the mask for an individual endpoint's interrupt 19862306a36Sopenharmony_ci * request. 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_cistatic void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, 20162306a36Sopenharmony_ci unsigned int ep, unsigned int dir_in, 20262306a36Sopenharmony_ci unsigned int en) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci unsigned long flags; 20562306a36Sopenharmony_ci u32 bit = 1 << ep; 20662306a36Sopenharmony_ci u32 daint; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (!dir_in) 20962306a36Sopenharmony_ci bit <<= 16; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci local_irq_save(flags); 21262306a36Sopenharmony_ci daint = dwc2_readl(hsotg, DAINTMSK); 21362306a36Sopenharmony_ci if (en) 21462306a36Sopenharmony_ci daint |= bit; 21562306a36Sopenharmony_ci else 21662306a36Sopenharmony_ci daint &= ~bit; 21762306a36Sopenharmony_ci dwc2_writel(hsotg, daint, DAINTMSK); 21862306a36Sopenharmony_ci local_irq_restore(flags); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/** 22262306a36Sopenharmony_ci * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode 22362306a36Sopenharmony_ci * 22462306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ciint dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci if (hsotg->hw_params.en_multiple_tx_fifo) 22962306a36Sopenharmony_ci /* In dedicated FIFO mode we need count of IN EPs */ 23062306a36Sopenharmony_ci return hsotg->hw_params.num_dev_in_eps; 23162306a36Sopenharmony_ci else 23262306a36Sopenharmony_ci /* In shared FIFO mode we need count of Periodic IN EPs */ 23362306a36Sopenharmony_ci return hsotg->hw_params.num_dev_perio_in_ep; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/** 23762306a36Sopenharmony_ci * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for 23862306a36Sopenharmony_ci * device mode TX FIFOs 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_ciint dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci int addr; 24562306a36Sopenharmony_ci int tx_addr_max; 24662306a36Sopenharmony_ci u32 np_tx_fifo_size; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci np_tx_fifo_size = min_t(u32, hsotg->hw_params.dev_nperio_tx_fifo_size, 24962306a36Sopenharmony_ci hsotg->params.g_np_tx_fifo_size); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Get Endpoint Info Control block size in DWORDs. */ 25262306a36Sopenharmony_ci tx_addr_max = hsotg->hw_params.total_fifo_size; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci addr = hsotg->params.g_rx_fifo_size + np_tx_fifo_size; 25562306a36Sopenharmony_ci if (tx_addr_max <= addr) 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return tx_addr_max - addr; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/** 26262306a36Sopenharmony_ci * dwc2_gadget_wkup_alert_handler - Handler for WKUP_ALERT interrupt 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_cistatic void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci u32 gintsts2; 27062306a36Sopenharmony_ci u32 gintmsk2; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci gintsts2 = dwc2_readl(hsotg, GINTSTS2); 27362306a36Sopenharmony_ci gintmsk2 = dwc2_readl(hsotg, GINTMSK2); 27462306a36Sopenharmony_ci gintsts2 &= gintmsk2; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) { 27762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__); 27862306a36Sopenharmony_ci dwc2_set_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT); 27962306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/** 28462306a36Sopenharmony_ci * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode 28562306a36Sopenharmony_ci * TX FIFOs 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ciint dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci int tx_fifo_count; 29262306a36Sopenharmony_ci int tx_fifo_depth; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci tx_fifo_depth = dwc2_hsotg_tx_fifo_total_depth(hsotg); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci tx_fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (!tx_fifo_count) 29962306a36Sopenharmony_ci return tx_fifo_depth; 30062306a36Sopenharmony_ci else 30162306a36Sopenharmony_ci return tx_fifo_depth / tx_fifo_count; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci/** 30562306a36Sopenharmony_ci * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs 30662306a36Sopenharmony_ci * @hsotg: The device instance. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_cistatic void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci unsigned int ep; 31162306a36Sopenharmony_ci unsigned int addr; 31262306a36Sopenharmony_ci int timeout; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci u32 val; 31562306a36Sopenharmony_ci u32 *txfsz = hsotg->params.g_tx_fifo_size; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Reset fifo map if not correctly cleared during previous session */ 31862306a36Sopenharmony_ci WARN_ON(hsotg->fifo_map); 31962306a36Sopenharmony_ci hsotg->fifo_map = 0; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* set RX/NPTX FIFO sizes */ 32262306a36Sopenharmony_ci dwc2_writel(hsotg, hsotg->params.g_rx_fifo_size, GRXFSIZ); 32362306a36Sopenharmony_ci dwc2_writel(hsotg, (hsotg->params.g_rx_fifo_size << 32462306a36Sopenharmony_ci FIFOSIZE_STARTADDR_SHIFT) | 32562306a36Sopenharmony_ci (hsotg->params.g_np_tx_fifo_size << FIFOSIZE_DEPTH_SHIFT), 32662306a36Sopenharmony_ci GNPTXFSIZ); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* 32962306a36Sopenharmony_ci * arange all the rest of the TX FIFOs, as some versions of this 33062306a36Sopenharmony_ci * block have overlapping default addresses. This also ensures 33162306a36Sopenharmony_ci * that if the settings have been changed, then they are set to 33262306a36Sopenharmony_ci * known values. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* start at the end of the GNPTXFSIZ, rounded up */ 33662306a36Sopenharmony_ci addr = hsotg->params.g_rx_fifo_size + hsotg->params.g_np_tx_fifo_size; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * Configure fifos sizes from provided configuration and assign 34062306a36Sopenharmony_ci * them to endpoints dynamically according to maxpacket size value of 34162306a36Sopenharmony_ci * given endpoint. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { 34462306a36Sopenharmony_ci if (!txfsz[ep]) 34562306a36Sopenharmony_ci continue; 34662306a36Sopenharmony_ci val = addr; 34762306a36Sopenharmony_ci val |= txfsz[ep] << FIFOSIZE_DEPTH_SHIFT; 34862306a36Sopenharmony_ci WARN_ONCE(addr + txfsz[ep] > hsotg->fifo_mem, 34962306a36Sopenharmony_ci "insufficient fifo memory"); 35062306a36Sopenharmony_ci addr += txfsz[ep]; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci dwc2_writel(hsotg, val, DPTXFSIZN(ep)); 35362306a36Sopenharmony_ci val = dwc2_readl(hsotg, DPTXFSIZN(ep)); 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci dwc2_writel(hsotg, hsotg->hw_params.total_fifo_size | 35762306a36Sopenharmony_ci addr << GDFIFOCFG_EPINFOBASE_SHIFT, 35862306a36Sopenharmony_ci GDFIFOCFG); 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * according to p428 of the design guide, we need to ensure that 36162306a36Sopenharmony_ci * all fifos are flushed before continuing 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci dwc2_writel(hsotg, GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | 36562306a36Sopenharmony_ci GRSTCTL_RXFFLSH, GRSTCTL); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* wait until the fifos are both flushed */ 36862306a36Sopenharmony_ci timeout = 100; 36962306a36Sopenharmony_ci while (1) { 37062306a36Sopenharmony_ci val = dwc2_readl(hsotg, GRSTCTL); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0) 37362306a36Sopenharmony_ci break; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (--timeout == 0) { 37662306a36Sopenharmony_ci dev_err(hsotg->dev, 37762306a36Sopenharmony_ci "%s: timeout flushing fifos (GRSTCTL=%08x)\n", 37862306a36Sopenharmony_ci __func__, val); 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci udelay(1); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci/** 38962306a36Sopenharmony_ci * dwc2_hsotg_ep_alloc_request - allocate USB rerequest structure 39062306a36Sopenharmony_ci * @ep: USB endpoint to allocate request for. 39162306a36Sopenharmony_ci * @flags: Allocation flags 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * Allocate a new USB request structure appropriate for the specified endpoint 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_cistatic struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, 39662306a36Sopenharmony_ci gfp_t flags) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct dwc2_hsotg_req *req; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci req = kzalloc(sizeof(*req), flags); 40162306a36Sopenharmony_ci if (!req) 40262306a36Sopenharmony_ci return NULL; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci INIT_LIST_HEAD(&req->queue); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return &req->req; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/** 41062306a36Sopenharmony_ci * is_ep_periodic - return true if the endpoint is in periodic mode. 41162306a36Sopenharmony_ci * @hs_ep: The endpoint to query. 41262306a36Sopenharmony_ci * 41362306a36Sopenharmony_ci * Returns true if the endpoint is in periodic mode, meaning it is being 41462306a36Sopenharmony_ci * used for an Interrupt or ISO transfer. 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_cistatic inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci return hs_ep->periodic; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci/** 42262306a36Sopenharmony_ci * dwc2_hsotg_unmap_dma - unmap the DMA memory being used for the request 42362306a36Sopenharmony_ci * @hsotg: The device state. 42462306a36Sopenharmony_ci * @hs_ep: The endpoint for the request 42562306a36Sopenharmony_ci * @hs_req: The request being processed. 42662306a36Sopenharmony_ci * 42762306a36Sopenharmony_ci * This is the reverse of dwc2_hsotg_map_dma(), called for the completion 42862306a36Sopenharmony_ci * of a request to ensure the buffer is ready for access by the caller. 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_cistatic void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, 43162306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 43262306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct usb_request *req = &hs_req->req; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->map_dir); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* 44062306a36Sopenharmony_ci * dwc2_gadget_alloc_ctrl_desc_chains - allocate DMA descriptor chains 44162306a36Sopenharmony_ci * for Control endpoint 44262306a36Sopenharmony_ci * @hsotg: The device state. 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * This function will allocate 4 descriptor chains for EP 0: 2 for 44562306a36Sopenharmony_ci * Setup stage, per one for IN and OUT data/status transactions. 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_cistatic int dwc2_gadget_alloc_ctrl_desc_chains(struct dwc2_hsotg *hsotg) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci hsotg->setup_desc[0] = 45062306a36Sopenharmony_ci dmam_alloc_coherent(hsotg->dev, 45162306a36Sopenharmony_ci sizeof(struct dwc2_dma_desc), 45262306a36Sopenharmony_ci &hsotg->setup_desc_dma[0], 45362306a36Sopenharmony_ci GFP_KERNEL); 45462306a36Sopenharmony_ci if (!hsotg->setup_desc[0]) 45562306a36Sopenharmony_ci goto fail; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci hsotg->setup_desc[1] = 45862306a36Sopenharmony_ci dmam_alloc_coherent(hsotg->dev, 45962306a36Sopenharmony_ci sizeof(struct dwc2_dma_desc), 46062306a36Sopenharmony_ci &hsotg->setup_desc_dma[1], 46162306a36Sopenharmony_ci GFP_KERNEL); 46262306a36Sopenharmony_ci if (!hsotg->setup_desc[1]) 46362306a36Sopenharmony_ci goto fail; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci hsotg->ctrl_in_desc = 46662306a36Sopenharmony_ci dmam_alloc_coherent(hsotg->dev, 46762306a36Sopenharmony_ci sizeof(struct dwc2_dma_desc), 46862306a36Sopenharmony_ci &hsotg->ctrl_in_desc_dma, 46962306a36Sopenharmony_ci GFP_KERNEL); 47062306a36Sopenharmony_ci if (!hsotg->ctrl_in_desc) 47162306a36Sopenharmony_ci goto fail; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci hsotg->ctrl_out_desc = 47462306a36Sopenharmony_ci dmam_alloc_coherent(hsotg->dev, 47562306a36Sopenharmony_ci sizeof(struct dwc2_dma_desc), 47662306a36Sopenharmony_ci &hsotg->ctrl_out_desc_dma, 47762306a36Sopenharmony_ci GFP_KERNEL); 47862306a36Sopenharmony_ci if (!hsotg->ctrl_out_desc) 47962306a36Sopenharmony_ci goto fail; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cifail: 48462306a36Sopenharmony_ci return -ENOMEM; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci/** 48862306a36Sopenharmony_ci * dwc2_hsotg_write_fifo - write packet Data to the TxFIFO 48962306a36Sopenharmony_ci * @hsotg: The controller state. 49062306a36Sopenharmony_ci * @hs_ep: The endpoint we're going to write for. 49162306a36Sopenharmony_ci * @hs_req: The request to write data for. 49262306a36Sopenharmony_ci * 49362306a36Sopenharmony_ci * This is called when the TxFIFO has some space in it to hold a new 49462306a36Sopenharmony_ci * transmission and we have something to give it. The actual setup of 49562306a36Sopenharmony_ci * the data size is done elsewhere, so all we have to do is to actually 49662306a36Sopenharmony_ci * write the data. 49762306a36Sopenharmony_ci * 49862306a36Sopenharmony_ci * The return value is zero if there is more space (or nothing was done) 49962306a36Sopenharmony_ci * otherwise -ENOSPC is returned if the FIFO space was used up. 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci * This routine is only needed for PIO 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_cistatic int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, 50462306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 50562306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci bool periodic = is_ep_periodic(hs_ep); 50862306a36Sopenharmony_ci u32 gnptxsts = dwc2_readl(hsotg, GNPTXSTS); 50962306a36Sopenharmony_ci int buf_pos = hs_req->req.actual; 51062306a36Sopenharmony_ci int to_write = hs_ep->size_loaded; 51162306a36Sopenharmony_ci void *data; 51262306a36Sopenharmony_ci int can_write; 51362306a36Sopenharmony_ci int pkt_round; 51462306a36Sopenharmony_ci int max_transfer; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci to_write -= (buf_pos - hs_ep->last_load); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* if there's nothing to write, get out early */ 51962306a36Sopenharmony_ci if (to_write == 0) 52062306a36Sopenharmony_ci return 0; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (periodic && !hsotg->dedicated_fifos) { 52362306a36Sopenharmony_ci u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index)); 52462306a36Sopenharmony_ci int size_left; 52562306a36Sopenharmony_ci int size_done; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* 52862306a36Sopenharmony_ci * work out how much data was loaded so we can calculate 52962306a36Sopenharmony_ci * how much data is left in the fifo. 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* 53562306a36Sopenharmony_ci * if shared fifo, we cannot write anything until the 53662306a36Sopenharmony_ci * previous data has been completely sent. 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci if (hs_ep->fifo_load != 0) { 53962306a36Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 54062306a36Sopenharmony_ci return -ENOSPC; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", 54462306a36Sopenharmony_ci __func__, size_left, 54562306a36Sopenharmony_ci hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* how much of the data has moved */ 54862306a36Sopenharmony_ci size_done = hs_ep->size_loaded - size_left; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* how much data is left in the fifo */ 55162306a36Sopenharmony_ci can_write = hs_ep->fifo_load - size_done; 55262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", 55362306a36Sopenharmony_ci __func__, can_write); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci can_write = hs_ep->fifo_size - can_write; 55662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", 55762306a36Sopenharmony_ci __func__, can_write); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (can_write <= 0) { 56062306a36Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP); 56162306a36Sopenharmony_ci return -ENOSPC; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { 56462306a36Sopenharmony_ci can_write = dwc2_readl(hsotg, 56562306a36Sopenharmony_ci DTXFSTS(hs_ep->fifo_index)); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci can_write &= 0xffff; 56862306a36Sopenharmony_ci can_write *= 4; 56962306a36Sopenharmony_ci } else { 57062306a36Sopenharmony_ci if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) { 57162306a36Sopenharmony_ci dev_dbg(hsotg->dev, 57262306a36Sopenharmony_ci "%s: no queue slots available (0x%08x)\n", 57362306a36Sopenharmony_ci __func__, gnptxsts); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP); 57662306a36Sopenharmony_ci return -ENOSPC; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts); 58062306a36Sopenharmony_ci can_write *= 4; /* fifo size is in 32bit quantities. */ 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", 58662306a36Sopenharmony_ci __func__, gnptxsts, can_write, to_write, max_transfer); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * limit to 512 bytes of data, it seems at least on the non-periodic 59062306a36Sopenharmony_ci * FIFO, requests of >512 cause the endpoint to get stuck with a 59162306a36Sopenharmony_ci * fragment of the end of the transfer in it. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci if (can_write > 512 && !periodic) 59462306a36Sopenharmony_ci can_write = 512; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* 59762306a36Sopenharmony_ci * limit the write to one max-packet size worth of data, but allow 59862306a36Sopenharmony_ci * the transfer to return that it did not run out of fifo space 59962306a36Sopenharmony_ci * doing it. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ci if (to_write > max_transfer) { 60262306a36Sopenharmony_ci to_write = max_transfer; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* it's needed only when we do not use dedicated fifos */ 60562306a36Sopenharmony_ci if (!hsotg->dedicated_fifos) 60662306a36Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, 60762306a36Sopenharmony_ci periodic ? GINTSTS_PTXFEMP : 60862306a36Sopenharmony_ci GINTSTS_NPTXFEMP); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* see if we can write data */ 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (to_write > can_write) { 61462306a36Sopenharmony_ci to_write = can_write; 61562306a36Sopenharmony_ci pkt_round = to_write % max_transfer; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* 61862306a36Sopenharmony_ci * Round the write down to an 61962306a36Sopenharmony_ci * exact number of packets. 62062306a36Sopenharmony_ci * 62162306a36Sopenharmony_ci * Note, we do not currently check to see if we can ever 62262306a36Sopenharmony_ci * write a full packet or not to the FIFO. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (pkt_round) 62662306a36Sopenharmony_ci to_write -= pkt_round; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* 62962306a36Sopenharmony_ci * enable correct FIFO interrupt to alert us when there 63062306a36Sopenharmony_ci * is more room left. 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* it's needed only when we do not use dedicated fifos */ 63462306a36Sopenharmony_ci if (!hsotg->dedicated_fifos) 63562306a36Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, 63662306a36Sopenharmony_ci periodic ? GINTSTS_PTXFEMP : 63762306a36Sopenharmony_ci GINTSTS_NPTXFEMP); 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", 64162306a36Sopenharmony_ci to_write, hs_req->req.length, can_write, buf_pos); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (to_write <= 0) 64462306a36Sopenharmony_ci return -ENOSPC; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci hs_req->req.actual = buf_pos + to_write; 64762306a36Sopenharmony_ci hs_ep->total_data += to_write; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (periodic) 65062306a36Sopenharmony_ci hs_ep->fifo_load += to_write; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci to_write = DIV_ROUND_UP(to_write, 4); 65362306a36Sopenharmony_ci data = hs_req->req.buf + buf_pos; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci dwc2_writel_rep(hsotg, EPFIFO(hs_ep->index), data, to_write); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return (to_write >= can_write) ? -ENOSPC : 0; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci/** 66162306a36Sopenharmony_ci * get_ep_limit - get the maximum data legnth for this endpoint 66262306a36Sopenharmony_ci * @hs_ep: The endpoint 66362306a36Sopenharmony_ci * 66462306a36Sopenharmony_ci * Return the maximum data that can be queued in one go on a given endpoint 66562306a36Sopenharmony_ci * so that transfers that are too long can be split. 66662306a36Sopenharmony_ci */ 66762306a36Sopenharmony_cistatic unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci int index = hs_ep->index; 67062306a36Sopenharmony_ci unsigned int maxsize; 67162306a36Sopenharmony_ci unsigned int maxpkt; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (index != 0) { 67462306a36Sopenharmony_ci maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; 67562306a36Sopenharmony_ci maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; 67662306a36Sopenharmony_ci } else { 67762306a36Sopenharmony_ci maxsize = 64 + 64; 67862306a36Sopenharmony_ci if (hs_ep->dir_in) 67962306a36Sopenharmony_ci maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; 68062306a36Sopenharmony_ci else 68162306a36Sopenharmony_ci maxpkt = 2; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* we made the constant loading easier above by using +1 */ 68562306a36Sopenharmony_ci maxpkt--; 68662306a36Sopenharmony_ci maxsize--; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* 68962306a36Sopenharmony_ci * constrain by packet count if maxpkts*pktsize is greater 69062306a36Sopenharmony_ci * than the length register size. 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) 69462306a36Sopenharmony_ci maxsize = maxpkt * hs_ep->ep.maxpacket; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return maxsize; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci/** 70062306a36Sopenharmony_ci * dwc2_hsotg_read_frameno - read current frame number 70162306a36Sopenharmony_ci * @hsotg: The device instance 70262306a36Sopenharmony_ci * 70362306a36Sopenharmony_ci * Return the current frame number 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_cistatic u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci u32 dsts; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci dsts = dwc2_readl(hsotg, DSTS); 71062306a36Sopenharmony_ci dsts &= DSTS_SOFFN_MASK; 71162306a36Sopenharmony_ci dsts >>= DSTS_SOFFN_SHIFT; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return dsts; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci/** 71762306a36Sopenharmony_ci * dwc2_gadget_get_chain_limit - get the maximum data payload value of the 71862306a36Sopenharmony_ci * DMA descriptor chain prepared for specific endpoint 71962306a36Sopenharmony_ci * @hs_ep: The endpoint 72062306a36Sopenharmony_ci * 72162306a36Sopenharmony_ci * Return the maximum data that can be queued in one go on a given endpoint 72262306a36Sopenharmony_ci * depending on its descriptor chain capacity so that transfers that 72362306a36Sopenharmony_ci * are too long can be split. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_cistatic unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc; 72862306a36Sopenharmony_ci int is_isoc = hs_ep->isochronous; 72962306a36Sopenharmony_ci unsigned int maxsize; 73062306a36Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 73162306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (is_isoc) 73462306a36Sopenharmony_ci maxsize = (hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT : 73562306a36Sopenharmony_ci DEV_DMA_ISOC_RX_NBYTES_LIMIT) * 73662306a36Sopenharmony_ci MAX_DMA_DESC_NUM_HS_ISOC; 73762306a36Sopenharmony_ci else 73862306a36Sopenharmony_ci maxsize = DEV_DMA_NBYTES_LIMIT * MAX_DMA_DESC_NUM_GENERIC; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* Interrupt OUT EP with mps not multiple of 4 */ 74162306a36Sopenharmony_ci if (hs_ep->index) 74262306a36Sopenharmony_ci if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4)) 74362306a36Sopenharmony_ci maxsize = mps * MAX_DMA_DESC_NUM_GENERIC; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci return maxsize; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci/* 74962306a36Sopenharmony_ci * dwc2_gadget_get_desc_params - get DMA descriptor parameters. 75062306a36Sopenharmony_ci * @hs_ep: The endpoint 75162306a36Sopenharmony_ci * @mask: RX/TX bytes mask to be defined 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * Returns maximum data payload for one descriptor after analyzing endpoint 75462306a36Sopenharmony_ci * characteristics. 75562306a36Sopenharmony_ci * DMA descriptor transfer bytes limit depends on EP type: 75662306a36Sopenharmony_ci * Control out - MPS, 75762306a36Sopenharmony_ci * Isochronous - descriptor rx/tx bytes bitfield limit, 75862306a36Sopenharmony_ci * Control In/Bulk/Interrupt - multiple of mps. This will allow to not 75962306a36Sopenharmony_ci * have concatenations from various descriptors within one packet. 76062306a36Sopenharmony_ci * Interrupt OUT - if mps not multiple of 4 then a single packet corresponds 76162306a36Sopenharmony_ci * to a single descriptor. 76262306a36Sopenharmony_ci * 76362306a36Sopenharmony_ci * Selects corresponding mask for RX/TX bytes as well. 76462306a36Sopenharmony_ci */ 76562306a36Sopenharmony_cistatic u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc; 76862306a36Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 76962306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 77062306a36Sopenharmony_ci u32 desc_size = 0; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (!hs_ep->index && !dir_in) { 77362306a36Sopenharmony_ci desc_size = mps; 77462306a36Sopenharmony_ci *mask = DEV_DMA_NBYTES_MASK; 77562306a36Sopenharmony_ci } else if (hs_ep->isochronous) { 77662306a36Sopenharmony_ci if (dir_in) { 77762306a36Sopenharmony_ci desc_size = DEV_DMA_ISOC_TX_NBYTES_LIMIT; 77862306a36Sopenharmony_ci *mask = DEV_DMA_ISOC_TX_NBYTES_MASK; 77962306a36Sopenharmony_ci } else { 78062306a36Sopenharmony_ci desc_size = DEV_DMA_ISOC_RX_NBYTES_LIMIT; 78162306a36Sopenharmony_ci *mask = DEV_DMA_ISOC_RX_NBYTES_MASK; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci } else { 78462306a36Sopenharmony_ci desc_size = DEV_DMA_NBYTES_LIMIT; 78562306a36Sopenharmony_ci *mask = DEV_DMA_NBYTES_MASK; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci /* Round down desc_size to be mps multiple */ 78862306a36Sopenharmony_ci desc_size -= desc_size % mps; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci /* Interrupt OUT EP with mps not multiple of 4 */ 79262306a36Sopenharmony_ci if (hs_ep->index) 79362306a36Sopenharmony_ci if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4)) { 79462306a36Sopenharmony_ci desc_size = mps; 79562306a36Sopenharmony_ci *mask = DEV_DMA_NBYTES_MASK; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci return desc_size; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep, 80262306a36Sopenharmony_ci struct dwc2_dma_desc **desc, 80362306a36Sopenharmony_ci dma_addr_t dma_buff, 80462306a36Sopenharmony_ci unsigned int len, 80562306a36Sopenharmony_ci bool true_last) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 80862306a36Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 80962306a36Sopenharmony_ci u32 maxsize = 0; 81062306a36Sopenharmony_ci u32 offset = 0; 81162306a36Sopenharmony_ci u32 mask = 0; 81262306a36Sopenharmony_ci int i; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci hs_ep->desc_count = (len / maxsize) + 81762306a36Sopenharmony_ci ((len % maxsize) ? 1 : 0); 81862306a36Sopenharmony_ci if (len == 0) 81962306a36Sopenharmony_ci hs_ep->desc_count = 1; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci for (i = 0; i < hs_ep->desc_count; ++i) { 82262306a36Sopenharmony_ci (*desc)->status = 0; 82362306a36Sopenharmony_ci (*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY 82462306a36Sopenharmony_ci << DEV_DMA_BUFF_STS_SHIFT); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (len > maxsize) { 82762306a36Sopenharmony_ci if (!hs_ep->index && !dir_in) 82862306a36Sopenharmony_ci (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci (*desc)->status |= 83162306a36Sopenharmony_ci maxsize << DEV_DMA_NBYTES_SHIFT & mask; 83262306a36Sopenharmony_ci (*desc)->buf = dma_buff + offset; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci len -= maxsize; 83562306a36Sopenharmony_ci offset += maxsize; 83662306a36Sopenharmony_ci } else { 83762306a36Sopenharmony_ci if (true_last) 83862306a36Sopenharmony_ci (*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (dir_in) 84162306a36Sopenharmony_ci (*desc)->status |= (len % mps) ? DEV_DMA_SHORT : 84262306a36Sopenharmony_ci ((hs_ep->send_zlp && true_last) ? 84362306a36Sopenharmony_ci DEV_DMA_SHORT : 0); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci (*desc)->status |= 84662306a36Sopenharmony_ci len << DEV_DMA_NBYTES_SHIFT & mask; 84762306a36Sopenharmony_ci (*desc)->buf = dma_buff + offset; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci (*desc)->status &= ~DEV_DMA_BUFF_STS_MASK; 85162306a36Sopenharmony_ci (*desc)->status |= (DEV_DMA_BUFF_STS_HREADY 85262306a36Sopenharmony_ci << DEV_DMA_BUFF_STS_SHIFT); 85362306a36Sopenharmony_ci (*desc)++; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci/* 85862306a36Sopenharmony_ci * dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain. 85962306a36Sopenharmony_ci * @hs_ep: The endpoint 86062306a36Sopenharmony_ci * @ureq: Request to transfer 86162306a36Sopenharmony_ci * @offset: offset in bytes 86262306a36Sopenharmony_ci * @len: Length of the transfer 86362306a36Sopenharmony_ci * 86462306a36Sopenharmony_ci * This function will iterate over descriptor chain and fill its entries 86562306a36Sopenharmony_ci * with corresponding information based on transfer data. 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_cistatic void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep, 86862306a36Sopenharmony_ci dma_addr_t dma_buff, 86962306a36Sopenharmony_ci unsigned int len) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct usb_request *ureq = NULL; 87262306a36Sopenharmony_ci struct dwc2_dma_desc *desc = hs_ep->desc_list; 87362306a36Sopenharmony_ci struct scatterlist *sg; 87462306a36Sopenharmony_ci int i; 87562306a36Sopenharmony_ci u8 desc_count = 0; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (hs_ep->req) 87862306a36Sopenharmony_ci ureq = &hs_ep->req->req; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* non-DMA sg buffer */ 88162306a36Sopenharmony_ci if (!ureq || !ureq->num_sgs) { 88262306a36Sopenharmony_ci dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, 88362306a36Sopenharmony_ci dma_buff, len, true); 88462306a36Sopenharmony_ci return; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* DMA sg buffer */ 88862306a36Sopenharmony_ci for_each_sg(ureq->sg, sg, ureq->num_sgs, i) { 88962306a36Sopenharmony_ci dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc, 89062306a36Sopenharmony_ci sg_dma_address(sg) + sg->offset, sg_dma_len(sg), 89162306a36Sopenharmony_ci sg_is_last(sg)); 89262306a36Sopenharmony_ci desc_count += hs_ep->desc_count; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci hs_ep->desc_count = desc_count; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci/* 89962306a36Sopenharmony_ci * dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain. 90062306a36Sopenharmony_ci * @hs_ep: The isochronous endpoint. 90162306a36Sopenharmony_ci * @dma_buff: usb requests dma buffer. 90262306a36Sopenharmony_ci * @len: usb request transfer length. 90362306a36Sopenharmony_ci * 90462306a36Sopenharmony_ci * Fills next free descriptor with the data of the arrived usb request, 90562306a36Sopenharmony_ci * frame info, sets Last and IOC bits increments next_desc. If filled 90662306a36Sopenharmony_ci * descriptor is not the first one, removes L bit from the previous descriptor 90762306a36Sopenharmony_ci * status. 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_cistatic int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, 91062306a36Sopenharmony_ci dma_addr_t dma_buff, unsigned int len) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci struct dwc2_dma_desc *desc; 91362306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 91462306a36Sopenharmony_ci u32 index; 91562306a36Sopenharmony_ci u32 mask = 0; 91662306a36Sopenharmony_ci u8 pid = 0; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci dwc2_gadget_get_desc_params(hs_ep, &mask); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci index = hs_ep->next_desc; 92162306a36Sopenharmony_ci desc = &hs_ep->desc_list[index]; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* Check if descriptor chain full */ 92462306a36Sopenharmony_ci if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) == 92562306a36Sopenharmony_ci DEV_DMA_BUFF_STS_HREADY) { 92662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__); 92762306a36Sopenharmony_ci return 1; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* Clear L bit of previous desc if more than one entries in the chain */ 93162306a36Sopenharmony_ci if (hs_ep->next_desc) 93262306a36Sopenharmony_ci hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n", 93562306a36Sopenharmony_ci __func__, hs_ep->index, hs_ep->dir_in ? "in" : "out", index); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci desc->status = 0; 93862306a36Sopenharmony_ci desc->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci desc->buf = dma_buff; 94162306a36Sopenharmony_ci desc->status |= (DEV_DMA_L | DEV_DMA_IOC | 94262306a36Sopenharmony_ci ((len << DEV_DMA_NBYTES_SHIFT) & mask)); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (hs_ep->dir_in) { 94562306a36Sopenharmony_ci if (len) 94662306a36Sopenharmony_ci pid = DIV_ROUND_UP(len, hs_ep->ep.maxpacket); 94762306a36Sopenharmony_ci else 94862306a36Sopenharmony_ci pid = 1; 94962306a36Sopenharmony_ci desc->status |= ((pid << DEV_DMA_ISOC_PID_SHIFT) & 95062306a36Sopenharmony_ci DEV_DMA_ISOC_PID_MASK) | 95162306a36Sopenharmony_ci ((len % hs_ep->ep.maxpacket) ? 95262306a36Sopenharmony_ci DEV_DMA_SHORT : 0) | 95362306a36Sopenharmony_ci ((hs_ep->target_frame << 95462306a36Sopenharmony_ci DEV_DMA_ISOC_FRNUM_SHIFT) & 95562306a36Sopenharmony_ci DEV_DMA_ISOC_FRNUM_MASK); 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci desc->status &= ~DEV_DMA_BUFF_STS_MASK; 95962306a36Sopenharmony_ci desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci /* Increment frame number by interval for IN */ 96262306a36Sopenharmony_ci if (hs_ep->dir_in) 96362306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* Update index of last configured entry in the chain */ 96662306a36Sopenharmony_ci hs_ep->next_desc++; 96762306a36Sopenharmony_ci if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_HS_ISOC) 96862306a36Sopenharmony_ci hs_ep->next_desc = 0; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci return 0; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci/* 97462306a36Sopenharmony_ci * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA 97562306a36Sopenharmony_ci * @hs_ep: The isochronous endpoint. 97662306a36Sopenharmony_ci * 97762306a36Sopenharmony_ci * Prepare descriptor chain for isochronous endpoints. Afterwards 97862306a36Sopenharmony_ci * write DMA address to HW and enable the endpoint. 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_cistatic void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 98362306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req, *treq; 98462306a36Sopenharmony_ci int index = hs_ep->index; 98562306a36Sopenharmony_ci int ret; 98662306a36Sopenharmony_ci int i; 98762306a36Sopenharmony_ci u32 dma_reg; 98862306a36Sopenharmony_ci u32 depctl; 98962306a36Sopenharmony_ci u32 ctrl; 99062306a36Sopenharmony_ci struct dwc2_dma_desc *desc; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (list_empty(&hs_ep->queue)) { 99362306a36Sopenharmony_ci hs_ep->target_frame = TARGET_FRAME_INITIAL; 99462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__); 99562306a36Sopenharmony_ci return; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* Initialize descriptor chain by Host Busy status */ 99962306a36Sopenharmony_ci for (i = 0; i < MAX_DMA_DESC_NUM_HS_ISOC; i++) { 100062306a36Sopenharmony_ci desc = &hs_ep->desc_list[i]; 100162306a36Sopenharmony_ci desc->status = 0; 100262306a36Sopenharmony_ci desc->status |= (DEV_DMA_BUFF_STS_HBUSY 100362306a36Sopenharmony_ci << DEV_DMA_BUFF_STS_SHIFT); 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci hs_ep->next_desc = 0; 100762306a36Sopenharmony_ci list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) { 100862306a36Sopenharmony_ci dma_addr_t dma_addr = hs_req->req.dma; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (hs_req->req.num_sgs) { 101162306a36Sopenharmony_ci WARN_ON(hs_req->req.num_sgs > 1); 101262306a36Sopenharmony_ci dma_addr = sg_dma_address(hs_req->req.sg); 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, 101562306a36Sopenharmony_ci hs_req->req.length); 101662306a36Sopenharmony_ci if (ret) 101762306a36Sopenharmony_ci break; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci hs_ep->compl_desc = 0; 102162306a36Sopenharmony_ci depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 102262306a36Sopenharmony_ci dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* write descriptor chain address to control register */ 102562306a36Sopenharmony_ci dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci ctrl = dwc2_readl(hsotg, depctl); 102862306a36Sopenharmony_ci ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK; 102962306a36Sopenharmony_ci dwc2_writel(hsotg, ctrl, depctl); 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep); 103362306a36Sopenharmony_cistatic void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 103462306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 103562306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req, 103662306a36Sopenharmony_ci int result); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci/** 103962306a36Sopenharmony_ci * dwc2_hsotg_start_req - start a USB request from an endpoint's queue 104062306a36Sopenharmony_ci * @hsotg: The controller state. 104162306a36Sopenharmony_ci * @hs_ep: The endpoint to process a request for 104262306a36Sopenharmony_ci * @hs_req: The request to start. 104362306a36Sopenharmony_ci * @continuing: True if we are doing more for the current request. 104462306a36Sopenharmony_ci * 104562306a36Sopenharmony_ci * Start the given request running by setting the endpoint registers 104662306a36Sopenharmony_ci * appropriately, and writing any data to the FIFOs. 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_cistatic void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, 104962306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 105062306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req, 105162306a36Sopenharmony_ci bool continuing) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci struct usb_request *ureq = &hs_req->req; 105462306a36Sopenharmony_ci int index = hs_ep->index; 105562306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 105662306a36Sopenharmony_ci u32 epctrl_reg; 105762306a36Sopenharmony_ci u32 epsize_reg; 105862306a36Sopenharmony_ci u32 epsize; 105962306a36Sopenharmony_ci u32 ctrl; 106062306a36Sopenharmony_ci unsigned int length; 106162306a36Sopenharmony_ci unsigned int packets; 106262306a36Sopenharmony_ci unsigned int maxreq; 106362306a36Sopenharmony_ci unsigned int dma_reg; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (index != 0) { 106662306a36Sopenharmony_ci if (hs_ep->req && !continuing) { 106762306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: active request\n", __func__); 106862306a36Sopenharmony_ci WARN_ON(1); 106962306a36Sopenharmony_ci return; 107062306a36Sopenharmony_ci } else if (hs_ep->req != hs_req && continuing) { 107162306a36Sopenharmony_ci dev_err(hsotg->dev, 107262306a36Sopenharmony_ci "%s: continue different req\n", __func__); 107362306a36Sopenharmony_ci WARN_ON(1); 107462306a36Sopenharmony_ci return; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); 107962306a36Sopenharmony_ci epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 108062306a36Sopenharmony_ci epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", 108362306a36Sopenharmony_ci __func__, dwc2_readl(hsotg, epctrl_reg), index, 108462306a36Sopenharmony_ci hs_ep->dir_in ? "in" : "out"); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci /* If endpoint is stalled, we will restart request later */ 108762306a36Sopenharmony_ci ctrl = dwc2_readl(hsotg, epctrl_reg); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (index && ctrl & DXEPCTL_STALL) { 109062306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); 109162306a36Sopenharmony_ci return; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci length = ureq->length - ureq->actual; 109562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", 109662306a36Sopenharmony_ci ureq->length, ureq->actual); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (!using_desc_dma(hsotg)) 109962306a36Sopenharmony_ci maxreq = get_ep_limit(hs_ep); 110062306a36Sopenharmony_ci else 110162306a36Sopenharmony_ci maxreq = dwc2_gadget_get_chain_limit(hs_ep); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (length > maxreq) { 110462306a36Sopenharmony_ci int round = maxreq % hs_ep->ep.maxpacket; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", 110762306a36Sopenharmony_ci __func__, length, maxreq, round); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* round down to multiple of packets */ 111062306a36Sopenharmony_ci if (round) 111162306a36Sopenharmony_ci maxreq -= round; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci length = maxreq; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci if (length) 111762306a36Sopenharmony_ci packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); 111862306a36Sopenharmony_ci else 111962306a36Sopenharmony_ci packets = 1; /* send one packet if length is zero. */ 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (dir_in && index != 0) 112262306a36Sopenharmony_ci if (hs_ep->isochronous) 112362306a36Sopenharmony_ci epsize = DXEPTSIZ_MC(packets); 112462306a36Sopenharmony_ci else 112562306a36Sopenharmony_ci epsize = DXEPTSIZ_MC(1); 112662306a36Sopenharmony_ci else 112762306a36Sopenharmony_ci epsize = 0; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci /* 113062306a36Sopenharmony_ci * zero length packet should be programmed on its own and should not 113162306a36Sopenharmony_ci * be counted in DIEPTSIZ.PktCnt with other packets. 113262306a36Sopenharmony_ci */ 113362306a36Sopenharmony_ci if (dir_in && ureq->zero && !continuing) { 113462306a36Sopenharmony_ci /* Test if zlp is actually required. */ 113562306a36Sopenharmony_ci if ((ureq->length >= hs_ep->ep.maxpacket) && 113662306a36Sopenharmony_ci !(ureq->length % hs_ep->ep.maxpacket)) 113762306a36Sopenharmony_ci hs_ep->send_zlp = 1; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci epsize |= DXEPTSIZ_PKTCNT(packets); 114162306a36Sopenharmony_ci epsize |= DXEPTSIZ_XFERSIZE(length); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", 114462306a36Sopenharmony_ci __func__, packets, length, ureq->length, epsize, epsize_reg); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci /* store the request as the current one we're doing */ 114762306a36Sopenharmony_ci hs_ep->req = hs_req; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (using_desc_dma(hsotg)) { 115062306a36Sopenharmony_ci u32 offset = 0; 115162306a36Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci /* Adjust length: EP0 - MPS, other OUT EPs - multiple of MPS */ 115462306a36Sopenharmony_ci if (!dir_in) { 115562306a36Sopenharmony_ci if (!index) 115662306a36Sopenharmony_ci length = mps; 115762306a36Sopenharmony_ci else if (length % mps) 115862306a36Sopenharmony_ci length += (mps - (length % mps)); 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (continuing) 116262306a36Sopenharmony_ci offset = ureq->actual; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* Fill DDMA chain entries */ 116562306a36Sopenharmony_ci dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset, 116662306a36Sopenharmony_ci length); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci /* write descriptor chain address to control register */ 116962306a36Sopenharmony_ci dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %08x pad => 0x%08x\n", 117262306a36Sopenharmony_ci __func__, (u32)hs_ep->desc_list_dma, dma_reg); 117362306a36Sopenharmony_ci } else { 117462306a36Sopenharmony_ci /* write size / packets */ 117562306a36Sopenharmony_ci dwc2_writel(hsotg, epsize, epsize_reg); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (using_dma(hsotg) && !continuing && (length != 0)) { 117862306a36Sopenharmony_ci /* 117962306a36Sopenharmony_ci * write DMA address to control register, buffer 118062306a36Sopenharmony_ci * already synced by dwc2_hsotg_ep_queue(). 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci dwc2_writel(hsotg, ureq->dma, dma_reg); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", 118662306a36Sopenharmony_ci __func__, &ureq->dma, dma_reg); 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (hs_ep->isochronous) { 119162306a36Sopenharmony_ci if (!dwc2_gadget_target_frame_elapsed(hs_ep)) { 119262306a36Sopenharmony_ci if (hs_ep->interval == 1) { 119362306a36Sopenharmony_ci if (hs_ep->target_frame & 0x1) 119462306a36Sopenharmony_ci ctrl |= DXEPCTL_SETODDFR; 119562306a36Sopenharmony_ci else 119662306a36Sopenharmony_ci ctrl |= DXEPCTL_SETEVENFR; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci ctrl |= DXEPCTL_CNAK; 119962306a36Sopenharmony_ci } else { 120062306a36Sopenharmony_ci hs_req->req.frame_number = hs_ep->target_frame; 120162306a36Sopenharmony_ci hs_req->req.actual = 0; 120262306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA); 120362306a36Sopenharmony_ci return; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci /* For Setup request do not clear NAK */ 121262306a36Sopenharmony_ci if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP)) 121362306a36Sopenharmony_ci ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 121662306a36Sopenharmony_ci dwc2_writel(hsotg, ctrl, epctrl_reg); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci /* 121962306a36Sopenharmony_ci * set these, it seems that DMA support increments past the end 122062306a36Sopenharmony_ci * of the packet buffer so we need to calculate the length from 122162306a36Sopenharmony_ci * this information. 122262306a36Sopenharmony_ci */ 122362306a36Sopenharmony_ci hs_ep->size_loaded = length; 122462306a36Sopenharmony_ci hs_ep->last_load = ureq->actual; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (dir_in && !using_dma(hsotg)) { 122762306a36Sopenharmony_ci /* set these anyway, we may need them for non-periodic in */ 122862306a36Sopenharmony_ci hs_ep->fifo_load = 0; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* 123462306a36Sopenharmony_ci * Note, trying to clear the NAK here causes problems with transmit 123562306a36Sopenharmony_ci * on the S3C6400 ending up with the TXFIFO becoming full. 123662306a36Sopenharmony_ci */ 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci /* check ep is enabled */ 123962306a36Sopenharmony_ci if (!(dwc2_readl(hsotg, epctrl_reg) & DXEPCTL_EPENA)) 124062306a36Sopenharmony_ci dev_dbg(hsotg->dev, 124162306a36Sopenharmony_ci "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", 124262306a36Sopenharmony_ci index, dwc2_readl(hsotg, epctrl_reg)); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", 124562306a36Sopenharmony_ci __func__, dwc2_readl(hsotg, epctrl_reg)); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci /* enable ep interrupts */ 124862306a36Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1); 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci/** 125262306a36Sopenharmony_ci * dwc2_hsotg_map_dma - map the DMA memory being used for the request 125362306a36Sopenharmony_ci * @hsotg: The device state. 125462306a36Sopenharmony_ci * @hs_ep: The endpoint the request is on. 125562306a36Sopenharmony_ci * @req: The request being processed. 125662306a36Sopenharmony_ci * 125762306a36Sopenharmony_ci * We've been asked to queue a request, so ensure that the memory buffer 125862306a36Sopenharmony_ci * is correctly setup for DMA. If we've been passed an extant DMA address 125962306a36Sopenharmony_ci * then ensure the buffer has been synced to memory. If our buffer has no 126062306a36Sopenharmony_ci * DMA memory, then we map the memory and mark our request to allow us to 126162306a36Sopenharmony_ci * cleanup on completion. 126262306a36Sopenharmony_ci */ 126362306a36Sopenharmony_cistatic int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, 126462306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 126562306a36Sopenharmony_ci struct usb_request *req) 126662306a36Sopenharmony_ci{ 126762306a36Sopenharmony_ci int ret; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci hs_ep->map_dir = hs_ep->dir_in; 127062306a36Sopenharmony_ci ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); 127162306a36Sopenharmony_ci if (ret) 127262306a36Sopenharmony_ci goto dma_error; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci return 0; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_cidma_error: 127762306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", 127862306a36Sopenharmony_ci __func__, req->buf, req->length); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci return -EIO; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, 128462306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 128562306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req) 128662306a36Sopenharmony_ci{ 128762306a36Sopenharmony_ci void *req_buf = hs_req->req.buf; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* If dma is not being used or buffer is aligned */ 129062306a36Sopenharmony_ci if (!using_dma(hsotg) || !((long)req_buf & 3)) 129162306a36Sopenharmony_ci return 0; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci WARN_ON(hs_req->saved_req_buf); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, 129662306a36Sopenharmony_ci hs_ep->ep.name, req_buf, hs_req->req.length); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); 129962306a36Sopenharmony_ci if (!hs_req->req.buf) { 130062306a36Sopenharmony_ci hs_req->req.buf = req_buf; 130162306a36Sopenharmony_ci dev_err(hsotg->dev, 130262306a36Sopenharmony_ci "%s: unable to allocate memory for bounce buffer\n", 130362306a36Sopenharmony_ci __func__); 130462306a36Sopenharmony_ci return -ENOMEM; 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci /* Save actual buffer */ 130862306a36Sopenharmony_ci hs_req->saved_req_buf = req_buf; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (hs_ep->dir_in) 131162306a36Sopenharmony_ci memcpy(hs_req->req.buf, req_buf, hs_req->req.length); 131262306a36Sopenharmony_ci return 0; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_cistatic void 131662306a36Sopenharmony_cidwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, 131762306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 131862306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci /* If dma is not being used or buffer was aligned */ 132162306a36Sopenharmony_ci if (!using_dma(hsotg) || !hs_req->saved_req_buf) 132262306a36Sopenharmony_ci return; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__, 132562306a36Sopenharmony_ci hs_ep->ep.name, hs_req->req.status, hs_req->req.actual); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci /* Copy data from bounce buffer on successful out transfer */ 132862306a36Sopenharmony_ci if (!hs_ep->dir_in && !hs_req->req.status) 132962306a36Sopenharmony_ci memcpy(hs_req->saved_req_buf, hs_req->req.buf, 133062306a36Sopenharmony_ci hs_req->req.actual); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* Free bounce buffer */ 133362306a36Sopenharmony_ci kfree(hs_req->req.buf); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci hs_req->req.buf = hs_req->saved_req_buf; 133662306a36Sopenharmony_ci hs_req->saved_req_buf = NULL; 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci/** 134062306a36Sopenharmony_ci * dwc2_gadget_target_frame_elapsed - Checks target frame 134162306a36Sopenharmony_ci * @hs_ep: The driver endpoint to check 134262306a36Sopenharmony_ci * 134362306a36Sopenharmony_ci * Returns 1 if targeted frame elapsed. If returned 1 then we need to drop 134462306a36Sopenharmony_ci * corresponding transfer. 134562306a36Sopenharmony_ci */ 134662306a36Sopenharmony_cistatic bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep) 134762306a36Sopenharmony_ci{ 134862306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 134962306a36Sopenharmony_ci u32 target_frame = hs_ep->target_frame; 135062306a36Sopenharmony_ci u32 current_frame = hsotg->frame_number; 135162306a36Sopenharmony_ci bool frame_overrun = hs_ep->frame_overrun; 135262306a36Sopenharmony_ci u16 limit = DSTS_SOFFN_LIMIT; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci if (hsotg->gadget.speed != USB_SPEED_HIGH) 135562306a36Sopenharmony_ci limit >>= 3; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (!frame_overrun && current_frame >= target_frame) 135862306a36Sopenharmony_ci return true; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (frame_overrun && current_frame >= target_frame && 136162306a36Sopenharmony_ci ((current_frame - target_frame) < limit / 2)) 136262306a36Sopenharmony_ci return true; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci return false; 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci/* 136862306a36Sopenharmony_ci * dwc2_gadget_set_ep0_desc_chain - Set EP's desc chain pointers 136962306a36Sopenharmony_ci * @hsotg: The driver state 137062306a36Sopenharmony_ci * @hs_ep: the ep descriptor chain is for 137162306a36Sopenharmony_ci * 137262306a36Sopenharmony_ci * Called to update EP0 structure's pointers depend on stage of 137362306a36Sopenharmony_ci * control transfer. 137462306a36Sopenharmony_ci */ 137562306a36Sopenharmony_cistatic int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg, 137662306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci switch (hsotg->ep0_state) { 137962306a36Sopenharmony_ci case DWC2_EP0_SETUP: 138062306a36Sopenharmony_ci case DWC2_EP0_STATUS_OUT: 138162306a36Sopenharmony_ci hs_ep->desc_list = hsotg->setup_desc[0]; 138262306a36Sopenharmony_ci hs_ep->desc_list_dma = hsotg->setup_desc_dma[0]; 138362306a36Sopenharmony_ci break; 138462306a36Sopenharmony_ci case DWC2_EP0_DATA_IN: 138562306a36Sopenharmony_ci case DWC2_EP0_STATUS_IN: 138662306a36Sopenharmony_ci hs_ep->desc_list = hsotg->ctrl_in_desc; 138762306a36Sopenharmony_ci hs_ep->desc_list_dma = hsotg->ctrl_in_desc_dma; 138862306a36Sopenharmony_ci break; 138962306a36Sopenharmony_ci case DWC2_EP0_DATA_OUT: 139062306a36Sopenharmony_ci hs_ep->desc_list = hsotg->ctrl_out_desc; 139162306a36Sopenharmony_ci hs_ep->desc_list_dma = hsotg->ctrl_out_desc_dma; 139262306a36Sopenharmony_ci break; 139362306a36Sopenharmony_ci default: 139462306a36Sopenharmony_ci dev_err(hsotg->dev, "invalid EP 0 state in queue %d\n", 139562306a36Sopenharmony_ci hsotg->ep0_state); 139662306a36Sopenharmony_ci return -EINVAL; 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci return 0; 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, 140362306a36Sopenharmony_ci gfp_t gfp_flags) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req = our_req(req); 140662306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 140762306a36Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 140862306a36Sopenharmony_ci bool first; 140962306a36Sopenharmony_ci int ret; 141062306a36Sopenharmony_ci u32 maxsize = 0; 141162306a36Sopenharmony_ci u32 mask = 0; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", 141562306a36Sopenharmony_ci ep->name, req, req->length, req->buf, req->no_interrupt, 141662306a36Sopenharmony_ci req->zero, req->short_not_ok); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci /* Prevent new request submission when controller is suspended */ 141962306a36Sopenharmony_ci if (hs->lx_state != DWC2_L0) { 142062306a36Sopenharmony_ci dev_dbg(hs->dev, "%s: submit request only in active state\n", 142162306a36Sopenharmony_ci __func__); 142262306a36Sopenharmony_ci return -EAGAIN; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci /* initialise status of the request */ 142662306a36Sopenharmony_ci INIT_LIST_HEAD(&hs_req->queue); 142762306a36Sopenharmony_ci req->actual = 0; 142862306a36Sopenharmony_ci req->status = -EINPROGRESS; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* Don't queue ISOC request if length greater than mps*mc */ 143162306a36Sopenharmony_ci if (hs_ep->isochronous && 143262306a36Sopenharmony_ci req->length > (hs_ep->mc * hs_ep->ep.maxpacket)) { 143362306a36Sopenharmony_ci dev_err(hs->dev, "req length > maxpacket*mc\n"); 143462306a36Sopenharmony_ci return -EINVAL; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* In DDMA mode for ISOC's don't queue request if length greater 143862306a36Sopenharmony_ci * than descriptor limits. 143962306a36Sopenharmony_ci */ 144062306a36Sopenharmony_ci if (using_desc_dma(hs) && hs_ep->isochronous) { 144162306a36Sopenharmony_ci maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); 144262306a36Sopenharmony_ci if (hs_ep->dir_in && req->length > maxsize) { 144362306a36Sopenharmony_ci dev_err(hs->dev, "wrong length %d (maxsize=%d)\n", 144462306a36Sopenharmony_ci req->length, maxsize); 144562306a36Sopenharmony_ci return -EINVAL; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (!hs_ep->dir_in && req->length > hs_ep->ep.maxpacket) { 144962306a36Sopenharmony_ci dev_err(hs->dev, "ISOC OUT: wrong length %d (mps=%d)\n", 145062306a36Sopenharmony_ci req->length, hs_ep->ep.maxpacket); 145162306a36Sopenharmony_ci return -EINVAL; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci ret = dwc2_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req); 145662306a36Sopenharmony_ci if (ret) 145762306a36Sopenharmony_ci return ret; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci /* if we're using DMA, sync the buffers as necessary */ 146062306a36Sopenharmony_ci if (using_dma(hs)) { 146162306a36Sopenharmony_ci ret = dwc2_hsotg_map_dma(hs, hs_ep, req); 146262306a36Sopenharmony_ci if (ret) 146362306a36Sopenharmony_ci return ret; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci /* If using descriptor DMA configure EP0 descriptor chain pointers */ 146662306a36Sopenharmony_ci if (using_desc_dma(hs) && !hs_ep->index) { 146762306a36Sopenharmony_ci ret = dwc2_gadget_set_ep0_desc_chain(hs, hs_ep); 146862306a36Sopenharmony_ci if (ret) 146962306a36Sopenharmony_ci return ret; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci first = list_empty(&hs_ep->queue); 147362306a36Sopenharmony_ci list_add_tail(&hs_req->queue, &hs_ep->queue); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci /* 147662306a36Sopenharmony_ci * Handle DDMA isochronous transfers separately - just add new entry 147762306a36Sopenharmony_ci * to the descriptor chain. 147862306a36Sopenharmony_ci * Transfer will be started once SW gets either one of NAK or 147962306a36Sopenharmony_ci * OutTknEpDis interrupts. 148062306a36Sopenharmony_ci */ 148162306a36Sopenharmony_ci if (using_desc_dma(hs) && hs_ep->isochronous) { 148262306a36Sopenharmony_ci if (hs_ep->target_frame != TARGET_FRAME_INITIAL) { 148362306a36Sopenharmony_ci dma_addr_t dma_addr = hs_req->req.dma; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci if (hs_req->req.num_sgs) { 148662306a36Sopenharmony_ci WARN_ON(hs_req->req.num_sgs > 1); 148762306a36Sopenharmony_ci dma_addr = sg_dma_address(hs_req->req.sg); 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr, 149062306a36Sopenharmony_ci hs_req->req.length); 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci return 0; 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci /* Change EP direction if status phase request is after data out */ 149662306a36Sopenharmony_ci if (!hs_ep->index && !req->length && !hs_ep->dir_in && 149762306a36Sopenharmony_ci hs->ep0_state == DWC2_EP0_DATA_OUT) 149862306a36Sopenharmony_ci hs_ep->dir_in = 1; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (first) { 150162306a36Sopenharmony_ci if (!hs_ep->isochronous) { 150262306a36Sopenharmony_ci dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 150362306a36Sopenharmony_ci return 0; 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* Update current frame number value. */ 150762306a36Sopenharmony_ci hs->frame_number = dwc2_hsotg_read_frameno(hs); 150862306a36Sopenharmony_ci while (dwc2_gadget_target_frame_elapsed(hs_ep)) { 150962306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 151062306a36Sopenharmony_ci /* Update current frame number value once more as it 151162306a36Sopenharmony_ci * changes here. 151262306a36Sopenharmony_ci */ 151362306a36Sopenharmony_ci hs->frame_number = dwc2_hsotg_read_frameno(hs); 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci if (hs_ep->target_frame != TARGET_FRAME_INITIAL) 151762306a36Sopenharmony_ci dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci return 0; 152062306a36Sopenharmony_ci} 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_cistatic int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, 152362306a36Sopenharmony_ci gfp_t gfp_flags) 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 152662306a36Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 152762306a36Sopenharmony_ci unsigned long flags; 152862306a36Sopenharmony_ci int ret; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci spin_lock_irqsave(&hs->lock, flags); 153162306a36Sopenharmony_ci ret = dwc2_hsotg_ep_queue(ep, req, gfp_flags); 153262306a36Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci return ret; 153562306a36Sopenharmony_ci} 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_cistatic void dwc2_hsotg_ep_free_request(struct usb_ep *ep, 153862306a36Sopenharmony_ci struct usb_request *req) 153962306a36Sopenharmony_ci{ 154062306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req = our_req(req); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci kfree(hs_req); 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci/** 154662306a36Sopenharmony_ci * dwc2_hsotg_complete_oursetup - setup completion callback 154762306a36Sopenharmony_ci * @ep: The endpoint the request was on. 154862306a36Sopenharmony_ci * @req: The request completed. 154962306a36Sopenharmony_ci * 155062306a36Sopenharmony_ci * Called on completion of any requests the driver itself 155162306a36Sopenharmony_ci * submitted that need cleaning up. 155262306a36Sopenharmony_ci */ 155362306a36Sopenharmony_cistatic void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, 155462306a36Sopenharmony_ci struct usb_request *req) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 155762306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci dwc2_hsotg_ep_free_request(ep, req); 156262306a36Sopenharmony_ci} 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci/** 156562306a36Sopenharmony_ci * ep_from_windex - convert control wIndex value to endpoint 156662306a36Sopenharmony_ci * @hsotg: The driver state. 156762306a36Sopenharmony_ci * @windex: The control request wIndex field (in host order). 156862306a36Sopenharmony_ci * 156962306a36Sopenharmony_ci * Convert the given wIndex into a pointer to an driver endpoint 157062306a36Sopenharmony_ci * structure, or return NULL if it is not a valid endpoint. 157162306a36Sopenharmony_ci */ 157262306a36Sopenharmony_cistatic struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, 157362306a36Sopenharmony_ci u32 windex) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci int dir = (windex & USB_DIR_IN) ? 1 : 0; 157662306a36Sopenharmony_ci int idx = windex & 0x7F; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci if (windex >= 0x100) 157962306a36Sopenharmony_ci return NULL; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (idx > hsotg->num_of_eps) 158262306a36Sopenharmony_ci return NULL; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci return index_to_ep(hsotg, idx, dir); 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci/** 158862306a36Sopenharmony_ci * dwc2_hsotg_set_test_mode - Enable usb Test Modes 158962306a36Sopenharmony_ci * @hsotg: The driver state. 159062306a36Sopenharmony_ci * @testmode: requested usb test mode 159162306a36Sopenharmony_ci * Enable usb Test Mode requested by the Host. 159262306a36Sopenharmony_ci */ 159362306a36Sopenharmony_ciint dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) 159462306a36Sopenharmony_ci{ 159562306a36Sopenharmony_ci int dctl = dwc2_readl(hsotg, DCTL); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci dctl &= ~DCTL_TSTCTL_MASK; 159862306a36Sopenharmony_ci switch (testmode) { 159962306a36Sopenharmony_ci case USB_TEST_J: 160062306a36Sopenharmony_ci case USB_TEST_K: 160162306a36Sopenharmony_ci case USB_TEST_SE0_NAK: 160262306a36Sopenharmony_ci case USB_TEST_PACKET: 160362306a36Sopenharmony_ci case USB_TEST_FORCE_ENABLE: 160462306a36Sopenharmony_ci dctl |= testmode << DCTL_TSTCTL_SHIFT; 160562306a36Sopenharmony_ci break; 160662306a36Sopenharmony_ci default: 160762306a36Sopenharmony_ci return -EINVAL; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 161062306a36Sopenharmony_ci return 0; 161162306a36Sopenharmony_ci} 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci/** 161462306a36Sopenharmony_ci * dwc2_hsotg_send_reply - send reply to control request 161562306a36Sopenharmony_ci * @hsotg: The device state 161662306a36Sopenharmony_ci * @ep: Endpoint 0 161762306a36Sopenharmony_ci * @buff: Buffer for request 161862306a36Sopenharmony_ci * @length: Length of reply. 161962306a36Sopenharmony_ci * 162062306a36Sopenharmony_ci * Create a request and queue it on the given endpoint. This is useful as 162162306a36Sopenharmony_ci * an internal method of sending replies to certain control requests, etc. 162262306a36Sopenharmony_ci */ 162362306a36Sopenharmony_cistatic int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, 162462306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep, 162562306a36Sopenharmony_ci void *buff, 162662306a36Sopenharmony_ci int length) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci struct usb_request *req; 162962306a36Sopenharmony_ci int ret; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci req = dwc2_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); 163462306a36Sopenharmony_ci hsotg->ep0_reply = req; 163562306a36Sopenharmony_ci if (!req) { 163662306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); 163762306a36Sopenharmony_ci return -ENOMEM; 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci req->buf = hsotg->ep0_buff; 164162306a36Sopenharmony_ci req->length = length; 164262306a36Sopenharmony_ci /* 164362306a36Sopenharmony_ci * zero flag is for sending zlp in DATA IN stage. It has no impact on 164462306a36Sopenharmony_ci * STATUS stage. 164562306a36Sopenharmony_ci */ 164662306a36Sopenharmony_ci req->zero = 0; 164762306a36Sopenharmony_ci req->complete = dwc2_hsotg_complete_oursetup; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci if (length) 165062306a36Sopenharmony_ci memcpy(req->buf, buff, length); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci ret = dwc2_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); 165362306a36Sopenharmony_ci if (ret) { 165462306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); 165562306a36Sopenharmony_ci return ret; 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci return 0; 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci/** 166262306a36Sopenharmony_ci * dwc2_hsotg_process_req_status - process request GET_STATUS 166362306a36Sopenharmony_ci * @hsotg: The device state 166462306a36Sopenharmony_ci * @ctrl: USB control request 166562306a36Sopenharmony_ci */ 166662306a36Sopenharmony_cistatic int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, 166762306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 167062306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep; 167162306a36Sopenharmony_ci __le16 reply; 167262306a36Sopenharmony_ci u16 status; 167362306a36Sopenharmony_ci int ret; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci if (!ep0->dir_in) { 167862306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: direction out?\n", __func__); 167962306a36Sopenharmony_ci return -EINVAL; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci switch (ctrl->bRequestType & USB_RECIP_MASK) { 168362306a36Sopenharmony_ci case USB_RECIP_DEVICE: 168462306a36Sopenharmony_ci status = hsotg->gadget.is_selfpowered << 168562306a36Sopenharmony_ci USB_DEVICE_SELF_POWERED; 168662306a36Sopenharmony_ci status |= hsotg->remote_wakeup_allowed << 168762306a36Sopenharmony_ci USB_DEVICE_REMOTE_WAKEUP; 168862306a36Sopenharmony_ci reply = cpu_to_le16(status); 168962306a36Sopenharmony_ci break; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 169262306a36Sopenharmony_ci /* currently, the data result should be zero */ 169362306a36Sopenharmony_ci reply = cpu_to_le16(0); 169462306a36Sopenharmony_ci break; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: 169762306a36Sopenharmony_ci ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); 169862306a36Sopenharmony_ci if (!ep) 169962306a36Sopenharmony_ci return -ENOENT; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci reply = cpu_to_le16(ep->halted ? 1 : 0); 170262306a36Sopenharmony_ci break; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci default: 170562306a36Sopenharmony_ci return 0; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci if (le16_to_cpu(ctrl->wLength) != 2) 170962306a36Sopenharmony_ci return -EINVAL; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci ret = dwc2_hsotg_send_reply(hsotg, ep0, &reply, 2); 171262306a36Sopenharmony_ci if (ret) { 171362306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); 171462306a36Sopenharmony_ci return ret; 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci return 1; 171862306a36Sopenharmony_ci} 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now); 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci/** 172362306a36Sopenharmony_ci * get_ep_head - return the first request on the endpoint 172462306a36Sopenharmony_ci * @hs_ep: The controller endpoint to get 172562306a36Sopenharmony_ci * 172662306a36Sopenharmony_ci * Get the first request on the endpoint. 172762306a36Sopenharmony_ci */ 172862306a36Sopenharmony_cistatic struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci return list_first_entry_or_null(&hs_ep->queue, struct dwc2_hsotg_req, 173162306a36Sopenharmony_ci queue); 173262306a36Sopenharmony_ci} 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci/** 173562306a36Sopenharmony_ci * dwc2_gadget_start_next_request - Starts next request from ep queue 173662306a36Sopenharmony_ci * @hs_ep: Endpoint structure 173762306a36Sopenharmony_ci * 173862306a36Sopenharmony_ci * If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked 173962306a36Sopenharmony_ci * in its handler. Hence we need to unmask it here to be able to do 174062306a36Sopenharmony_ci * resynchronization. 174162306a36Sopenharmony_ci */ 174262306a36Sopenharmony_cistatic void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 174562306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 174662306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci if (!list_empty(&hs_ep->queue)) { 174962306a36Sopenharmony_ci hs_req = get_ep_head(hs_ep); 175062306a36Sopenharmony_ci dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false); 175162306a36Sopenharmony_ci return; 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci if (!hs_ep->isochronous) 175462306a36Sopenharmony_ci return; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci if (dir_in) { 175762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n", 175862306a36Sopenharmony_ci __func__); 175962306a36Sopenharmony_ci } else { 176062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n", 176162306a36Sopenharmony_ci __func__); 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci} 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci/** 176662306a36Sopenharmony_ci * dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE 176762306a36Sopenharmony_ci * @hsotg: The device state 176862306a36Sopenharmony_ci * @ctrl: USB control request 176962306a36Sopenharmony_ci */ 177062306a36Sopenharmony_cistatic int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, 177162306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 177262306a36Sopenharmony_ci{ 177362306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 177462306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 177562306a36Sopenharmony_ci bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); 177662306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep; 177762306a36Sopenharmony_ci int ret; 177862306a36Sopenharmony_ci bool halted; 177962306a36Sopenharmony_ci u32 recip; 178062306a36Sopenharmony_ci u32 wValue; 178162306a36Sopenharmony_ci u32 wIndex; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", 178462306a36Sopenharmony_ci __func__, set ? "SET" : "CLEAR"); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci wValue = le16_to_cpu(ctrl->wValue); 178762306a36Sopenharmony_ci wIndex = le16_to_cpu(ctrl->wIndex); 178862306a36Sopenharmony_ci recip = ctrl->bRequestType & USB_RECIP_MASK; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci switch (recip) { 179162306a36Sopenharmony_ci case USB_RECIP_DEVICE: 179262306a36Sopenharmony_ci switch (wValue) { 179362306a36Sopenharmony_ci case USB_DEVICE_REMOTE_WAKEUP: 179462306a36Sopenharmony_ci if (set) 179562306a36Sopenharmony_ci hsotg->remote_wakeup_allowed = 1; 179662306a36Sopenharmony_ci else 179762306a36Sopenharmony_ci hsotg->remote_wakeup_allowed = 0; 179862306a36Sopenharmony_ci break; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci case USB_DEVICE_TEST_MODE: 180162306a36Sopenharmony_ci if ((wIndex & 0xff) != 0) 180262306a36Sopenharmony_ci return -EINVAL; 180362306a36Sopenharmony_ci if (!set) 180462306a36Sopenharmony_ci return -EINVAL; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci hsotg->test_mode = wIndex >> 8; 180762306a36Sopenharmony_ci break; 180862306a36Sopenharmony_ci default: 180962306a36Sopenharmony_ci return -ENOENT; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 181362306a36Sopenharmony_ci if (ret) { 181462306a36Sopenharmony_ci dev_err(hsotg->dev, 181562306a36Sopenharmony_ci "%s: failed to send reply\n", __func__); 181662306a36Sopenharmony_ci return ret; 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci break; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: 182162306a36Sopenharmony_ci ep = ep_from_windex(hsotg, wIndex); 182262306a36Sopenharmony_ci if (!ep) { 182362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", 182462306a36Sopenharmony_ci __func__, wIndex); 182562306a36Sopenharmony_ci return -ENOENT; 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci switch (wValue) { 182962306a36Sopenharmony_ci case USB_ENDPOINT_HALT: 183062306a36Sopenharmony_ci halted = ep->halted; 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci if (!ep->wedged) 183362306a36Sopenharmony_ci dwc2_hsotg_ep_sethalt(&ep->ep, set, true); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 183662306a36Sopenharmony_ci if (ret) { 183762306a36Sopenharmony_ci dev_err(hsotg->dev, 183862306a36Sopenharmony_ci "%s: failed to send reply\n", __func__); 183962306a36Sopenharmony_ci return ret; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* 184362306a36Sopenharmony_ci * we have to complete all requests for ep if it was 184462306a36Sopenharmony_ci * halted, and the halt was cleared by CLEAR_FEATURE 184562306a36Sopenharmony_ci */ 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci if (!set && halted) { 184862306a36Sopenharmony_ci /* 184962306a36Sopenharmony_ci * If we have request in progress, 185062306a36Sopenharmony_ci * then complete it 185162306a36Sopenharmony_ci */ 185262306a36Sopenharmony_ci if (ep->req) { 185362306a36Sopenharmony_ci hs_req = ep->req; 185462306a36Sopenharmony_ci ep->req = NULL; 185562306a36Sopenharmony_ci list_del_init(&hs_req->queue); 185662306a36Sopenharmony_ci if (hs_req->req.complete) { 185762306a36Sopenharmony_ci spin_unlock(&hsotg->lock); 185862306a36Sopenharmony_ci usb_gadget_giveback_request( 185962306a36Sopenharmony_ci &ep->ep, &hs_req->req); 186062306a36Sopenharmony_ci spin_lock(&hsotg->lock); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci } 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci /* If we have pending request, then start it */ 186562306a36Sopenharmony_ci if (!ep->req) 186662306a36Sopenharmony_ci dwc2_gadget_start_next_request(ep); 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci break; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci default: 187262306a36Sopenharmony_ci return -ENOENT; 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci break; 187562306a36Sopenharmony_ci default: 187662306a36Sopenharmony_ci return -ENOENT; 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci return 1; 187962306a36Sopenharmony_ci} 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_cistatic void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci/** 188462306a36Sopenharmony_ci * dwc2_hsotg_stall_ep0 - stall ep0 188562306a36Sopenharmony_ci * @hsotg: The device state 188662306a36Sopenharmony_ci * 188762306a36Sopenharmony_ci * Set stall for ep0 as response for setup request. 188862306a36Sopenharmony_ci */ 188962306a36Sopenharmony_cistatic void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) 189062306a36Sopenharmony_ci{ 189162306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 189262306a36Sopenharmony_ci u32 reg; 189362306a36Sopenharmony_ci u32 ctrl; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); 189662306a36Sopenharmony_ci reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci /* 189962306a36Sopenharmony_ci * DxEPCTL_Stall will be cleared by EP once it has 190062306a36Sopenharmony_ci * taken effect, so no need to clear later. 190162306a36Sopenharmony_ci */ 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci ctrl = dwc2_readl(hsotg, reg); 190462306a36Sopenharmony_ci ctrl |= DXEPCTL_STALL; 190562306a36Sopenharmony_ci ctrl |= DXEPCTL_CNAK; 190662306a36Sopenharmony_ci dwc2_writel(hsotg, ctrl, reg); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci dev_dbg(hsotg->dev, 190962306a36Sopenharmony_ci "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", 191062306a36Sopenharmony_ci ctrl, reg, dwc2_readl(hsotg, reg)); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci /* 191362306a36Sopenharmony_ci * complete won't be called, so we enqueue 191462306a36Sopenharmony_ci * setup request here 191562306a36Sopenharmony_ci */ 191662306a36Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 191762306a36Sopenharmony_ci} 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci/** 192062306a36Sopenharmony_ci * dwc2_hsotg_process_control - process a control request 192162306a36Sopenharmony_ci * @hsotg: The device state 192262306a36Sopenharmony_ci * @ctrl: The control request received 192362306a36Sopenharmony_ci * 192462306a36Sopenharmony_ci * The controller has received the SETUP phase of a control request, and 192562306a36Sopenharmony_ci * needs to work out what to do next (and whether to pass it on to the 192662306a36Sopenharmony_ci * gadget driver). 192762306a36Sopenharmony_ci */ 192862306a36Sopenharmony_cistatic void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, 192962306a36Sopenharmony_ci struct usb_ctrlrequest *ctrl) 193062306a36Sopenharmony_ci{ 193162306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; 193262306a36Sopenharmony_ci int ret = 0; 193362306a36Sopenharmony_ci u32 dcfg; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci dev_dbg(hsotg->dev, 193662306a36Sopenharmony_ci "ctrl Type=%02x, Req=%02x, V=%04x, I=%04x, L=%04x\n", 193762306a36Sopenharmony_ci ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, 193862306a36Sopenharmony_ci ctrl->wIndex, ctrl->wLength); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci if (ctrl->wLength == 0) { 194162306a36Sopenharmony_ci ep0->dir_in = 1; 194262306a36Sopenharmony_ci hsotg->ep0_state = DWC2_EP0_STATUS_IN; 194362306a36Sopenharmony_ci } else if (ctrl->bRequestType & USB_DIR_IN) { 194462306a36Sopenharmony_ci ep0->dir_in = 1; 194562306a36Sopenharmony_ci hsotg->ep0_state = DWC2_EP0_DATA_IN; 194662306a36Sopenharmony_ci } else { 194762306a36Sopenharmony_ci ep0->dir_in = 0; 194862306a36Sopenharmony_ci hsotg->ep0_state = DWC2_EP0_DATA_OUT; 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { 195262306a36Sopenharmony_ci switch (ctrl->bRequest) { 195362306a36Sopenharmony_ci case USB_REQ_SET_ADDRESS: 195462306a36Sopenharmony_ci hsotg->connected = 1; 195562306a36Sopenharmony_ci dcfg = dwc2_readl(hsotg, DCFG); 195662306a36Sopenharmony_ci dcfg &= ~DCFG_DEVADDR_MASK; 195762306a36Sopenharmony_ci dcfg |= (le16_to_cpu(ctrl->wValue) << 195862306a36Sopenharmony_ci DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK; 195962306a36Sopenharmony_ci dwc2_writel(hsotg, dcfg, DCFG); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); 196462306a36Sopenharmony_ci return; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci case USB_REQ_GET_STATUS: 196762306a36Sopenharmony_ci ret = dwc2_hsotg_process_req_status(hsotg, ctrl); 196862306a36Sopenharmony_ci break; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 197162306a36Sopenharmony_ci case USB_REQ_SET_FEATURE: 197262306a36Sopenharmony_ci ret = dwc2_hsotg_process_req_feature(hsotg, ctrl); 197362306a36Sopenharmony_ci break; 197462306a36Sopenharmony_ci } 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci /* as a fallback, try delivering it to the driver to deal with */ 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci if (ret == 0 && hsotg->driver) { 198062306a36Sopenharmony_ci spin_unlock(&hsotg->lock); 198162306a36Sopenharmony_ci ret = hsotg->driver->setup(&hsotg->gadget, ctrl); 198262306a36Sopenharmony_ci spin_lock(&hsotg->lock); 198362306a36Sopenharmony_ci if (ret < 0) 198462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); 198562306a36Sopenharmony_ci } 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci hsotg->delayed_status = false; 198862306a36Sopenharmony_ci if (ret == USB_GADGET_DELAYED_STATUS) 198962306a36Sopenharmony_ci hsotg->delayed_status = true; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci /* 199262306a36Sopenharmony_ci * the request is either unhandlable, or is not formatted correctly 199362306a36Sopenharmony_ci * so respond with a STALL for the status stage to indicate failure. 199462306a36Sopenharmony_ci */ 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci if (ret < 0) 199762306a36Sopenharmony_ci dwc2_hsotg_stall_ep0(hsotg); 199862306a36Sopenharmony_ci} 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci/** 200162306a36Sopenharmony_ci * dwc2_hsotg_complete_setup - completion of a setup transfer 200262306a36Sopenharmony_ci * @ep: The endpoint the request was on. 200362306a36Sopenharmony_ci * @req: The request completed. 200462306a36Sopenharmony_ci * 200562306a36Sopenharmony_ci * Called on completion of any requests the driver itself submitted for 200662306a36Sopenharmony_ci * EP0 setup packets 200762306a36Sopenharmony_ci */ 200862306a36Sopenharmony_cistatic void dwc2_hsotg_complete_setup(struct usb_ep *ep, 200962306a36Sopenharmony_ci struct usb_request *req) 201062306a36Sopenharmony_ci{ 201162306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 201262306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci if (req->status < 0) { 201562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); 201662306a36Sopenharmony_ci return; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci spin_lock(&hsotg->lock); 202062306a36Sopenharmony_ci if (req->actual == 0) 202162306a36Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 202262306a36Sopenharmony_ci else 202362306a36Sopenharmony_ci dwc2_hsotg_process_control(hsotg, req->buf); 202462306a36Sopenharmony_ci spin_unlock(&hsotg->lock); 202562306a36Sopenharmony_ci} 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci/** 202862306a36Sopenharmony_ci * dwc2_hsotg_enqueue_setup - start a request for EP0 packets 202962306a36Sopenharmony_ci * @hsotg: The device state. 203062306a36Sopenharmony_ci * 203162306a36Sopenharmony_ci * Enqueue a request on EP0 if necessary to received any SETUP packets 203262306a36Sopenharmony_ci * received from the host. 203362306a36Sopenharmony_ci */ 203462306a36Sopenharmony_cistatic void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) 203562306a36Sopenharmony_ci{ 203662306a36Sopenharmony_ci struct usb_request *req = hsotg->ctrl_req; 203762306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req = our_req(req); 203862306a36Sopenharmony_ci int ret; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci req->zero = 0; 204362306a36Sopenharmony_ci req->length = 8; 204462306a36Sopenharmony_ci req->buf = hsotg->ctrl_buff; 204562306a36Sopenharmony_ci req->complete = dwc2_hsotg_complete_setup; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (!list_empty(&hs_req->queue)) { 204862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s already queued???\n", __func__); 204962306a36Sopenharmony_ci return; 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci hsotg->eps_out[0]->dir_in = 0; 205362306a36Sopenharmony_ci hsotg->eps_out[0]->send_zlp = 0; 205462306a36Sopenharmony_ci hsotg->ep0_state = DWC2_EP0_SETUP; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci ret = dwc2_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC); 205762306a36Sopenharmony_ci if (ret < 0) { 205862306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); 205962306a36Sopenharmony_ci /* 206062306a36Sopenharmony_ci * Don't think there's much we can do other than watch the 206162306a36Sopenharmony_ci * driver fail. 206262306a36Sopenharmony_ci */ 206362306a36Sopenharmony_ci } 206462306a36Sopenharmony_ci} 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_cistatic void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, 206762306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 206862306a36Sopenharmony_ci{ 206962306a36Sopenharmony_ci u32 ctrl; 207062306a36Sopenharmony_ci u8 index = hs_ep->index; 207162306a36Sopenharmony_ci u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index); 207262306a36Sopenharmony_ci u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci if (hs_ep->dir_in) 207562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n", 207662306a36Sopenharmony_ci index); 207762306a36Sopenharmony_ci else 207862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n", 207962306a36Sopenharmony_ci index); 208062306a36Sopenharmony_ci if (using_desc_dma(hsotg)) { 208162306a36Sopenharmony_ci /* Not specific buffer needed for ep0 ZLP */ 208262306a36Sopenharmony_ci dma_addr_t dma = hs_ep->desc_list_dma; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci if (!index) 208562306a36Sopenharmony_ci dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0); 208862306a36Sopenharmony_ci } else { 208962306a36Sopenharmony_ci dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 209062306a36Sopenharmony_ci DXEPTSIZ_XFERSIZE(0), 209162306a36Sopenharmony_ci epsiz_reg); 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci ctrl = dwc2_readl(hsotg, epctl_reg); 209562306a36Sopenharmony_ci ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */ 209662306a36Sopenharmony_ci ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ 209762306a36Sopenharmony_ci ctrl |= DXEPCTL_USBACTEP; 209862306a36Sopenharmony_ci dwc2_writel(hsotg, ctrl, epctl_reg); 209962306a36Sopenharmony_ci} 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci/** 210262306a36Sopenharmony_ci * dwc2_hsotg_complete_request - complete a request given to us 210362306a36Sopenharmony_ci * @hsotg: The device state. 210462306a36Sopenharmony_ci * @hs_ep: The endpoint the request was on. 210562306a36Sopenharmony_ci * @hs_req: The request to complete. 210662306a36Sopenharmony_ci * @result: The result code (0 => Ok, otherwise errno) 210762306a36Sopenharmony_ci * 210862306a36Sopenharmony_ci * The given request has finished, so call the necessary completion 210962306a36Sopenharmony_ci * if it has one and then look to see if we can start a new request 211062306a36Sopenharmony_ci * on the endpoint. 211162306a36Sopenharmony_ci * 211262306a36Sopenharmony_ci * Note, expects the ep to already be locked as appropriate. 211362306a36Sopenharmony_ci */ 211462306a36Sopenharmony_cistatic void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, 211562306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 211662306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req, 211762306a36Sopenharmony_ci int result) 211862306a36Sopenharmony_ci{ 211962306a36Sopenharmony_ci if (!hs_req) { 212062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); 212162306a36Sopenharmony_ci return; 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", 212562306a36Sopenharmony_ci hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci /* 212862306a36Sopenharmony_ci * only replace the status if we've not already set an error 212962306a36Sopenharmony_ci * from a previous transaction 213062306a36Sopenharmony_ci */ 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci if (hs_req->req.status == -EINPROGRESS) 213362306a36Sopenharmony_ci hs_req->req.status = result; 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci if (using_dma(hsotg)) 213662306a36Sopenharmony_ci dwc2_hsotg_unmap_dma(hsotg, hs_ep, hs_req); 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci dwc2_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req); 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci hs_ep->req = NULL; 214162306a36Sopenharmony_ci list_del_init(&hs_req->queue); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci /* 214462306a36Sopenharmony_ci * call the complete request with the locks off, just in case the 214562306a36Sopenharmony_ci * request tries to queue more work for this endpoint. 214662306a36Sopenharmony_ci */ 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci if (hs_req->req.complete) { 214962306a36Sopenharmony_ci spin_unlock(&hsotg->lock); 215062306a36Sopenharmony_ci usb_gadget_giveback_request(&hs_ep->ep, &hs_req->req); 215162306a36Sopenharmony_ci spin_lock(&hsotg->lock); 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci /* In DDMA don't need to proceed to starting of next ISOC request */ 215562306a36Sopenharmony_ci if (using_desc_dma(hsotg) && hs_ep->isochronous) 215662306a36Sopenharmony_ci return; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci /* 215962306a36Sopenharmony_ci * Look to see if there is anything else to do. Note, the completion 216062306a36Sopenharmony_ci * of the previous request may have caused a new request to be started 216162306a36Sopenharmony_ci * so be careful when doing this. 216262306a36Sopenharmony_ci */ 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci if (!hs_ep->req && result >= 0) 216562306a36Sopenharmony_ci dwc2_gadget_start_next_request(hs_ep); 216662306a36Sopenharmony_ci} 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci/* 216962306a36Sopenharmony_ci * dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA 217062306a36Sopenharmony_ci * @hs_ep: The endpoint the request was on. 217162306a36Sopenharmony_ci * 217262306a36Sopenharmony_ci * Get first request from the ep queue, determine descriptor on which complete 217362306a36Sopenharmony_ci * happened. SW discovers which descriptor currently in use by HW, adjusts 217462306a36Sopenharmony_ci * dma_address and calculates index of completed descriptor based on the value 217562306a36Sopenharmony_ci * of DEPDMA register. Update actual length of request, giveback to gadget. 217662306a36Sopenharmony_ci */ 217762306a36Sopenharmony_cistatic void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep) 217862306a36Sopenharmony_ci{ 217962306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 218062306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 218162306a36Sopenharmony_ci struct usb_request *ureq; 218262306a36Sopenharmony_ci u32 desc_sts; 218362306a36Sopenharmony_ci u32 mask; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci /* Process only descriptors with buffer status set to DMA done */ 218862306a36Sopenharmony_ci while ((desc_sts & DEV_DMA_BUFF_STS_MASK) >> 218962306a36Sopenharmony_ci DEV_DMA_BUFF_STS_SHIFT == DEV_DMA_BUFF_STS_DMADONE) { 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci hs_req = get_ep_head(hs_ep); 219262306a36Sopenharmony_ci if (!hs_req) { 219362306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__); 219462306a36Sopenharmony_ci return; 219562306a36Sopenharmony_ci } 219662306a36Sopenharmony_ci ureq = &hs_req->req; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci /* Check completion status */ 219962306a36Sopenharmony_ci if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT == 220062306a36Sopenharmony_ci DEV_DMA_STS_SUCC) { 220162306a36Sopenharmony_ci mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK : 220262306a36Sopenharmony_ci DEV_DMA_ISOC_RX_NBYTES_MASK; 220362306a36Sopenharmony_ci ureq->actual = ureq->length - ((desc_sts & mask) >> 220462306a36Sopenharmony_ci DEV_DMA_ISOC_NBYTES_SHIFT); 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci /* Adjust actual len for ISOC Out if len is 220762306a36Sopenharmony_ci * not align of 4 220862306a36Sopenharmony_ci */ 220962306a36Sopenharmony_ci if (!hs_ep->dir_in && ureq->length & 0x3) 221062306a36Sopenharmony_ci ureq->actual += 4 - (ureq->length & 0x3); 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci /* Set actual frame number for completed transfers */ 221362306a36Sopenharmony_ci ureq->frame_number = 221462306a36Sopenharmony_ci (desc_sts & DEV_DMA_ISOC_FRNUM_MASK) >> 221562306a36Sopenharmony_ci DEV_DMA_ISOC_FRNUM_SHIFT; 221662306a36Sopenharmony_ci } 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci hs_ep->compl_desc++; 222162306a36Sopenharmony_ci if (hs_ep->compl_desc > (MAX_DMA_DESC_NUM_HS_ISOC - 1)) 222262306a36Sopenharmony_ci hs_ep->compl_desc = 0; 222362306a36Sopenharmony_ci desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; 222462306a36Sopenharmony_ci } 222562306a36Sopenharmony_ci} 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci/* 222862306a36Sopenharmony_ci * dwc2_gadget_handle_isoc_bna - handle BNA interrupt for ISOC. 222962306a36Sopenharmony_ci * @hs_ep: The isochronous endpoint. 223062306a36Sopenharmony_ci * 223162306a36Sopenharmony_ci * If EP ISOC OUT then need to flush RX FIFO to remove source of BNA 223262306a36Sopenharmony_ci * interrupt. Reset target frame and next_desc to allow to start 223362306a36Sopenharmony_ci * ISOC's on NAK interrupt for IN direction or on OUTTKNEPDIS 223462306a36Sopenharmony_ci * interrupt for OUT direction. 223562306a36Sopenharmony_ci */ 223662306a36Sopenharmony_cistatic void dwc2_gadget_handle_isoc_bna(struct dwc2_hsotg_ep *hs_ep) 223762306a36Sopenharmony_ci{ 223862306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci if (!hs_ep->dir_in) 224162306a36Sopenharmony_ci dwc2_flush_rx_fifo(hsotg); 224262306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, get_ep_head(hs_ep), 0); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci hs_ep->target_frame = TARGET_FRAME_INITIAL; 224562306a36Sopenharmony_ci hs_ep->next_desc = 0; 224662306a36Sopenharmony_ci hs_ep->compl_desc = 0; 224762306a36Sopenharmony_ci} 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci/** 225062306a36Sopenharmony_ci * dwc2_hsotg_rx_data - receive data from the FIFO for an endpoint 225162306a36Sopenharmony_ci * @hsotg: The device state. 225262306a36Sopenharmony_ci * @ep_idx: The endpoint index for the data 225362306a36Sopenharmony_ci * @size: The size of data in the fifo, in bytes 225462306a36Sopenharmony_ci * 225562306a36Sopenharmony_ci * The FIFO status shows there is data to read from the FIFO for a given 225662306a36Sopenharmony_ci * endpoint, so sort out whether we need to read the data into a request 225762306a36Sopenharmony_ci * that has been made for that endpoint. 225862306a36Sopenharmony_ci */ 225962306a36Sopenharmony_cistatic void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) 226062306a36Sopenharmony_ci{ 226162306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx]; 226262306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req = hs_ep->req; 226362306a36Sopenharmony_ci int to_read; 226462306a36Sopenharmony_ci int max_req; 226562306a36Sopenharmony_ci int read_ptr; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci if (!hs_req) { 226862306a36Sopenharmony_ci u32 epctl = dwc2_readl(hsotg, DOEPCTL(ep_idx)); 226962306a36Sopenharmony_ci int ptr; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci dev_dbg(hsotg->dev, 227262306a36Sopenharmony_ci "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", 227362306a36Sopenharmony_ci __func__, size, ep_idx, epctl); 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci /* dump the data from the FIFO, we've nothing we can do */ 227662306a36Sopenharmony_ci for (ptr = 0; ptr < size; ptr += 4) 227762306a36Sopenharmony_ci (void)dwc2_readl(hsotg, EPFIFO(ep_idx)); 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci return; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci to_read = size; 228362306a36Sopenharmony_ci read_ptr = hs_req->req.actual; 228462306a36Sopenharmony_ci max_req = hs_req->req.length - read_ptr; 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", 228762306a36Sopenharmony_ci __func__, to_read, max_req, read_ptr, hs_req->req.length); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci if (to_read > max_req) { 229062306a36Sopenharmony_ci /* 229162306a36Sopenharmony_ci * more data appeared than we where willing 229262306a36Sopenharmony_ci * to deal with in this request. 229362306a36Sopenharmony_ci */ 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci /* currently we don't deal this */ 229662306a36Sopenharmony_ci WARN_ON_ONCE(1); 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci hs_ep->total_data += to_read; 230062306a36Sopenharmony_ci hs_req->req.actual += to_read; 230162306a36Sopenharmony_ci to_read = DIV_ROUND_UP(to_read, 4); 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci /* 230462306a36Sopenharmony_ci * note, we might over-write the buffer end by 3 bytes depending on 230562306a36Sopenharmony_ci * alignment of the data. 230662306a36Sopenharmony_ci */ 230762306a36Sopenharmony_ci dwc2_readl_rep(hsotg, EPFIFO(ep_idx), 230862306a36Sopenharmony_ci hs_req->req.buf + read_ptr, to_read); 230962306a36Sopenharmony_ci} 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci/** 231262306a36Sopenharmony_ci * dwc2_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint 231362306a36Sopenharmony_ci * @hsotg: The device instance 231462306a36Sopenharmony_ci * @dir_in: If IN zlp 231562306a36Sopenharmony_ci * 231662306a36Sopenharmony_ci * Generate a zero-length IN packet request for terminating a SETUP 231762306a36Sopenharmony_ci * transaction. 231862306a36Sopenharmony_ci * 231962306a36Sopenharmony_ci * Note, since we don't write any data to the TxFIFO, then it is 232062306a36Sopenharmony_ci * currently believed that we do not need to wait for any space in 232162306a36Sopenharmony_ci * the TxFIFO. 232262306a36Sopenharmony_ci */ 232362306a36Sopenharmony_cistatic void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) 232462306a36Sopenharmony_ci{ 232562306a36Sopenharmony_ci /* eps_out[0] is used in both directions */ 232662306a36Sopenharmony_ci hsotg->eps_out[0]->dir_in = dir_in; 232762306a36Sopenharmony_ci hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT; 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci dwc2_hsotg_program_zlp(hsotg, hsotg->eps_out[0]); 233062306a36Sopenharmony_ci} 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci/* 233362306a36Sopenharmony_ci * dwc2_gadget_get_xfersize_ddma - get transferred bytes amount from desc 233462306a36Sopenharmony_ci * @hs_ep - The endpoint on which transfer went 233562306a36Sopenharmony_ci * 233662306a36Sopenharmony_ci * Iterate over endpoints descriptor chain and get info on bytes remained 233762306a36Sopenharmony_ci * in DMA descriptors after transfer has completed. Used for non isoc EPs. 233862306a36Sopenharmony_ci */ 233962306a36Sopenharmony_cistatic unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) 234062306a36Sopenharmony_ci{ 234162306a36Sopenharmony_ci const struct usb_endpoint_descriptor *ep_desc = hs_ep->ep.desc; 234262306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 234362306a36Sopenharmony_ci unsigned int bytes_rem = 0; 234462306a36Sopenharmony_ci unsigned int bytes_rem_correction = 0; 234562306a36Sopenharmony_ci struct dwc2_dma_desc *desc = hs_ep->desc_list; 234662306a36Sopenharmony_ci int i; 234762306a36Sopenharmony_ci u32 status; 234862306a36Sopenharmony_ci u32 mps = hs_ep->ep.maxpacket; 234962306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci if (!desc) 235262306a36Sopenharmony_ci return -EINVAL; 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci /* Interrupt OUT EP with mps not multiple of 4 */ 235562306a36Sopenharmony_ci if (hs_ep->index) 235662306a36Sopenharmony_ci if (usb_endpoint_xfer_int(ep_desc) && !dir_in && (mps % 4)) 235762306a36Sopenharmony_ci bytes_rem_correction = 4 - (mps % 4); 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci for (i = 0; i < hs_ep->desc_count; ++i) { 236062306a36Sopenharmony_ci status = desc->status; 236162306a36Sopenharmony_ci bytes_rem += status & DEV_DMA_NBYTES_MASK; 236262306a36Sopenharmony_ci bytes_rem -= bytes_rem_correction; 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci if (status & DEV_DMA_STS_MASK) 236562306a36Sopenharmony_ci dev_err(hsotg->dev, "descriptor %d closed with %x\n", 236662306a36Sopenharmony_ci i, status & DEV_DMA_STS_MASK); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci if (status & DEV_DMA_L) 236962306a36Sopenharmony_ci break; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci desc++; 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci return bytes_rem; 237562306a36Sopenharmony_ci} 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci/** 237862306a36Sopenharmony_ci * dwc2_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO 237962306a36Sopenharmony_ci * @hsotg: The device instance 238062306a36Sopenharmony_ci * @epnum: The endpoint received from 238162306a36Sopenharmony_ci * 238262306a36Sopenharmony_ci * The RXFIFO has delivered an OutDone event, which means that the data 238362306a36Sopenharmony_ci * transfer for an OUT endpoint has been completed, either by a short 238462306a36Sopenharmony_ci * packet or by the finish of a transfer. 238562306a36Sopenharmony_ci */ 238662306a36Sopenharmony_cistatic void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) 238762306a36Sopenharmony_ci{ 238862306a36Sopenharmony_ci u32 epsize = dwc2_readl(hsotg, DOEPTSIZ(epnum)); 238962306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; 239062306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req = hs_ep->req; 239162306a36Sopenharmony_ci struct usb_request *req = &hs_req->req; 239262306a36Sopenharmony_ci unsigned int size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 239362306a36Sopenharmony_ci int result = 0; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci if (!hs_req) { 239662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: no request active\n", __func__); 239762306a36Sopenharmony_ci return; 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) { 240162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "zlp packet received\n"); 240262306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 240362306a36Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 240462306a36Sopenharmony_ci return; 240562306a36Sopenharmony_ci } 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci if (using_desc_dma(hsotg)) 240862306a36Sopenharmony_ci size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci if (using_dma(hsotg)) { 241162306a36Sopenharmony_ci unsigned int size_done; 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci /* 241462306a36Sopenharmony_ci * Calculate the size of the transfer by checking how much 241562306a36Sopenharmony_ci * is left in the endpoint size register and then working it 241662306a36Sopenharmony_ci * out from the amount we loaded for the transfer. 241762306a36Sopenharmony_ci * 241862306a36Sopenharmony_ci * We need to do this as DMA pointers are always 32bit aligned 241962306a36Sopenharmony_ci * so may overshoot/undershoot the transfer. 242062306a36Sopenharmony_ci */ 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci size_done = hs_ep->size_loaded - size_left; 242362306a36Sopenharmony_ci size_done += hs_ep->last_load; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci req->actual = size_done; 242662306a36Sopenharmony_ci } 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci /* if there is more request to do, schedule new transfer */ 242962306a36Sopenharmony_ci if (req->actual < req->length && size_left == 0) { 243062306a36Sopenharmony_ci dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 243162306a36Sopenharmony_ci return; 243262306a36Sopenharmony_ci } 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_ci if (req->actual < req->length && req->short_not_ok) { 243562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", 243662306a36Sopenharmony_ci __func__, req->actual, req->length); 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci /* 243962306a36Sopenharmony_ci * todo - what should we return here? there's no one else 244062306a36Sopenharmony_ci * even bothering to check the status. 244162306a36Sopenharmony_ci */ 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci /* DDMA IN status phase will start from StsPhseRcvd interrupt */ 244562306a36Sopenharmony_ci if (!using_desc_dma(hsotg) && epnum == 0 && 244662306a36Sopenharmony_ci hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 244762306a36Sopenharmony_ci /* Move to STATUS IN */ 244862306a36Sopenharmony_ci if (!hsotg->delayed_status) 244962306a36Sopenharmony_ci dwc2_hsotg_ep0_zlp(hsotg, true); 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci /* Set actual frame number for completed transfers */ 245362306a36Sopenharmony_ci if (!using_desc_dma(hsotg) && hs_ep->isochronous) { 245462306a36Sopenharmony_ci req->frame_number = hs_ep->target_frame; 245562306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 245662306a36Sopenharmony_ci } 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result); 245962306a36Sopenharmony_ci} 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci/** 246262306a36Sopenharmony_ci * dwc2_hsotg_handle_rx - RX FIFO has data 246362306a36Sopenharmony_ci * @hsotg: The device instance 246462306a36Sopenharmony_ci * 246562306a36Sopenharmony_ci * The IRQ handler has detected that the RX FIFO has some data in it 246662306a36Sopenharmony_ci * that requires processing, so find out what is in there and do the 246762306a36Sopenharmony_ci * appropriate read. 246862306a36Sopenharmony_ci * 246962306a36Sopenharmony_ci * The RXFIFO is a true FIFO, the packets coming out are still in packet 247062306a36Sopenharmony_ci * chunks, so if you have x packets received on an endpoint you'll get x 247162306a36Sopenharmony_ci * FIFO events delivered, each with a packet's worth of data in it. 247262306a36Sopenharmony_ci * 247362306a36Sopenharmony_ci * When using DMA, we should not be processing events from the RXFIFO 247462306a36Sopenharmony_ci * as the actual data should be sent to the memory directly and we turn 247562306a36Sopenharmony_ci * on the completion interrupts to get notifications of transfer completion. 247662306a36Sopenharmony_ci */ 247762306a36Sopenharmony_cistatic void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) 247862306a36Sopenharmony_ci{ 247962306a36Sopenharmony_ci u32 grxstsr = dwc2_readl(hsotg, GRXSTSP); 248062306a36Sopenharmony_ci u32 epnum, status, size; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci WARN_ON(using_dma(hsotg)); 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci epnum = grxstsr & GRXSTS_EPNUM_MASK; 248562306a36Sopenharmony_ci status = grxstsr & GRXSTS_PKTSTS_MASK; 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci size = grxstsr & GRXSTS_BYTECNT_MASK; 248862306a36Sopenharmony_ci size >>= GRXSTS_BYTECNT_SHIFT; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", 249162306a36Sopenharmony_ci __func__, grxstsr, size, epnum); 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { 249462306a36Sopenharmony_ci case GRXSTS_PKTSTS_GLOBALOUTNAK: 249562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GLOBALOUTNAK\n"); 249662306a36Sopenharmony_ci break; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci case GRXSTS_PKTSTS_OUTDONE: 249962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", 250062306a36Sopenharmony_ci dwc2_hsotg_read_frameno(hsotg)); 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci if (!using_dma(hsotg)) 250362306a36Sopenharmony_ci dwc2_hsotg_handle_outdone(hsotg, epnum); 250462306a36Sopenharmony_ci break; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci case GRXSTS_PKTSTS_SETUPDONE: 250762306a36Sopenharmony_ci dev_dbg(hsotg->dev, 250862306a36Sopenharmony_ci "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 250962306a36Sopenharmony_ci dwc2_hsotg_read_frameno(hsotg), 251062306a36Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL(0))); 251162306a36Sopenharmony_ci /* 251262306a36Sopenharmony_ci * Call dwc2_hsotg_handle_outdone here if it was not called from 251362306a36Sopenharmony_ci * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't 251462306a36Sopenharmony_ci * generate GRXSTS_PKTSTS_OUTDONE for setup packet. 251562306a36Sopenharmony_ci */ 251662306a36Sopenharmony_ci if (hsotg->ep0_state == DWC2_EP0_SETUP) 251762306a36Sopenharmony_ci dwc2_hsotg_handle_outdone(hsotg, epnum); 251862306a36Sopenharmony_ci break; 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci case GRXSTS_PKTSTS_OUTRX: 252162306a36Sopenharmony_ci dwc2_hsotg_rx_data(hsotg, epnum, size); 252262306a36Sopenharmony_ci break; 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci case GRXSTS_PKTSTS_SETUPRX: 252562306a36Sopenharmony_ci dev_dbg(hsotg->dev, 252662306a36Sopenharmony_ci "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", 252762306a36Sopenharmony_ci dwc2_hsotg_read_frameno(hsotg), 252862306a36Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL(0))); 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP); 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci dwc2_hsotg_rx_data(hsotg, epnum, size); 253362306a36Sopenharmony_ci break; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci default: 253662306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: unknown status %08x\n", 253762306a36Sopenharmony_ci __func__, grxstsr); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci dwc2_hsotg_dump(hsotg); 254062306a36Sopenharmony_ci break; 254162306a36Sopenharmony_ci } 254262306a36Sopenharmony_ci} 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci/** 254562306a36Sopenharmony_ci * dwc2_hsotg_ep0_mps - turn max packet size into register setting 254662306a36Sopenharmony_ci * @mps: The maximum packet size in bytes. 254762306a36Sopenharmony_ci */ 254862306a36Sopenharmony_cistatic u32 dwc2_hsotg_ep0_mps(unsigned int mps) 254962306a36Sopenharmony_ci{ 255062306a36Sopenharmony_ci switch (mps) { 255162306a36Sopenharmony_ci case 64: 255262306a36Sopenharmony_ci return D0EPCTL_MPS_64; 255362306a36Sopenharmony_ci case 32: 255462306a36Sopenharmony_ci return D0EPCTL_MPS_32; 255562306a36Sopenharmony_ci case 16: 255662306a36Sopenharmony_ci return D0EPCTL_MPS_16; 255762306a36Sopenharmony_ci case 8: 255862306a36Sopenharmony_ci return D0EPCTL_MPS_8; 255962306a36Sopenharmony_ci } 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci /* bad max packet size, warn and return invalid result */ 256262306a36Sopenharmony_ci WARN_ON(1); 256362306a36Sopenharmony_ci return (u32)-1; 256462306a36Sopenharmony_ci} 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci/** 256762306a36Sopenharmony_ci * dwc2_hsotg_set_ep_maxpacket - set endpoint's max-packet field 256862306a36Sopenharmony_ci * @hsotg: The driver state. 256962306a36Sopenharmony_ci * @ep: The index number of the endpoint 257062306a36Sopenharmony_ci * @mps: The maximum packet size in bytes 257162306a36Sopenharmony_ci * @mc: The multicount value 257262306a36Sopenharmony_ci * @dir_in: True if direction is in. 257362306a36Sopenharmony_ci * 257462306a36Sopenharmony_ci * Configure the maximum packet size for the given endpoint, updating 257562306a36Sopenharmony_ci * the hardware control registers to reflect this. 257662306a36Sopenharmony_ci */ 257762306a36Sopenharmony_cistatic void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg, 257862306a36Sopenharmony_ci unsigned int ep, unsigned int mps, 257962306a36Sopenharmony_ci unsigned int mc, unsigned int dir_in) 258062306a36Sopenharmony_ci{ 258162306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep; 258262306a36Sopenharmony_ci u32 reg; 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci hs_ep = index_to_ep(hsotg, ep, dir_in); 258562306a36Sopenharmony_ci if (!hs_ep) 258662306a36Sopenharmony_ci return; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci if (ep == 0) { 258962306a36Sopenharmony_ci u32 mps_bytes = mps; 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci /* EP0 is a special case */ 259262306a36Sopenharmony_ci mps = dwc2_hsotg_ep0_mps(mps_bytes); 259362306a36Sopenharmony_ci if (mps > 3) 259462306a36Sopenharmony_ci goto bad_mps; 259562306a36Sopenharmony_ci hs_ep->ep.maxpacket = mps_bytes; 259662306a36Sopenharmony_ci hs_ep->mc = 1; 259762306a36Sopenharmony_ci } else { 259862306a36Sopenharmony_ci if (mps > 1024) 259962306a36Sopenharmony_ci goto bad_mps; 260062306a36Sopenharmony_ci hs_ep->mc = mc; 260162306a36Sopenharmony_ci if (mc > 3) 260262306a36Sopenharmony_ci goto bad_mps; 260362306a36Sopenharmony_ci hs_ep->ep.maxpacket = mps; 260462306a36Sopenharmony_ci } 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci if (dir_in) { 260762306a36Sopenharmony_ci reg = dwc2_readl(hsotg, DIEPCTL(ep)); 260862306a36Sopenharmony_ci reg &= ~DXEPCTL_MPS_MASK; 260962306a36Sopenharmony_ci reg |= mps; 261062306a36Sopenharmony_ci dwc2_writel(hsotg, reg, DIEPCTL(ep)); 261162306a36Sopenharmony_ci } else { 261262306a36Sopenharmony_ci reg = dwc2_readl(hsotg, DOEPCTL(ep)); 261362306a36Sopenharmony_ci reg &= ~DXEPCTL_MPS_MASK; 261462306a36Sopenharmony_ci reg |= mps; 261562306a36Sopenharmony_ci dwc2_writel(hsotg, reg, DOEPCTL(ep)); 261662306a36Sopenharmony_ci } 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci return; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_cibad_mps: 262162306a36Sopenharmony_ci dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); 262262306a36Sopenharmony_ci} 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci/** 262562306a36Sopenharmony_ci * dwc2_hsotg_txfifo_flush - flush Tx FIFO 262662306a36Sopenharmony_ci * @hsotg: The driver state 262762306a36Sopenharmony_ci * @idx: The index for the endpoint (0..15) 262862306a36Sopenharmony_ci */ 262962306a36Sopenharmony_cistatic void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) 263062306a36Sopenharmony_ci{ 263162306a36Sopenharmony_ci dwc2_writel(hsotg, GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH, 263262306a36Sopenharmony_ci GRSTCTL); 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci /* wait until the fifo is flushed */ 263562306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 100)) 263662306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: timeout flushing fifo GRSTCTL_TXFFLSH\n", 263762306a36Sopenharmony_ci __func__); 263862306a36Sopenharmony_ci} 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci/** 264162306a36Sopenharmony_ci * dwc2_hsotg_trytx - check to see if anything needs transmitting 264262306a36Sopenharmony_ci * @hsotg: The driver state 264362306a36Sopenharmony_ci * @hs_ep: The driver endpoint to check. 264462306a36Sopenharmony_ci * 264562306a36Sopenharmony_ci * Check to see if there is a request that has data to send, and if so 264662306a36Sopenharmony_ci * make an attempt to write data into the FIFO. 264762306a36Sopenharmony_ci */ 264862306a36Sopenharmony_cistatic int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, 264962306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 265062306a36Sopenharmony_ci{ 265162306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req = hs_ep->req; 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci if (!hs_ep->dir_in || !hs_req) { 265462306a36Sopenharmony_ci /** 265562306a36Sopenharmony_ci * if request is not enqueued, we disable interrupts 265662306a36Sopenharmony_ci * for endpoints, excepting ep0 265762306a36Sopenharmony_ci */ 265862306a36Sopenharmony_ci if (hs_ep->index != 0) 265962306a36Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, 266062306a36Sopenharmony_ci hs_ep->dir_in, 0); 266162306a36Sopenharmony_ci return 0; 266262306a36Sopenharmony_ci } 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci if (hs_req->req.actual < hs_req->req.length) { 266562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "trying to write more for ep%d\n", 266662306a36Sopenharmony_ci hs_ep->index); 266762306a36Sopenharmony_ci return dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req); 266862306a36Sopenharmony_ci } 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci return 0; 267162306a36Sopenharmony_ci} 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci/** 267462306a36Sopenharmony_ci * dwc2_hsotg_complete_in - complete IN transfer 267562306a36Sopenharmony_ci * @hsotg: The device state. 267662306a36Sopenharmony_ci * @hs_ep: The endpoint that has just completed. 267762306a36Sopenharmony_ci * 267862306a36Sopenharmony_ci * An IN transfer has been completed, update the transfer's state and then 267962306a36Sopenharmony_ci * call the relevant completion routines. 268062306a36Sopenharmony_ci */ 268162306a36Sopenharmony_cistatic void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, 268262306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 268362306a36Sopenharmony_ci{ 268462306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req = hs_ep->req; 268562306a36Sopenharmony_ci u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index)); 268662306a36Sopenharmony_ci int size_left, size_done; 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_ci if (!hs_req) { 268962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "XferCompl but no req\n"); 269062306a36Sopenharmony_ci return; 269162306a36Sopenharmony_ci } 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci /* Finish ZLP handling for IN EP0 transactions */ 269462306a36Sopenharmony_ci if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) { 269562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "zlp packet sent\n"); 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci /* 269862306a36Sopenharmony_ci * While send zlp for DWC2_EP0_STATUS_IN EP direction was 269962306a36Sopenharmony_ci * changed to IN. Change back to complete OUT transfer request 270062306a36Sopenharmony_ci */ 270162306a36Sopenharmony_ci hs_ep->dir_in = 0; 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 270462306a36Sopenharmony_ci if (hsotg->test_mode) { 270562306a36Sopenharmony_ci int ret; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); 270862306a36Sopenharmony_ci if (ret < 0) { 270962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Invalid Test #%d\n", 271062306a36Sopenharmony_ci hsotg->test_mode); 271162306a36Sopenharmony_ci dwc2_hsotg_stall_ep0(hsotg); 271262306a36Sopenharmony_ci return; 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ci } 271562306a36Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 271662306a36Sopenharmony_ci return; 271762306a36Sopenharmony_ci } 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci /* 272062306a36Sopenharmony_ci * Calculate the size of the transfer by checking how much is left 272162306a36Sopenharmony_ci * in the endpoint size register and then working it out from 272262306a36Sopenharmony_ci * the amount we loaded for the transfer. 272362306a36Sopenharmony_ci * 272462306a36Sopenharmony_ci * We do this even for DMA, as the transfer may have incremented 272562306a36Sopenharmony_ci * past the end of the buffer (DMA transfers are always 32bit 272662306a36Sopenharmony_ci * aligned). 272762306a36Sopenharmony_ci */ 272862306a36Sopenharmony_ci if (using_desc_dma(hsotg)) { 272962306a36Sopenharmony_ci size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); 273062306a36Sopenharmony_ci if (size_left < 0) 273162306a36Sopenharmony_ci dev_err(hsotg->dev, "error parsing DDMA results %d\n", 273262306a36Sopenharmony_ci size_left); 273362306a36Sopenharmony_ci } else { 273462306a36Sopenharmony_ci size_left = DXEPTSIZ_XFERSIZE_GET(epsize); 273562306a36Sopenharmony_ci } 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci size_done = hs_ep->size_loaded - size_left; 273862306a36Sopenharmony_ci size_done += hs_ep->last_load; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci if (hs_req->req.actual != size_done) 274162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", 274262306a36Sopenharmony_ci __func__, hs_req->req.actual, size_done); 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci hs_req->req.actual = size_done; 274562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", 274662306a36Sopenharmony_ci hs_req->req.length, hs_req->req.actual, hs_req->req.zero); 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci if (!size_left && hs_req->req.actual < hs_req->req.length) { 274962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); 275062306a36Sopenharmony_ci dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, true); 275162306a36Sopenharmony_ci return; 275262306a36Sopenharmony_ci } 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci /* Zlp for all endpoints in non DDMA, for ep0 only in DATA IN stage */ 275562306a36Sopenharmony_ci if (hs_ep->send_zlp) { 275662306a36Sopenharmony_ci hs_ep->send_zlp = 0; 275762306a36Sopenharmony_ci if (!using_desc_dma(hsotg)) { 275862306a36Sopenharmony_ci dwc2_hsotg_program_zlp(hsotg, hs_ep); 275962306a36Sopenharmony_ci /* transfer will be completed on next complete interrupt */ 276062306a36Sopenharmony_ci return; 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci } 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) { 276562306a36Sopenharmony_ci /* Move to STATUS OUT */ 276662306a36Sopenharmony_ci dwc2_hsotg_ep0_zlp(hsotg, false); 276762306a36Sopenharmony_ci return; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci /* Set actual frame number for completed transfers */ 277162306a36Sopenharmony_ci if (!using_desc_dma(hsotg) && hs_ep->isochronous) { 277262306a36Sopenharmony_ci hs_req->req.frame_number = hs_ep->target_frame; 277362306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 277462306a36Sopenharmony_ci } 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); 277762306a36Sopenharmony_ci} 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci/** 278062306a36Sopenharmony_ci * dwc2_gadget_read_ep_interrupts - reads interrupts for given ep 278162306a36Sopenharmony_ci * @hsotg: The device state. 278262306a36Sopenharmony_ci * @idx: Index of ep. 278362306a36Sopenharmony_ci * @dir_in: Endpoint direction 1-in 0-out. 278462306a36Sopenharmony_ci * 278562306a36Sopenharmony_ci * Reads for endpoint with given index and direction, by masking 278662306a36Sopenharmony_ci * epint_reg with coresponding mask. 278762306a36Sopenharmony_ci */ 278862306a36Sopenharmony_cistatic u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg, 278962306a36Sopenharmony_ci unsigned int idx, int dir_in) 279062306a36Sopenharmony_ci{ 279162306a36Sopenharmony_ci u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK; 279262306a36Sopenharmony_ci u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 279362306a36Sopenharmony_ci u32 ints; 279462306a36Sopenharmony_ci u32 mask; 279562306a36Sopenharmony_ci u32 diepempmsk; 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci mask = dwc2_readl(hsotg, epmsk_reg); 279862306a36Sopenharmony_ci diepempmsk = dwc2_readl(hsotg, DIEPEMPMSK); 279962306a36Sopenharmony_ci mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0; 280062306a36Sopenharmony_ci mask |= DXEPINT_SETUP_RCVD; 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci ints = dwc2_readl(hsotg, epint_reg); 280362306a36Sopenharmony_ci ints &= mask; 280462306a36Sopenharmony_ci return ints; 280562306a36Sopenharmony_ci} 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci/** 280862306a36Sopenharmony_ci * dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD 280962306a36Sopenharmony_ci * @hs_ep: The endpoint on which interrupt is asserted. 281062306a36Sopenharmony_ci * 281162306a36Sopenharmony_ci * This interrupt indicates that the endpoint has been disabled per the 281262306a36Sopenharmony_ci * application's request. 281362306a36Sopenharmony_ci * 281462306a36Sopenharmony_ci * For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK, 281562306a36Sopenharmony_ci * in case of ISOC completes current request. 281662306a36Sopenharmony_ci * 281762306a36Sopenharmony_ci * For ISOC-OUT endpoints completes expired requests. If there is remaining 281862306a36Sopenharmony_ci * request starts it. 281962306a36Sopenharmony_ci */ 282062306a36Sopenharmony_cistatic void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep) 282162306a36Sopenharmony_ci{ 282262306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 282362306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 282462306a36Sopenharmony_ci unsigned char idx = hs_ep->index; 282562306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 282662306a36Sopenharmony_ci u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 282762306a36Sopenharmony_ci int dctl = dwc2_readl(hsotg, DCTL); 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci if (dir_in) { 283262306a36Sopenharmony_ci int epctl = dwc2_readl(hsotg, epctl_reg); 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) { 283762306a36Sopenharmony_ci int dctl = dwc2_readl(hsotg, DCTL); 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci dctl |= DCTL_CGNPINNAK; 284062306a36Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 284162306a36Sopenharmony_ci } 284262306a36Sopenharmony_ci } else { 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci if (dctl & DCTL_GOUTNAKSTS) { 284562306a36Sopenharmony_ci dctl |= DCTL_CGOUTNAK; 284662306a36Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 284762306a36Sopenharmony_ci } 284862306a36Sopenharmony_ci } 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci if (!hs_ep->isochronous) 285162306a36Sopenharmony_ci return; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci if (list_empty(&hs_ep->queue)) { 285462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n", 285562306a36Sopenharmony_ci __func__, hs_ep); 285662306a36Sopenharmony_ci return; 285762306a36Sopenharmony_ci } 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci do { 286062306a36Sopenharmony_ci hs_req = get_ep_head(hs_ep); 286162306a36Sopenharmony_ci if (hs_req) { 286262306a36Sopenharmony_ci hs_req->req.frame_number = hs_ep->target_frame; 286362306a36Sopenharmony_ci hs_req->req.actual = 0; 286462306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 286562306a36Sopenharmony_ci -ENODATA); 286662306a36Sopenharmony_ci } 286762306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 286862306a36Sopenharmony_ci /* Update current frame number value. */ 286962306a36Sopenharmony_ci hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); 287062306a36Sopenharmony_ci } while (dwc2_gadget_target_frame_elapsed(hs_ep)); 287162306a36Sopenharmony_ci} 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci/** 287462306a36Sopenharmony_ci * dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS 287562306a36Sopenharmony_ci * @ep: The endpoint on which interrupt is asserted. 287662306a36Sopenharmony_ci * 287762306a36Sopenharmony_ci * This is starting point for ISOC-OUT transfer, synchronization done with 287862306a36Sopenharmony_ci * first out token received from host while corresponding EP is disabled. 287962306a36Sopenharmony_ci * 288062306a36Sopenharmony_ci * Device does not know initial frame in which out token will come. For this 288162306a36Sopenharmony_ci * HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon 288262306a36Sopenharmony_ci * getting this interrupt SW starts calculation for next transfer frame. 288362306a36Sopenharmony_ci */ 288462306a36Sopenharmony_cistatic void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) 288562306a36Sopenharmony_ci{ 288662306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = ep->parent; 288762306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 288862306a36Sopenharmony_ci int dir_in = ep->dir_in; 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci if (dir_in || !ep->isochronous) 289162306a36Sopenharmony_ci return; 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci if (using_desc_dma(hsotg)) { 289462306a36Sopenharmony_ci if (ep->target_frame == TARGET_FRAME_INITIAL) { 289562306a36Sopenharmony_ci /* Start first ISO Out */ 289662306a36Sopenharmony_ci ep->target_frame = hsotg->frame_number; 289762306a36Sopenharmony_ci dwc2_gadget_start_isoc_ddma(ep); 289862306a36Sopenharmony_ci } 289962306a36Sopenharmony_ci return; 290062306a36Sopenharmony_ci } 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci if (ep->target_frame == TARGET_FRAME_INITIAL) { 290362306a36Sopenharmony_ci u32 ctrl; 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci ep->target_frame = hsotg->frame_number; 290662306a36Sopenharmony_ci if (ep->interval > 1) { 290762306a36Sopenharmony_ci ctrl = dwc2_readl(hsotg, DOEPCTL(ep->index)); 290862306a36Sopenharmony_ci if (ep->target_frame & 0x1) 290962306a36Sopenharmony_ci ctrl |= DXEPCTL_SETODDFR; 291062306a36Sopenharmony_ci else 291162306a36Sopenharmony_ci ctrl |= DXEPCTL_SETEVENFR; 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci dwc2_writel(hsotg, ctrl, DOEPCTL(ep->index)); 291462306a36Sopenharmony_ci } 291562306a36Sopenharmony_ci } 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci while (dwc2_gadget_target_frame_elapsed(ep)) { 291862306a36Sopenharmony_ci hs_req = get_ep_head(ep); 291962306a36Sopenharmony_ci if (hs_req) { 292062306a36Sopenharmony_ci hs_req->req.frame_number = ep->target_frame; 292162306a36Sopenharmony_ci hs_req->req.actual = 0; 292262306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, ep, hs_req, -ENODATA); 292362306a36Sopenharmony_ci } 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(ep); 292662306a36Sopenharmony_ci /* Update current frame number value. */ 292762306a36Sopenharmony_ci hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); 292862306a36Sopenharmony_ci } 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci if (!ep->req) 293162306a36Sopenharmony_ci dwc2_gadget_start_next_request(ep); 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci} 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_cistatic void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 293662306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep); 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci/** 293962306a36Sopenharmony_ci * dwc2_gadget_handle_nak - handle NAK interrupt 294062306a36Sopenharmony_ci * @hs_ep: The endpoint on which interrupt is asserted. 294162306a36Sopenharmony_ci * 294262306a36Sopenharmony_ci * This is starting point for ISOC-IN transfer, synchronization done with 294362306a36Sopenharmony_ci * first IN token received from host while corresponding EP is disabled. 294462306a36Sopenharmony_ci * 294562306a36Sopenharmony_ci * Device does not know when first one token will arrive from host. On first 294662306a36Sopenharmony_ci * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' 294762306a36Sopenharmony_ci * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was 294862306a36Sopenharmony_ci * sent in response to that as there was no data in FIFO. SW is basing on this 294962306a36Sopenharmony_ci * interrupt to obtain frame in which token has come and then based on the 295062306a36Sopenharmony_ci * interval calculates next frame for transfer. 295162306a36Sopenharmony_ci */ 295262306a36Sopenharmony_cistatic void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) 295362306a36Sopenharmony_ci{ 295462306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 295562306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req; 295662306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 295762306a36Sopenharmony_ci u32 ctrl; 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci if (!dir_in || !hs_ep->isochronous) 296062306a36Sopenharmony_ci return; 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci if (hs_ep->target_frame == TARGET_FRAME_INITIAL) { 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci if (using_desc_dma(hsotg)) { 296562306a36Sopenharmony_ci hs_ep->target_frame = hsotg->frame_number; 296662306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci /* In service interval mode target_frame must 296962306a36Sopenharmony_ci * be set to last (u)frame of the service interval. 297062306a36Sopenharmony_ci */ 297162306a36Sopenharmony_ci if (hsotg->params.service_interval) { 297262306a36Sopenharmony_ci /* Set target_frame to the first (u)frame of 297362306a36Sopenharmony_ci * the service interval 297462306a36Sopenharmony_ci */ 297562306a36Sopenharmony_ci hs_ep->target_frame &= ~hs_ep->interval + 1; 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci /* Set target_frame to the last (u)frame of 297862306a36Sopenharmony_ci * the service interval 297962306a36Sopenharmony_ci */ 298062306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 298162306a36Sopenharmony_ci dwc2_gadget_dec_frame_num_by_one(hs_ep); 298262306a36Sopenharmony_ci } 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci dwc2_gadget_start_isoc_ddma(hs_ep); 298562306a36Sopenharmony_ci return; 298662306a36Sopenharmony_ci } 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci hs_ep->target_frame = hsotg->frame_number; 298962306a36Sopenharmony_ci if (hs_ep->interval > 1) { 299062306a36Sopenharmony_ci u32 ctrl = dwc2_readl(hsotg, 299162306a36Sopenharmony_ci DIEPCTL(hs_ep->index)); 299262306a36Sopenharmony_ci if (hs_ep->target_frame & 0x1) 299362306a36Sopenharmony_ci ctrl |= DXEPCTL_SETODDFR; 299462306a36Sopenharmony_ci else 299562306a36Sopenharmony_ci ctrl |= DXEPCTL_SETEVENFR; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci dwc2_writel(hsotg, ctrl, DIEPCTL(hs_ep->index)); 299862306a36Sopenharmony_ci } 299962306a36Sopenharmony_ci } 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci if (using_desc_dma(hsotg)) 300262306a36Sopenharmony_ci return; 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci ctrl = dwc2_readl(hsotg, DIEPCTL(hs_ep->index)); 300562306a36Sopenharmony_ci if (ctrl & DXEPCTL_EPENA) 300662306a36Sopenharmony_ci dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep); 300762306a36Sopenharmony_ci else 300862306a36Sopenharmony_ci dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index); 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci while (dwc2_gadget_target_frame_elapsed(hs_ep)) { 301162306a36Sopenharmony_ci hs_req = get_ep_head(hs_ep); 301262306a36Sopenharmony_ci if (hs_req) { 301362306a36Sopenharmony_ci hs_req->req.frame_number = hs_ep->target_frame; 301462306a36Sopenharmony_ci hs_req->req.actual = 0; 301562306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ENODATA); 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci dwc2_gadget_incr_frame_num(hs_ep); 301962306a36Sopenharmony_ci /* Update current frame number value. */ 302062306a36Sopenharmony_ci hsotg->frame_number = dwc2_hsotg_read_frameno(hsotg); 302162306a36Sopenharmony_ci } 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci if (!hs_ep->req) 302462306a36Sopenharmony_ci dwc2_gadget_start_next_request(hs_ep); 302562306a36Sopenharmony_ci} 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci/** 302862306a36Sopenharmony_ci * dwc2_hsotg_epint - handle an in/out endpoint interrupt 302962306a36Sopenharmony_ci * @hsotg: The driver state 303062306a36Sopenharmony_ci * @idx: The index for the endpoint (0..15) 303162306a36Sopenharmony_ci * @dir_in: Set if this is an IN endpoint 303262306a36Sopenharmony_ci * 303362306a36Sopenharmony_ci * Process and clear any interrupt pending for an individual endpoint 303462306a36Sopenharmony_ci */ 303562306a36Sopenharmony_cistatic void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, 303662306a36Sopenharmony_ci int dir_in) 303762306a36Sopenharmony_ci{ 303862306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); 303962306a36Sopenharmony_ci u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); 304062306a36Sopenharmony_ci u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); 304162306a36Sopenharmony_ci u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); 304262306a36Sopenharmony_ci u32 ints; 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in); 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci /* Clear endpoint interrupts */ 304762306a36Sopenharmony_ci dwc2_writel(hsotg, ints, epint_reg); 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci if (!hs_ep) { 305062306a36Sopenharmony_ci dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", 305162306a36Sopenharmony_ci __func__, idx, dir_in ? "in" : "out"); 305262306a36Sopenharmony_ci return; 305362306a36Sopenharmony_ci } 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", 305662306a36Sopenharmony_ci __func__, idx, dir_in ? "in" : "out", ints); 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* Don't process XferCompl interrupt if it is a setup packet */ 305962306a36Sopenharmony_ci if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD))) 306062306a36Sopenharmony_ci ints &= ~DXEPINT_XFERCOMPL; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci /* 306362306a36Sopenharmony_ci * Don't process XferCompl interrupt in DDMA if EP0 is still in SETUP 306462306a36Sopenharmony_ci * stage and xfercomplete was generated without SETUP phase done 306562306a36Sopenharmony_ci * interrupt. SW should parse received setup packet only after host's 306662306a36Sopenharmony_ci * exit from setup phase of control transfer. 306762306a36Sopenharmony_ci */ 306862306a36Sopenharmony_ci if (using_desc_dma(hsotg) && idx == 0 && !hs_ep->dir_in && 306962306a36Sopenharmony_ci hsotg->ep0_state == DWC2_EP0_SETUP && !(ints & DXEPINT_SETUP)) 307062306a36Sopenharmony_ci ints &= ~DXEPINT_XFERCOMPL; 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci if (ints & DXEPINT_XFERCOMPL) { 307362306a36Sopenharmony_ci dev_dbg(hsotg->dev, 307462306a36Sopenharmony_ci "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n", 307562306a36Sopenharmony_ci __func__, dwc2_readl(hsotg, epctl_reg), 307662306a36Sopenharmony_ci dwc2_readl(hsotg, epsiz_reg)); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci /* In DDMA handle isochronous requests separately */ 307962306a36Sopenharmony_ci if (using_desc_dma(hsotg) && hs_ep->isochronous) { 308062306a36Sopenharmony_ci dwc2_gadget_complete_isoc_request_ddma(hs_ep); 308162306a36Sopenharmony_ci } else if (dir_in) { 308262306a36Sopenharmony_ci /* 308362306a36Sopenharmony_ci * We get OutDone from the FIFO, so we only 308462306a36Sopenharmony_ci * need to look at completing IN requests here 308562306a36Sopenharmony_ci * if operating slave mode 308662306a36Sopenharmony_ci */ 308762306a36Sopenharmony_ci if (!hs_ep->isochronous || !(ints & DXEPINT_NAKINTRPT)) 308862306a36Sopenharmony_ci dwc2_hsotg_complete_in(hsotg, hs_ep); 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci if (idx == 0 && !hs_ep->req) 309162306a36Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 309262306a36Sopenharmony_ci } else if (using_dma(hsotg)) { 309362306a36Sopenharmony_ci /* 309462306a36Sopenharmony_ci * We're using DMA, we need to fire an OutDone here 309562306a36Sopenharmony_ci * as we ignore the RXFIFO. 309662306a36Sopenharmony_ci */ 309762306a36Sopenharmony_ci if (!hs_ep->isochronous || !(ints & DXEPINT_OUTTKNEPDIS)) 309862306a36Sopenharmony_ci dwc2_hsotg_handle_outdone(hsotg, idx); 309962306a36Sopenharmony_ci } 310062306a36Sopenharmony_ci } 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_ci if (ints & DXEPINT_EPDISBLD) 310362306a36Sopenharmony_ci dwc2_gadget_handle_ep_disabled(hs_ep); 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_ci if (ints & DXEPINT_OUTTKNEPDIS) 310662306a36Sopenharmony_ci dwc2_gadget_handle_out_token_ep_disabled(hs_ep); 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci if (ints & DXEPINT_NAKINTRPT) 310962306a36Sopenharmony_ci dwc2_gadget_handle_nak(hs_ep); 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci if (ints & DXEPINT_AHBERR) 311262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci if (ints & DXEPINT_SETUP) { /* Setup or Timeout */ 311562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci if (using_dma(hsotg) && idx == 0) { 311862306a36Sopenharmony_ci /* 311962306a36Sopenharmony_ci * this is the notification we've received a 312062306a36Sopenharmony_ci * setup packet. In non-DMA mode we'd get this 312162306a36Sopenharmony_ci * from the RXFIFO, instead we need to process 312262306a36Sopenharmony_ci * the setup here. 312362306a36Sopenharmony_ci */ 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci if (dir_in) 312662306a36Sopenharmony_ci WARN_ON_ONCE(1); 312762306a36Sopenharmony_ci else 312862306a36Sopenharmony_ci dwc2_hsotg_handle_outdone(hsotg, 0); 312962306a36Sopenharmony_ci } 313062306a36Sopenharmony_ci } 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci if (ints & DXEPINT_STSPHSERCVD) { 313362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__); 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci /* Safety check EP0 state when STSPHSERCVD asserted */ 313662306a36Sopenharmony_ci if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) { 313762306a36Sopenharmony_ci /* Move to STATUS IN for DDMA */ 313862306a36Sopenharmony_ci if (using_desc_dma(hsotg)) { 313962306a36Sopenharmony_ci if (!hsotg->delayed_status) 314062306a36Sopenharmony_ci dwc2_hsotg_ep0_zlp(hsotg, true); 314162306a36Sopenharmony_ci else 314262306a36Sopenharmony_ci /* In case of 3 stage Control Write with delayed 314362306a36Sopenharmony_ci * status, when Status IN transfer started 314462306a36Sopenharmony_ci * before STSPHSERCVD asserted, NAKSTS bit not 314562306a36Sopenharmony_ci * cleared by CNAK in dwc2_hsotg_start_req() 314662306a36Sopenharmony_ci * function. Clear now NAKSTS to allow complete 314762306a36Sopenharmony_ci * transfer. 314862306a36Sopenharmony_ci */ 314962306a36Sopenharmony_ci dwc2_set_bit(hsotg, DIEPCTL(0), 315062306a36Sopenharmony_ci DXEPCTL_CNAK); 315162306a36Sopenharmony_ci } 315262306a36Sopenharmony_ci } 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci } 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci if (ints & DXEPINT_BACK2BACKSETUP) 315762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci if (ints & DXEPINT_BNAINTR) { 316062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: BNA interrupt\n", __func__); 316162306a36Sopenharmony_ci if (hs_ep->isochronous) 316262306a36Sopenharmony_ci dwc2_gadget_handle_isoc_bna(hs_ep); 316362306a36Sopenharmony_ci } 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci if (dir_in && !hs_ep->isochronous) { 316662306a36Sopenharmony_ci /* not sure if this is important, but we'll clear it anyway */ 316762306a36Sopenharmony_ci if (ints & DXEPINT_INTKNTXFEMP) { 316862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", 316962306a36Sopenharmony_ci __func__, idx); 317062306a36Sopenharmony_ci } 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci /* this probably means something bad is happening */ 317362306a36Sopenharmony_ci if (ints & DXEPINT_INTKNEPMIS) { 317462306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", 317562306a36Sopenharmony_ci __func__, idx); 317662306a36Sopenharmony_ci } 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci /* FIFO has space or is empty (see GAHBCFG) */ 317962306a36Sopenharmony_ci if (hsotg->dedicated_fifos && 318062306a36Sopenharmony_ci ints & DXEPINT_TXFEMP) { 318162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", 318262306a36Sopenharmony_ci __func__, idx); 318362306a36Sopenharmony_ci if (!using_dma(hsotg)) 318462306a36Sopenharmony_ci dwc2_hsotg_trytx(hsotg, hs_ep); 318562306a36Sopenharmony_ci } 318662306a36Sopenharmony_ci } 318762306a36Sopenharmony_ci} 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci/** 319062306a36Sopenharmony_ci * dwc2_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) 319162306a36Sopenharmony_ci * @hsotg: The device state. 319262306a36Sopenharmony_ci * 319362306a36Sopenharmony_ci * Handle updating the device settings after the enumeration phase has 319462306a36Sopenharmony_ci * been completed. 319562306a36Sopenharmony_ci */ 319662306a36Sopenharmony_cistatic void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg) 319762306a36Sopenharmony_ci{ 319862306a36Sopenharmony_ci u32 dsts = dwc2_readl(hsotg, DSTS); 319962306a36Sopenharmony_ci int ep0_mps = 0, ep_mps = 8; 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci /* 320262306a36Sopenharmony_ci * This should signal the finish of the enumeration phase 320362306a36Sopenharmony_ci * of the USB handshaking, so we should now know what rate 320462306a36Sopenharmony_ci * we connected at. 320562306a36Sopenharmony_ci */ 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci /* 321062306a36Sopenharmony_ci * note, since we're limited by the size of transfer on EP0, and 321162306a36Sopenharmony_ci * it seems IN transfers must be a even number of packets we do 321262306a36Sopenharmony_ci * not advertise a 64byte MPS on EP0. 321362306a36Sopenharmony_ci */ 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci /* catch both EnumSpd_FS and EnumSpd_FS48 */ 321662306a36Sopenharmony_ci switch ((dsts & DSTS_ENUMSPD_MASK) >> DSTS_ENUMSPD_SHIFT) { 321762306a36Sopenharmony_ci case DSTS_ENUMSPD_FS: 321862306a36Sopenharmony_ci case DSTS_ENUMSPD_FS48: 321962306a36Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_FULL; 322062306a36Sopenharmony_ci ep0_mps = EP0_MPS_LIMIT; 322162306a36Sopenharmony_ci ep_mps = 1023; 322262306a36Sopenharmony_ci break; 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci case DSTS_ENUMSPD_HS: 322562306a36Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_HIGH; 322662306a36Sopenharmony_ci ep0_mps = EP0_MPS_LIMIT; 322762306a36Sopenharmony_ci ep_mps = 1024; 322862306a36Sopenharmony_ci break; 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_ci case DSTS_ENUMSPD_LS: 323162306a36Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_LOW; 323262306a36Sopenharmony_ci ep0_mps = 8; 323362306a36Sopenharmony_ci ep_mps = 8; 323462306a36Sopenharmony_ci /* 323562306a36Sopenharmony_ci * note, we don't actually support LS in this driver at the 323662306a36Sopenharmony_ci * moment, and the documentation seems to imply that it isn't 323762306a36Sopenharmony_ci * supported by the PHYs on some of the devices. 323862306a36Sopenharmony_ci */ 323962306a36Sopenharmony_ci break; 324062306a36Sopenharmony_ci } 324162306a36Sopenharmony_ci dev_info(hsotg->dev, "new device is %s\n", 324262306a36Sopenharmony_ci usb_speed_string(hsotg->gadget.speed)); 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci /* 324562306a36Sopenharmony_ci * we should now know the maximum packet size for an 324662306a36Sopenharmony_ci * endpoint, so set the endpoints to a default value. 324762306a36Sopenharmony_ci */ 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci if (ep0_mps) { 325062306a36Sopenharmony_ci int i; 325162306a36Sopenharmony_ci /* Initialize ep0 for both in and out directions */ 325262306a36Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 1); 325362306a36Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0, 0); 325462306a36Sopenharmony_ci for (i = 1; i < hsotg->num_of_eps; i++) { 325562306a36Sopenharmony_ci if (hsotg->eps_in[i]) 325662306a36Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 325762306a36Sopenharmony_ci 0, 1); 325862306a36Sopenharmony_ci if (hsotg->eps_out[i]) 325962306a36Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 326062306a36Sopenharmony_ci 0, 0); 326162306a36Sopenharmony_ci } 326262306a36Sopenharmony_ci } 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci /* ensure after enumeration our EP0 is active */ 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 326962306a36Sopenharmony_ci dwc2_readl(hsotg, DIEPCTL0), 327062306a36Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL0)); 327162306a36Sopenharmony_ci} 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci/** 327462306a36Sopenharmony_ci * kill_all_requests - remove all requests from the endpoint's queue 327562306a36Sopenharmony_ci * @hsotg: The device state. 327662306a36Sopenharmony_ci * @ep: The endpoint the requests may be on. 327762306a36Sopenharmony_ci * @result: The result code to use. 327862306a36Sopenharmony_ci * 327962306a36Sopenharmony_ci * Go through the requests on the given endpoint and mark them 328062306a36Sopenharmony_ci * completed with the given result code. 328162306a36Sopenharmony_ci */ 328262306a36Sopenharmony_cistatic void kill_all_requests(struct dwc2_hsotg *hsotg, 328362306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep, 328462306a36Sopenharmony_ci int result) 328562306a36Sopenharmony_ci{ 328662306a36Sopenharmony_ci unsigned int size; 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci ep->req = NULL; 328962306a36Sopenharmony_ci 329062306a36Sopenharmony_ci while (!list_empty(&ep->queue)) { 329162306a36Sopenharmony_ci struct dwc2_hsotg_req *req = get_ep_head(ep); 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_ci dwc2_hsotg_complete_request(hsotg, ep, req, result); 329462306a36Sopenharmony_ci } 329562306a36Sopenharmony_ci 329662306a36Sopenharmony_ci if (!hsotg->dedicated_fifos) 329762306a36Sopenharmony_ci return; 329862306a36Sopenharmony_ci size = (dwc2_readl(hsotg, DTXFSTS(ep->fifo_index)) & 0xffff) * 4; 329962306a36Sopenharmony_ci if (size < ep->fifo_size) 330062306a36Sopenharmony_ci dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); 330162306a36Sopenharmony_ci} 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci/** 330462306a36Sopenharmony_ci * dwc2_hsotg_disconnect - disconnect service 330562306a36Sopenharmony_ci * @hsotg: The device state. 330662306a36Sopenharmony_ci * 330762306a36Sopenharmony_ci * The device has been disconnected. Remove all current 330862306a36Sopenharmony_ci * transactions and signal the gadget driver that this 330962306a36Sopenharmony_ci * has happened. 331062306a36Sopenharmony_ci */ 331162306a36Sopenharmony_civoid dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) 331262306a36Sopenharmony_ci{ 331362306a36Sopenharmony_ci unsigned int ep; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci if (!hsotg->connected) 331662306a36Sopenharmony_ci return; 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci hsotg->connected = 0; 331962306a36Sopenharmony_ci hsotg->test_mode = 0; 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci /* all endpoints should be shutdown */ 332262306a36Sopenharmony_ci for (ep = 0; ep < hsotg->num_of_eps; ep++) { 332362306a36Sopenharmony_ci if (hsotg->eps_in[ep]) 332462306a36Sopenharmony_ci kill_all_requests(hsotg, hsotg->eps_in[ep], 332562306a36Sopenharmony_ci -ESHUTDOWN); 332662306a36Sopenharmony_ci if (hsotg->eps_out[ep]) 332762306a36Sopenharmony_ci kill_all_requests(hsotg, hsotg->eps_out[ep], 332862306a36Sopenharmony_ci -ESHUTDOWN); 332962306a36Sopenharmony_ci } 333062306a36Sopenharmony_ci 333162306a36Sopenharmony_ci call_gadget(hsotg, disconnect); 333262306a36Sopenharmony_ci hsotg->lx_state = DWC2_L3; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci usb_gadget_set_state(&hsotg->gadget, USB_STATE_NOTATTACHED); 333562306a36Sopenharmony_ci} 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci/** 333862306a36Sopenharmony_ci * dwc2_hsotg_irq_fifoempty - TX FIFO empty interrupt handler 333962306a36Sopenharmony_ci * @hsotg: The device state: 334062306a36Sopenharmony_ci * @periodic: True if this is a periodic FIFO interrupt 334162306a36Sopenharmony_ci */ 334262306a36Sopenharmony_cistatic void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) 334362306a36Sopenharmony_ci{ 334462306a36Sopenharmony_ci struct dwc2_hsotg_ep *ep; 334562306a36Sopenharmony_ci int epno, ret; 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci /* look through for any more data to transmit */ 334862306a36Sopenharmony_ci for (epno = 0; epno < hsotg->num_of_eps; epno++) { 334962306a36Sopenharmony_ci ep = index_to_ep(hsotg, epno, 1); 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci if (!ep) 335262306a36Sopenharmony_ci continue; 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci if (!ep->dir_in) 335562306a36Sopenharmony_ci continue; 335662306a36Sopenharmony_ci 335762306a36Sopenharmony_ci if ((periodic && !ep->periodic) || 335862306a36Sopenharmony_ci (!periodic && ep->periodic)) 335962306a36Sopenharmony_ci continue; 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci ret = dwc2_hsotg_trytx(hsotg, ep); 336262306a36Sopenharmony_ci if (ret < 0) 336362306a36Sopenharmony_ci break; 336462306a36Sopenharmony_ci } 336562306a36Sopenharmony_ci} 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_ci/* IRQ flags which will trigger a retry around the IRQ loop */ 336862306a36Sopenharmony_ci#define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ 336962306a36Sopenharmony_ci GINTSTS_PTXFEMP | \ 337062306a36Sopenharmony_ci GINTSTS_RXFLVL) 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_cistatic int dwc2_hsotg_ep_disable(struct usb_ep *ep); 337362306a36Sopenharmony_ci/** 337462306a36Sopenharmony_ci * dwc2_hsotg_core_init_disconnected - issue softreset to the core 337562306a36Sopenharmony_ci * @hsotg: The device state 337662306a36Sopenharmony_ci * @is_usb_reset: Usb resetting flag 337762306a36Sopenharmony_ci * 337862306a36Sopenharmony_ci * Issue a soft reset to the core, and await the core finishing it. 337962306a36Sopenharmony_ci */ 338062306a36Sopenharmony_civoid dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, 338162306a36Sopenharmony_ci bool is_usb_reset) 338262306a36Sopenharmony_ci{ 338362306a36Sopenharmony_ci u32 intmsk; 338462306a36Sopenharmony_ci u32 val; 338562306a36Sopenharmony_ci u32 usbcfg; 338662306a36Sopenharmony_ci u32 dcfg = 0; 338762306a36Sopenharmony_ci int ep; 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci /* Kill any ep0 requests as controller will be reinitialized */ 339062306a36Sopenharmony_ci kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci if (!is_usb_reset) { 339362306a36Sopenharmony_ci if (dwc2_core_reset(hsotg, true)) 339462306a36Sopenharmony_ci return; 339562306a36Sopenharmony_ci } else { 339662306a36Sopenharmony_ci /* all endpoints should be shutdown */ 339762306a36Sopenharmony_ci for (ep = 1; ep < hsotg->num_of_eps; ep++) { 339862306a36Sopenharmony_ci if (hsotg->eps_in[ep]) 339962306a36Sopenharmony_ci dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); 340062306a36Sopenharmony_ci if (hsotg->eps_out[ep]) 340162306a36Sopenharmony_ci dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); 340262306a36Sopenharmony_ci } 340362306a36Sopenharmony_ci } 340462306a36Sopenharmony_ci 340562306a36Sopenharmony_ci /* 340662306a36Sopenharmony_ci * we must now enable ep0 ready for host detection and then 340762306a36Sopenharmony_ci * set configuration. 340862306a36Sopenharmony_ci */ 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci /* keep other bits untouched (so e.g. forced modes are not lost) */ 341162306a36Sopenharmony_ci usbcfg = dwc2_readl(hsotg, GUSBCFG); 341262306a36Sopenharmony_ci usbcfg &= ~GUSBCFG_TOUTCAL_MASK; 341362306a36Sopenharmony_ci usbcfg |= GUSBCFG_TOUTCAL(7); 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci /* remove the HNP/SRP and set the PHY */ 341662306a36Sopenharmony_ci usbcfg &= ~(GUSBCFG_SRPCAP | GUSBCFG_HNPCAP); 341762306a36Sopenharmony_ci dwc2_writel(hsotg, usbcfg, GUSBCFG); 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci dwc2_phy_init(hsotg, true); 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci dwc2_hsotg_init_fifo(hsotg); 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci if (!is_usb_reset) 342462306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 342562306a36Sopenharmony_ci 342662306a36Sopenharmony_ci dcfg |= DCFG_EPMISCNT(1); 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci switch (hsotg->params.speed) { 342962306a36Sopenharmony_ci case DWC2_SPEED_PARAM_LOW: 343062306a36Sopenharmony_ci dcfg |= DCFG_DEVSPD_LS; 343162306a36Sopenharmony_ci break; 343262306a36Sopenharmony_ci case DWC2_SPEED_PARAM_FULL: 343362306a36Sopenharmony_ci if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) 343462306a36Sopenharmony_ci dcfg |= DCFG_DEVSPD_FS48; 343562306a36Sopenharmony_ci else 343662306a36Sopenharmony_ci dcfg |= DCFG_DEVSPD_FS; 343762306a36Sopenharmony_ci break; 343862306a36Sopenharmony_ci default: 343962306a36Sopenharmony_ci dcfg |= DCFG_DEVSPD_HS; 344062306a36Sopenharmony_ci } 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_ci if (hsotg->params.ipg_isoc_en) 344362306a36Sopenharmony_ci dcfg |= DCFG_IPG_ISOC_SUPPORDED; 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci dwc2_writel(hsotg, dcfg, DCFG); 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci /* Clear any pending OTG interrupts */ 344862306a36Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GOTGINT); 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci /* Clear any pending interrupts */ 345162306a36Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 345262306a36Sopenharmony_ci intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | 345362306a36Sopenharmony_ci GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | 345462306a36Sopenharmony_ci GINTSTS_USBRST | GINTSTS_RESETDET | 345562306a36Sopenharmony_ci GINTSTS_ENUMDONE | GINTSTS_OTGINT | 345662306a36Sopenharmony_ci GINTSTS_USBSUSP | GINTSTS_WKUPINT | 345762306a36Sopenharmony_ci GINTSTS_LPMTRANRCVD; 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ci if (!using_desc_dma(hsotg)) 346062306a36Sopenharmony_ci intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci if (!hsotg->params.external_id_pin_ctl) 346362306a36Sopenharmony_ci intmsk |= GINTSTS_CONIDSTSCHNG; 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci dwc2_writel(hsotg, intmsk, GINTMSK); 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci if (using_dma(hsotg)) { 346862306a36Sopenharmony_ci dwc2_writel(hsotg, GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | 346962306a36Sopenharmony_ci hsotg->params.ahbcfg, 347062306a36Sopenharmony_ci GAHBCFG); 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci /* Set DDMA mode support in the core if needed */ 347362306a36Sopenharmony_ci if (using_desc_dma(hsotg)) 347462306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCFG, DCFG_DESCDMA_EN); 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci } else { 347762306a36Sopenharmony_ci dwc2_writel(hsotg, ((hsotg->dedicated_fifos) ? 347862306a36Sopenharmony_ci (GAHBCFG_NP_TXF_EMP_LVL | 347962306a36Sopenharmony_ci GAHBCFG_P_TXF_EMP_LVL) : 0) | 348062306a36Sopenharmony_ci GAHBCFG_GLBL_INTR_EN, GAHBCFG); 348162306a36Sopenharmony_ci } 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci /* 348462306a36Sopenharmony_ci * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts 348562306a36Sopenharmony_ci * when we have no data to transfer. Otherwise we get being flooded by 348662306a36Sopenharmony_ci * interrupts. 348762306a36Sopenharmony_ci */ 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci dwc2_writel(hsotg, ((hsotg->dedicated_fifos && !using_dma(hsotg)) ? 349062306a36Sopenharmony_ci DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) | 349162306a36Sopenharmony_ci DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | 349262306a36Sopenharmony_ci DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK, 349362306a36Sopenharmony_ci DIEPMSK); 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_ci /* 349662306a36Sopenharmony_ci * don't need XferCompl, we get that from RXFIFO in slave mode. In 349762306a36Sopenharmony_ci * DMA mode we may need this and StsPhseRcvd. 349862306a36Sopenharmony_ci */ 349962306a36Sopenharmony_ci dwc2_writel(hsotg, (using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | 350062306a36Sopenharmony_ci DOEPMSK_STSPHSERCVDMSK) : 0) | 350162306a36Sopenharmony_ci DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | 350262306a36Sopenharmony_ci DOEPMSK_SETUPMSK, 350362306a36Sopenharmony_ci DOEPMSK); 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci /* Enable BNA interrupt for DDMA */ 350662306a36Sopenharmony_ci if (using_desc_dma(hsotg)) { 350762306a36Sopenharmony_ci dwc2_set_bit(hsotg, DOEPMSK, DOEPMSK_BNAMSK); 350862306a36Sopenharmony_ci dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK); 350962306a36Sopenharmony_ci } 351062306a36Sopenharmony_ci 351162306a36Sopenharmony_ci /* Enable Service Interval mode if supported */ 351262306a36Sopenharmony_ci if (using_desc_dma(hsotg) && hsotg->params.service_interval) 351362306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SERVICE_INTERVAL_SUPPORTED); 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci dwc2_writel(hsotg, 0, DAINTMSK); 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 351862306a36Sopenharmony_ci dwc2_readl(hsotg, DIEPCTL0), 351962306a36Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL0)); 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci /* enable in and out endpoint interrupts */ 352262306a36Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT); 352362306a36Sopenharmony_ci 352462306a36Sopenharmony_ci /* 352562306a36Sopenharmony_ci * Enable the RXFIFO when in slave mode, as this is how we collect 352662306a36Sopenharmony_ci * the data. In DMA mode, we get events from the FIFO but also 352762306a36Sopenharmony_ci * things we cannot process, so do not use it. 352862306a36Sopenharmony_ci */ 352962306a36Sopenharmony_ci if (!using_dma(hsotg)) 353062306a36Sopenharmony_ci dwc2_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL); 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_ci /* Enable interrupts for EP0 in and out */ 353362306a36Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, 0, 0, 1); 353462306a36Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1); 353562306a36Sopenharmony_ci 353662306a36Sopenharmony_ci if (!is_usb_reset) { 353762306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_PWRONPRGDONE); 353862306a36Sopenharmony_ci udelay(10); /* see openiboot */ 353962306a36Sopenharmony_ci dwc2_clear_bit(hsotg, DCTL, DCTL_PWRONPRGDONE); 354062306a36Sopenharmony_ci } 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg, DCTL)); 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_ci /* 354562306a36Sopenharmony_ci * DxEPCTL_USBActEp says RO in manual, but seems to be set by 354662306a36Sopenharmony_ci * writing to the EPCTL register.. 354762306a36Sopenharmony_ci */ 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci /* set to read 1 8byte packet */ 355062306a36Sopenharmony_ci dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | 355162306a36Sopenharmony_ci DXEPTSIZ_XFERSIZE(8), DOEPTSIZ0); 355262306a36Sopenharmony_ci 355362306a36Sopenharmony_ci dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 355462306a36Sopenharmony_ci DXEPCTL_CNAK | DXEPCTL_EPENA | 355562306a36Sopenharmony_ci DXEPCTL_USBACTEP, 355662306a36Sopenharmony_ci DOEPCTL0); 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci /* enable, but don't activate EP0in */ 355962306a36Sopenharmony_ci dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) | 356062306a36Sopenharmony_ci DXEPCTL_USBACTEP, DIEPCTL0); 356162306a36Sopenharmony_ci 356262306a36Sopenharmony_ci /* clear global NAKs */ 356362306a36Sopenharmony_ci val = DCTL_CGOUTNAK | DCTL_CGNPINNAK; 356462306a36Sopenharmony_ci if (!is_usb_reset) 356562306a36Sopenharmony_ci val |= DCTL_SFTDISCON; 356662306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, val); 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci /* configure the core to support LPM */ 356962306a36Sopenharmony_ci dwc2_gadget_init_lpm(hsotg); 357062306a36Sopenharmony_ci 357162306a36Sopenharmony_ci /* program GREFCLK register if needed */ 357262306a36Sopenharmony_ci if (using_desc_dma(hsotg) && hsotg->params.service_interval) 357362306a36Sopenharmony_ci dwc2_gadget_program_ref_clk(hsotg); 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci /* must be at-least 3ms to allow bus to see disconnect */ 357662306a36Sopenharmony_ci mdelay(3); 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_ci hsotg->lx_state = DWC2_L0; 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_ci dwc2_hsotg_enqueue_setup(hsotg); 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", 358362306a36Sopenharmony_ci dwc2_readl(hsotg, DIEPCTL0), 358462306a36Sopenharmony_ci dwc2_readl(hsotg, DOEPCTL0)); 358562306a36Sopenharmony_ci} 358662306a36Sopenharmony_ci 358762306a36Sopenharmony_civoid dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) 358862306a36Sopenharmony_ci{ 358962306a36Sopenharmony_ci /* set the soft-disconnect bit */ 359062306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 359162306a36Sopenharmony_ci} 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_civoid dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) 359462306a36Sopenharmony_ci{ 359562306a36Sopenharmony_ci /* remove the soft-disconnect and let's go */ 359662306a36Sopenharmony_ci if (!hsotg->role_sw || (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_BSESVLD)) 359762306a36Sopenharmony_ci dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); 359862306a36Sopenharmony_ci} 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci/** 360162306a36Sopenharmony_ci * dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt. 360262306a36Sopenharmony_ci * @hsotg: The device state: 360362306a36Sopenharmony_ci * 360462306a36Sopenharmony_ci * This interrupt indicates one of the following conditions occurred while 360562306a36Sopenharmony_ci * transmitting an ISOC transaction. 360662306a36Sopenharmony_ci * - Corrupted IN Token for ISOC EP. 360762306a36Sopenharmony_ci * - Packet not complete in FIFO. 360862306a36Sopenharmony_ci * 360962306a36Sopenharmony_ci * The following actions will be taken: 361062306a36Sopenharmony_ci * - Determine the EP 361162306a36Sopenharmony_ci * - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO 361262306a36Sopenharmony_ci */ 361362306a36Sopenharmony_cistatic void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg) 361462306a36Sopenharmony_ci{ 361562306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep; 361662306a36Sopenharmony_ci u32 epctrl; 361762306a36Sopenharmony_ci u32 daintmsk; 361862306a36Sopenharmony_ci u32 idx; 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n"); 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci daintmsk = dwc2_readl(hsotg, DAINTMSK); 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci for (idx = 1; idx < hsotg->num_of_eps; idx++) { 362562306a36Sopenharmony_ci hs_ep = hsotg->eps_in[idx]; 362662306a36Sopenharmony_ci /* Proceed only unmasked ISOC EPs */ 362762306a36Sopenharmony_ci if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) 362862306a36Sopenharmony_ci continue; 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci epctrl = dwc2_readl(hsotg, DIEPCTL(idx)); 363162306a36Sopenharmony_ci if ((epctrl & DXEPCTL_EPENA) && 363262306a36Sopenharmony_ci dwc2_gadget_target_frame_elapsed(hs_ep)) { 363362306a36Sopenharmony_ci epctrl |= DXEPCTL_SNAK; 363462306a36Sopenharmony_ci epctrl |= DXEPCTL_EPDIS; 363562306a36Sopenharmony_ci dwc2_writel(hsotg, epctrl, DIEPCTL(idx)); 363662306a36Sopenharmony_ci } 363762306a36Sopenharmony_ci } 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci /* Clear interrupt */ 364062306a36Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_INCOMPL_SOIN, GINTSTS); 364162306a36Sopenharmony_ci} 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci/** 364462306a36Sopenharmony_ci * dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt 364562306a36Sopenharmony_ci * @hsotg: The device state: 364662306a36Sopenharmony_ci * 364762306a36Sopenharmony_ci * This interrupt indicates one of the following conditions occurred while 364862306a36Sopenharmony_ci * transmitting an ISOC transaction. 364962306a36Sopenharmony_ci * - Corrupted OUT Token for ISOC EP. 365062306a36Sopenharmony_ci * - Packet not complete in FIFO. 365162306a36Sopenharmony_ci * 365262306a36Sopenharmony_ci * The following actions will be taken: 365362306a36Sopenharmony_ci * - Determine the EP 365462306a36Sopenharmony_ci * - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed. 365562306a36Sopenharmony_ci */ 365662306a36Sopenharmony_cistatic void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg) 365762306a36Sopenharmony_ci{ 365862306a36Sopenharmony_ci u32 gintsts; 365962306a36Sopenharmony_ci u32 gintmsk; 366062306a36Sopenharmony_ci u32 daintmsk; 366162306a36Sopenharmony_ci u32 epctrl; 366262306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep; 366362306a36Sopenharmony_ci int idx; 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__); 366662306a36Sopenharmony_ci 366762306a36Sopenharmony_ci daintmsk = dwc2_readl(hsotg, DAINTMSK); 366862306a36Sopenharmony_ci daintmsk >>= DAINT_OUTEP_SHIFT; 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_ci for (idx = 1; idx < hsotg->num_of_eps; idx++) { 367162306a36Sopenharmony_ci hs_ep = hsotg->eps_out[idx]; 367262306a36Sopenharmony_ci /* Proceed only unmasked ISOC EPs */ 367362306a36Sopenharmony_ci if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous) 367462306a36Sopenharmony_ci continue; 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ci epctrl = dwc2_readl(hsotg, DOEPCTL(idx)); 367762306a36Sopenharmony_ci if ((epctrl & DXEPCTL_EPENA) && 367862306a36Sopenharmony_ci dwc2_gadget_target_frame_elapsed(hs_ep)) { 367962306a36Sopenharmony_ci /* Unmask GOUTNAKEFF interrupt */ 368062306a36Sopenharmony_ci gintmsk = dwc2_readl(hsotg, GINTMSK); 368162306a36Sopenharmony_ci gintmsk |= GINTSTS_GOUTNAKEFF; 368262306a36Sopenharmony_ci dwc2_writel(hsotg, gintmsk, GINTMSK); 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ci gintsts = dwc2_readl(hsotg, GINTSTS); 368562306a36Sopenharmony_ci if (!(gintsts & GINTSTS_GOUTNAKEFF)) { 368662306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK); 368762306a36Sopenharmony_ci break; 368862306a36Sopenharmony_ci } 368962306a36Sopenharmony_ci } 369062306a36Sopenharmony_ci } 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci /* Clear interrupt */ 369362306a36Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_INCOMPL_SOOUT, GINTSTS); 369462306a36Sopenharmony_ci} 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci/** 369762306a36Sopenharmony_ci * dwc2_hsotg_irq - handle device interrupt 369862306a36Sopenharmony_ci * @irq: The IRQ number triggered 369962306a36Sopenharmony_ci * @pw: The pw value when registered the handler. 370062306a36Sopenharmony_ci */ 370162306a36Sopenharmony_cistatic irqreturn_t dwc2_hsotg_irq(int irq, void *pw) 370262306a36Sopenharmony_ci{ 370362306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = pw; 370462306a36Sopenharmony_ci int retry_count = 8; 370562306a36Sopenharmony_ci u32 gintsts; 370662306a36Sopenharmony_ci u32 gintmsk; 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci if (!dwc2_is_device_mode(hsotg)) 370962306a36Sopenharmony_ci return IRQ_NONE; 371062306a36Sopenharmony_ci 371162306a36Sopenharmony_ci spin_lock(&hsotg->lock); 371262306a36Sopenharmony_ciirq_retry: 371362306a36Sopenharmony_ci gintsts = dwc2_readl(hsotg, GINTSTS); 371462306a36Sopenharmony_ci gintmsk = dwc2_readl(hsotg, GINTMSK); 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", 371762306a36Sopenharmony_ci __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_ci gintsts &= gintmsk; 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci if (gintsts & GINTSTS_RESETDET) { 372262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__); 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS); 372562306a36Sopenharmony_ci 372662306a36Sopenharmony_ci /* This event must be used only if controller is suspended */ 372762306a36Sopenharmony_ci if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2) 372862306a36Sopenharmony_ci dwc2_exit_partial_power_down(hsotg, 0, true); 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci hsotg->lx_state = DWC2_L0; 373162306a36Sopenharmony_ci } 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { 373462306a36Sopenharmony_ci u32 usb_status = dwc2_readl(hsotg, GOTGCTL); 373562306a36Sopenharmony_ci u32 connected = hsotg->connected; 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: USBRst\n", __func__); 373862306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", 373962306a36Sopenharmony_ci dwc2_readl(hsotg, GNPTXSTS)); 374062306a36Sopenharmony_ci 374162306a36Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_USBRST, GINTSTS); 374262306a36Sopenharmony_ci 374362306a36Sopenharmony_ci /* Report disconnection if it is not already done. */ 374462306a36Sopenharmony_ci dwc2_hsotg_disconnect(hsotg); 374562306a36Sopenharmony_ci 374662306a36Sopenharmony_ci /* Reset device address to zero */ 374762306a36Sopenharmony_ci dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK); 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_ci if (usb_status & GOTGCTL_BSESVLD && connected) 375062306a36Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, true); 375162306a36Sopenharmony_ci } 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci if (gintsts & GINTSTS_ENUMDONE) { 375462306a36Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_ENUMDONE, GINTSTS); 375562306a36Sopenharmony_ci 375662306a36Sopenharmony_ci dwc2_hsotg_irq_enumdone(hsotg); 375762306a36Sopenharmony_ci } 375862306a36Sopenharmony_ci 375962306a36Sopenharmony_ci if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) { 376062306a36Sopenharmony_ci u32 daint = dwc2_readl(hsotg, DAINT); 376162306a36Sopenharmony_ci u32 daintmsk = dwc2_readl(hsotg, DAINTMSK); 376262306a36Sopenharmony_ci u32 daint_out, daint_in; 376362306a36Sopenharmony_ci int ep; 376462306a36Sopenharmony_ci 376562306a36Sopenharmony_ci daint &= daintmsk; 376662306a36Sopenharmony_ci daint_out = daint >> DAINT_OUTEP_SHIFT; 376762306a36Sopenharmony_ci daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); 377062306a36Sopenharmony_ci 377162306a36Sopenharmony_ci for (ep = 0; ep < hsotg->num_of_eps && daint_out; 377262306a36Sopenharmony_ci ep++, daint_out >>= 1) { 377362306a36Sopenharmony_ci if (daint_out & 1) 377462306a36Sopenharmony_ci dwc2_hsotg_epint(hsotg, ep, 0); 377562306a36Sopenharmony_ci } 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci for (ep = 0; ep < hsotg->num_of_eps && daint_in; 377862306a36Sopenharmony_ci ep++, daint_in >>= 1) { 377962306a36Sopenharmony_ci if (daint_in & 1) 378062306a36Sopenharmony_ci dwc2_hsotg_epint(hsotg, ep, 1); 378162306a36Sopenharmony_ci } 378262306a36Sopenharmony_ci } 378362306a36Sopenharmony_ci 378462306a36Sopenharmony_ci /* check both FIFOs */ 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci if (gintsts & GINTSTS_NPTXFEMP) { 378762306a36Sopenharmony_ci dev_dbg(hsotg->dev, "NPTxFEmp\n"); 378862306a36Sopenharmony_ci 378962306a36Sopenharmony_ci /* 379062306a36Sopenharmony_ci * Disable the interrupt to stop it happening again 379162306a36Sopenharmony_ci * unless one of these endpoint routines decides that 379262306a36Sopenharmony_ci * it needs re-enabling 379362306a36Sopenharmony_ci */ 379462306a36Sopenharmony_ci 379562306a36Sopenharmony_ci dwc2_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP); 379662306a36Sopenharmony_ci dwc2_hsotg_irq_fifoempty(hsotg, false); 379762306a36Sopenharmony_ci } 379862306a36Sopenharmony_ci 379962306a36Sopenharmony_ci if (gintsts & GINTSTS_PTXFEMP) { 380062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "PTxFEmp\n"); 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci /* See note in GINTSTS_NPTxFEmp */ 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci dwc2_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP); 380562306a36Sopenharmony_ci dwc2_hsotg_irq_fifoempty(hsotg, true); 380662306a36Sopenharmony_ci } 380762306a36Sopenharmony_ci 380862306a36Sopenharmony_ci if (gintsts & GINTSTS_RXFLVL) { 380962306a36Sopenharmony_ci /* 381062306a36Sopenharmony_ci * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, 381162306a36Sopenharmony_ci * we need to retry dwc2_hsotg_handle_rx if this is still 381262306a36Sopenharmony_ci * set. 381362306a36Sopenharmony_ci */ 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci dwc2_hsotg_handle_rx(hsotg); 381662306a36Sopenharmony_ci } 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_ci if (gintsts & GINTSTS_ERLYSUSP) { 381962306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); 382062306a36Sopenharmony_ci dwc2_writel(hsotg, GINTSTS_ERLYSUSP, GINTSTS); 382162306a36Sopenharmony_ci } 382262306a36Sopenharmony_ci 382362306a36Sopenharmony_ci /* 382462306a36Sopenharmony_ci * these next two seem to crop-up occasionally causing the core 382562306a36Sopenharmony_ci * to shutdown the USB transfer, so try clearing them and logging 382662306a36Sopenharmony_ci * the occurrence. 382762306a36Sopenharmony_ci */ 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_ci if (gintsts & GINTSTS_GOUTNAKEFF) { 383062306a36Sopenharmony_ci u8 idx; 383162306a36Sopenharmony_ci u32 epctrl; 383262306a36Sopenharmony_ci u32 gintmsk; 383362306a36Sopenharmony_ci u32 daintmsk; 383462306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep; 383562306a36Sopenharmony_ci 383662306a36Sopenharmony_ci daintmsk = dwc2_readl(hsotg, DAINTMSK); 383762306a36Sopenharmony_ci daintmsk >>= DAINT_OUTEP_SHIFT; 383862306a36Sopenharmony_ci /* Mask this interrupt */ 383962306a36Sopenharmony_ci gintmsk = dwc2_readl(hsotg, GINTMSK); 384062306a36Sopenharmony_ci gintmsk &= ~GINTSTS_GOUTNAKEFF; 384162306a36Sopenharmony_ci dwc2_writel(hsotg, gintmsk, GINTMSK); 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GOUTNakEff triggered\n"); 384462306a36Sopenharmony_ci for (idx = 1; idx < hsotg->num_of_eps; idx++) { 384562306a36Sopenharmony_ci hs_ep = hsotg->eps_out[idx]; 384662306a36Sopenharmony_ci /* Proceed only unmasked ISOC EPs */ 384762306a36Sopenharmony_ci if (BIT(idx) & ~daintmsk) 384862306a36Sopenharmony_ci continue; 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci epctrl = dwc2_readl(hsotg, DOEPCTL(idx)); 385162306a36Sopenharmony_ci 385262306a36Sopenharmony_ci //ISOC Ep's only 385362306a36Sopenharmony_ci if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) { 385462306a36Sopenharmony_ci epctrl |= DXEPCTL_SNAK; 385562306a36Sopenharmony_ci epctrl |= DXEPCTL_EPDIS; 385662306a36Sopenharmony_ci dwc2_writel(hsotg, epctrl, DOEPCTL(idx)); 385762306a36Sopenharmony_ci continue; 385862306a36Sopenharmony_ci } 385962306a36Sopenharmony_ci 386062306a36Sopenharmony_ci //Non-ISOC EP's 386162306a36Sopenharmony_ci if (hs_ep->halted) { 386262306a36Sopenharmony_ci if (!(epctrl & DXEPCTL_EPENA)) 386362306a36Sopenharmony_ci epctrl |= DXEPCTL_EPENA; 386462306a36Sopenharmony_ci epctrl |= DXEPCTL_EPDIS; 386562306a36Sopenharmony_ci epctrl |= DXEPCTL_STALL; 386662306a36Sopenharmony_ci dwc2_writel(hsotg, epctrl, DOEPCTL(idx)); 386762306a36Sopenharmony_ci } 386862306a36Sopenharmony_ci } 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci /* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */ 387162306a36Sopenharmony_ci } 387262306a36Sopenharmony_ci 387362306a36Sopenharmony_ci if (gintsts & GINTSTS_GINNAKEFF) { 387462306a36Sopenharmony_ci dev_info(hsotg->dev, "GINNakEff triggered\n"); 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK); 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_ci dwc2_hsotg_dump(hsotg); 387962306a36Sopenharmony_ci } 388062306a36Sopenharmony_ci 388162306a36Sopenharmony_ci if (gintsts & GINTSTS_INCOMPL_SOIN) 388262306a36Sopenharmony_ci dwc2_gadget_handle_incomplete_isoc_in(hsotg); 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci if (gintsts & GINTSTS_INCOMPL_SOOUT) 388562306a36Sopenharmony_ci dwc2_gadget_handle_incomplete_isoc_out(hsotg); 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci /* 388862306a36Sopenharmony_ci * if we've had fifo events, we should try and go around the 388962306a36Sopenharmony_ci * loop again to see if there's any point in returning yet. 389062306a36Sopenharmony_ci */ 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_ci if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) 389362306a36Sopenharmony_ci goto irq_retry; 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci /* Check WKUP_ALERT interrupt*/ 389662306a36Sopenharmony_ci if (hsotg->params.service_interval) 389762306a36Sopenharmony_ci dwc2_gadget_wkup_alert_handler(hsotg); 389862306a36Sopenharmony_ci 389962306a36Sopenharmony_ci spin_unlock(&hsotg->lock); 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci return IRQ_HANDLED; 390262306a36Sopenharmony_ci} 390362306a36Sopenharmony_ci 390462306a36Sopenharmony_cistatic void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, 390562306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep) 390662306a36Sopenharmony_ci{ 390762306a36Sopenharmony_ci u32 epctrl_reg; 390862306a36Sopenharmony_ci u32 epint_reg; 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci epctrl_reg = hs_ep->dir_in ? DIEPCTL(hs_ep->index) : 391162306a36Sopenharmony_ci DOEPCTL(hs_ep->index); 391262306a36Sopenharmony_ci epint_reg = hs_ep->dir_in ? DIEPINT(hs_ep->index) : 391362306a36Sopenharmony_ci DOEPINT(hs_ep->index); 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: stopping transfer on %s\n", __func__, 391662306a36Sopenharmony_ci hs_ep->name); 391762306a36Sopenharmony_ci 391862306a36Sopenharmony_ci if (hs_ep->dir_in) { 391962306a36Sopenharmony_ci if (hsotg->dedicated_fifos || hs_ep->periodic) { 392062306a36Sopenharmony_ci dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_SNAK); 392162306a36Sopenharmony_ci /* Wait for Nak effect */ 392262306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, 392362306a36Sopenharmony_ci DXEPINT_INEPNAKEFF, 100)) 392462306a36Sopenharmony_ci dev_warn(hsotg->dev, 392562306a36Sopenharmony_ci "%s: timeout DIEPINT.NAKEFF\n", 392662306a36Sopenharmony_ci __func__); 392762306a36Sopenharmony_ci } else { 392862306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SGNPINNAK); 392962306a36Sopenharmony_ci /* Wait for Nak effect */ 393062306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 393162306a36Sopenharmony_ci GINTSTS_GINNAKEFF, 100)) 393262306a36Sopenharmony_ci dev_warn(hsotg->dev, 393362306a36Sopenharmony_ci "%s: timeout GINTSTS.GINNAKEFF\n", 393462306a36Sopenharmony_ci __func__); 393562306a36Sopenharmony_ci } 393662306a36Sopenharmony_ci } else { 393762306a36Sopenharmony_ci /* Mask GINTSTS_GOUTNAKEFF interrupt */ 393862306a36Sopenharmony_ci dwc2_hsotg_disable_gsint(hsotg, GINTSTS_GOUTNAKEFF); 393962306a36Sopenharmony_ci 394062306a36Sopenharmony_ci if (!(dwc2_readl(hsotg, GINTSTS) & GINTSTS_GOUTNAKEFF)) 394162306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK); 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci if (!using_dma(hsotg)) { 394462306a36Sopenharmony_ci /* Wait for GINTSTS_RXFLVL interrupt */ 394562306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 394662306a36Sopenharmony_ci GINTSTS_RXFLVL, 100)) { 394762306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: timeout GINTSTS.RXFLVL\n", 394862306a36Sopenharmony_ci __func__); 394962306a36Sopenharmony_ci } else { 395062306a36Sopenharmony_ci /* 395162306a36Sopenharmony_ci * Pop GLOBAL OUT NAK status packet from RxFIFO 395262306a36Sopenharmony_ci * to assert GOUTNAKEFF interrupt 395362306a36Sopenharmony_ci */ 395462306a36Sopenharmony_ci dwc2_readl(hsotg, GRXSTSP); 395562306a36Sopenharmony_ci } 395662306a36Sopenharmony_ci } 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_ci /* Wait for global nak to take effect */ 395962306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, 396062306a36Sopenharmony_ci GINTSTS_GOUTNAKEFF, 100)) 396162306a36Sopenharmony_ci dev_warn(hsotg->dev, "%s: timeout GINTSTS.GOUTNAKEFF\n", 396262306a36Sopenharmony_ci __func__); 396362306a36Sopenharmony_ci } 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_ci /* Disable ep */ 396662306a36Sopenharmony_ci dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK); 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci /* Wait for ep to be disabled */ 396962306a36Sopenharmony_ci if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100)) 397062306a36Sopenharmony_ci dev_warn(hsotg->dev, 397162306a36Sopenharmony_ci "%s: timeout DOEPCTL.EPDisable\n", __func__); 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_ci /* Clear EPDISBLD interrupt */ 397462306a36Sopenharmony_ci dwc2_set_bit(hsotg, epint_reg, DXEPINT_EPDISBLD); 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ci if (hs_ep->dir_in) { 397762306a36Sopenharmony_ci unsigned short fifo_index; 397862306a36Sopenharmony_ci 397962306a36Sopenharmony_ci if (hsotg->dedicated_fifos || hs_ep->periodic) 398062306a36Sopenharmony_ci fifo_index = hs_ep->fifo_index; 398162306a36Sopenharmony_ci else 398262306a36Sopenharmony_ci fifo_index = 0; 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci /* Flush TX FIFO */ 398562306a36Sopenharmony_ci dwc2_flush_tx_fifo(hsotg, fifo_index); 398662306a36Sopenharmony_ci 398762306a36Sopenharmony_ci /* Clear Global In NP NAK in Shared FIFO for non periodic ep */ 398862306a36Sopenharmony_ci if (!hsotg->dedicated_fifos && !hs_ep->periodic) 398962306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK); 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci } else { 399262306a36Sopenharmony_ci /* Remove global NAKs */ 399362306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_CGOUTNAK); 399462306a36Sopenharmony_ci } 399562306a36Sopenharmony_ci} 399662306a36Sopenharmony_ci 399762306a36Sopenharmony_ci/** 399862306a36Sopenharmony_ci * dwc2_hsotg_ep_enable - enable the given endpoint 399962306a36Sopenharmony_ci * @ep: The USB endpint to configure 400062306a36Sopenharmony_ci * @desc: The USB endpoint descriptor to configure with. 400162306a36Sopenharmony_ci * 400262306a36Sopenharmony_ci * This is called from the USB gadget code's usb_ep_enable(). 400362306a36Sopenharmony_ci */ 400462306a36Sopenharmony_cistatic int dwc2_hsotg_ep_enable(struct usb_ep *ep, 400562306a36Sopenharmony_ci const struct usb_endpoint_descriptor *desc) 400662306a36Sopenharmony_ci{ 400762306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 400862306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 400962306a36Sopenharmony_ci unsigned long flags; 401062306a36Sopenharmony_ci unsigned int index = hs_ep->index; 401162306a36Sopenharmony_ci u32 epctrl_reg; 401262306a36Sopenharmony_ci u32 epctrl; 401362306a36Sopenharmony_ci u32 mps; 401462306a36Sopenharmony_ci u32 mc; 401562306a36Sopenharmony_ci u32 mask; 401662306a36Sopenharmony_ci unsigned int dir_in; 401762306a36Sopenharmony_ci unsigned int i, val, size; 401862306a36Sopenharmony_ci int ret = 0; 401962306a36Sopenharmony_ci unsigned char ep_type; 402062306a36Sopenharmony_ci int desc_num; 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_ci dev_dbg(hsotg->dev, 402362306a36Sopenharmony_ci "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", 402462306a36Sopenharmony_ci __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, 402562306a36Sopenharmony_ci desc->wMaxPacketSize, desc->bInterval); 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci /* not to be called for EP0 */ 402862306a36Sopenharmony_ci if (index == 0) { 402962306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); 403062306a36Sopenharmony_ci return -EINVAL; 403162306a36Sopenharmony_ci } 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; 403462306a36Sopenharmony_ci if (dir_in != hs_ep->dir_in) { 403562306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); 403662306a36Sopenharmony_ci return -EINVAL; 403762306a36Sopenharmony_ci } 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; 404062306a36Sopenharmony_ci mps = usb_endpoint_maxp(desc); 404162306a36Sopenharmony_ci mc = usb_endpoint_maxp_mult(desc); 404262306a36Sopenharmony_ci 404362306a36Sopenharmony_ci /* ISOC IN in DDMA supported bInterval up to 10 */ 404462306a36Sopenharmony_ci if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && 404562306a36Sopenharmony_ci dir_in && desc->bInterval > 10) { 404662306a36Sopenharmony_ci dev_err(hsotg->dev, 404762306a36Sopenharmony_ci "%s: ISOC IN, DDMA: bInterval>10 not supported!\n", __func__); 404862306a36Sopenharmony_ci return -EINVAL; 404962306a36Sopenharmony_ci } 405062306a36Sopenharmony_ci 405162306a36Sopenharmony_ci /* High bandwidth ISOC OUT in DDMA not supported */ 405262306a36Sopenharmony_ci if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC && 405362306a36Sopenharmony_ci !dir_in && mc > 1) { 405462306a36Sopenharmony_ci dev_err(hsotg->dev, 405562306a36Sopenharmony_ci "%s: ISOC OUT, DDMA: HB not supported!\n", __func__); 405662306a36Sopenharmony_ci return -EINVAL; 405762306a36Sopenharmony_ci } 405862306a36Sopenharmony_ci 405962306a36Sopenharmony_ci /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */ 406062306a36Sopenharmony_ci 406162306a36Sopenharmony_ci epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 406262306a36Sopenharmony_ci epctrl = dwc2_readl(hsotg, epctrl_reg); 406362306a36Sopenharmony_ci 406462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", 406562306a36Sopenharmony_ci __func__, epctrl, epctrl_reg); 406662306a36Sopenharmony_ci 406762306a36Sopenharmony_ci if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC) 406862306a36Sopenharmony_ci desc_num = MAX_DMA_DESC_NUM_HS_ISOC; 406962306a36Sopenharmony_ci else 407062306a36Sopenharmony_ci desc_num = MAX_DMA_DESC_NUM_GENERIC; 407162306a36Sopenharmony_ci 407262306a36Sopenharmony_ci /* Allocate DMA descriptor chain for non-ctrl endpoints */ 407362306a36Sopenharmony_ci if (using_desc_dma(hsotg) && !hs_ep->desc_list) { 407462306a36Sopenharmony_ci hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev, 407562306a36Sopenharmony_ci desc_num * sizeof(struct dwc2_dma_desc), 407662306a36Sopenharmony_ci &hs_ep->desc_list_dma, GFP_ATOMIC); 407762306a36Sopenharmony_ci if (!hs_ep->desc_list) { 407862306a36Sopenharmony_ci ret = -ENOMEM; 407962306a36Sopenharmony_ci goto error2; 408062306a36Sopenharmony_ci } 408162306a36Sopenharmony_ci } 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 408462306a36Sopenharmony_ci 408562306a36Sopenharmony_ci epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); 408662306a36Sopenharmony_ci epctrl |= DXEPCTL_MPS(mps); 408762306a36Sopenharmony_ci 408862306a36Sopenharmony_ci /* 408962306a36Sopenharmony_ci * mark the endpoint as active, otherwise the core may ignore 409062306a36Sopenharmony_ci * transactions entirely for this endpoint 409162306a36Sopenharmony_ci */ 409262306a36Sopenharmony_ci epctrl |= DXEPCTL_USBACTEP; 409362306a36Sopenharmony_ci 409462306a36Sopenharmony_ci /* update the endpoint state */ 409562306a36Sopenharmony_ci dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, mc, dir_in); 409662306a36Sopenharmony_ci 409762306a36Sopenharmony_ci /* default, set to non-periodic */ 409862306a36Sopenharmony_ci hs_ep->isochronous = 0; 409962306a36Sopenharmony_ci hs_ep->periodic = 0; 410062306a36Sopenharmony_ci hs_ep->halted = 0; 410162306a36Sopenharmony_ci hs_ep->wedged = 0; 410262306a36Sopenharmony_ci hs_ep->interval = desc->bInterval; 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci switch (ep_type) { 410562306a36Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 410662306a36Sopenharmony_ci epctrl |= DXEPCTL_EPTYPE_ISO; 410762306a36Sopenharmony_ci epctrl |= DXEPCTL_SETEVENFR; 410862306a36Sopenharmony_ci hs_ep->isochronous = 1; 410962306a36Sopenharmony_ci hs_ep->interval = 1 << (desc->bInterval - 1); 411062306a36Sopenharmony_ci hs_ep->target_frame = TARGET_FRAME_INITIAL; 411162306a36Sopenharmony_ci hs_ep->next_desc = 0; 411262306a36Sopenharmony_ci hs_ep->compl_desc = 0; 411362306a36Sopenharmony_ci if (dir_in) { 411462306a36Sopenharmony_ci hs_ep->periodic = 1; 411562306a36Sopenharmony_ci mask = dwc2_readl(hsotg, DIEPMSK); 411662306a36Sopenharmony_ci mask |= DIEPMSK_NAKMSK; 411762306a36Sopenharmony_ci dwc2_writel(hsotg, mask, DIEPMSK); 411862306a36Sopenharmony_ci } else { 411962306a36Sopenharmony_ci epctrl |= DXEPCTL_SNAK; 412062306a36Sopenharmony_ci mask = dwc2_readl(hsotg, DOEPMSK); 412162306a36Sopenharmony_ci mask |= DOEPMSK_OUTTKNEPDISMSK; 412262306a36Sopenharmony_ci dwc2_writel(hsotg, mask, DOEPMSK); 412362306a36Sopenharmony_ci } 412462306a36Sopenharmony_ci break; 412562306a36Sopenharmony_ci 412662306a36Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 412762306a36Sopenharmony_ci epctrl |= DXEPCTL_EPTYPE_BULK; 412862306a36Sopenharmony_ci break; 412962306a36Sopenharmony_ci 413062306a36Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 413162306a36Sopenharmony_ci if (dir_in) 413262306a36Sopenharmony_ci hs_ep->periodic = 1; 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci if (hsotg->gadget.speed == USB_SPEED_HIGH) 413562306a36Sopenharmony_ci hs_ep->interval = 1 << (desc->bInterval - 1); 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci epctrl |= DXEPCTL_EPTYPE_INTERRUPT; 413862306a36Sopenharmony_ci break; 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 414162306a36Sopenharmony_ci epctrl |= DXEPCTL_EPTYPE_CONTROL; 414262306a36Sopenharmony_ci break; 414362306a36Sopenharmony_ci } 414462306a36Sopenharmony_ci 414562306a36Sopenharmony_ci /* 414662306a36Sopenharmony_ci * if the hardware has dedicated fifos, we must give each IN EP 414762306a36Sopenharmony_ci * a unique tx-fifo even if it is non-periodic. 414862306a36Sopenharmony_ci */ 414962306a36Sopenharmony_ci if (dir_in && hsotg->dedicated_fifos) { 415062306a36Sopenharmony_ci unsigned fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); 415162306a36Sopenharmony_ci u32 fifo_index = 0; 415262306a36Sopenharmony_ci u32 fifo_size = UINT_MAX; 415362306a36Sopenharmony_ci 415462306a36Sopenharmony_ci size = hs_ep->ep.maxpacket * hs_ep->mc; 415562306a36Sopenharmony_ci for (i = 1; i <= fifo_count; ++i) { 415662306a36Sopenharmony_ci if (hsotg->fifo_map & (1 << i)) 415762306a36Sopenharmony_ci continue; 415862306a36Sopenharmony_ci val = dwc2_readl(hsotg, DPTXFSIZN(i)); 415962306a36Sopenharmony_ci val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4; 416062306a36Sopenharmony_ci if (val < size) 416162306a36Sopenharmony_ci continue; 416262306a36Sopenharmony_ci /* Search for smallest acceptable fifo */ 416362306a36Sopenharmony_ci if (val < fifo_size) { 416462306a36Sopenharmony_ci fifo_size = val; 416562306a36Sopenharmony_ci fifo_index = i; 416662306a36Sopenharmony_ci } 416762306a36Sopenharmony_ci } 416862306a36Sopenharmony_ci if (!fifo_index) { 416962306a36Sopenharmony_ci dev_err(hsotg->dev, 417062306a36Sopenharmony_ci "%s: No suitable fifo found\n", __func__); 417162306a36Sopenharmony_ci ret = -ENOMEM; 417262306a36Sopenharmony_ci goto error1; 417362306a36Sopenharmony_ci } 417462306a36Sopenharmony_ci epctrl &= ~(DXEPCTL_TXFNUM_LIMIT << DXEPCTL_TXFNUM_SHIFT); 417562306a36Sopenharmony_ci hsotg->fifo_map |= 1 << fifo_index; 417662306a36Sopenharmony_ci epctrl |= DXEPCTL_TXFNUM(fifo_index); 417762306a36Sopenharmony_ci hs_ep->fifo_index = fifo_index; 417862306a36Sopenharmony_ci hs_ep->fifo_size = fifo_size; 417962306a36Sopenharmony_ci } 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci /* for non control endpoints, set PID to D0 */ 418262306a36Sopenharmony_ci if (index && !hs_ep->isochronous) 418362306a36Sopenharmony_ci epctrl |= DXEPCTL_SETD0PID; 418462306a36Sopenharmony_ci 418562306a36Sopenharmony_ci /* WA for Full speed ISOC IN in DDMA mode. 418662306a36Sopenharmony_ci * By Clear NAK status of EP, core will send ZLP 418762306a36Sopenharmony_ci * to IN token and assert NAK interrupt relying 418862306a36Sopenharmony_ci * on TxFIFO status only 418962306a36Sopenharmony_ci */ 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci if (hsotg->gadget.speed == USB_SPEED_FULL && 419262306a36Sopenharmony_ci hs_ep->isochronous && dir_in) { 419362306a36Sopenharmony_ci /* The WA applies only to core versions from 2.72a 419462306a36Sopenharmony_ci * to 4.00a (including both). Also for FS_IOT_1.00a 419562306a36Sopenharmony_ci * and HS_IOT_1.00a. 419662306a36Sopenharmony_ci */ 419762306a36Sopenharmony_ci u32 gsnpsid = dwc2_readl(hsotg, GSNPSID); 419862306a36Sopenharmony_ci 419962306a36Sopenharmony_ci if ((gsnpsid >= DWC2_CORE_REV_2_72a && 420062306a36Sopenharmony_ci gsnpsid <= DWC2_CORE_REV_4_00a) || 420162306a36Sopenharmony_ci gsnpsid == DWC2_FS_IOT_REV_1_00a || 420262306a36Sopenharmony_ci gsnpsid == DWC2_HS_IOT_REV_1_00a) 420362306a36Sopenharmony_ci epctrl |= DXEPCTL_CNAK; 420462306a36Sopenharmony_ci } 420562306a36Sopenharmony_ci 420662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", 420762306a36Sopenharmony_ci __func__, epctrl); 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci dwc2_writel(hsotg, epctrl, epctrl_reg); 421062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", 421162306a36Sopenharmony_ci __func__, dwc2_readl(hsotg, epctrl_reg)); 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_ci /* enable the endpoint interrupt */ 421462306a36Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1); 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_cierror1: 421762306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 421862306a36Sopenharmony_ci 421962306a36Sopenharmony_cierror2: 422062306a36Sopenharmony_ci if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) { 422162306a36Sopenharmony_ci dmam_free_coherent(hsotg->dev, desc_num * 422262306a36Sopenharmony_ci sizeof(struct dwc2_dma_desc), 422362306a36Sopenharmony_ci hs_ep->desc_list, hs_ep->desc_list_dma); 422462306a36Sopenharmony_ci hs_ep->desc_list = NULL; 422562306a36Sopenharmony_ci } 422662306a36Sopenharmony_ci 422762306a36Sopenharmony_ci return ret; 422862306a36Sopenharmony_ci} 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_ci/** 423162306a36Sopenharmony_ci * dwc2_hsotg_ep_disable - disable given endpoint 423262306a36Sopenharmony_ci * @ep: The endpoint to disable. 423362306a36Sopenharmony_ci */ 423462306a36Sopenharmony_cistatic int dwc2_hsotg_ep_disable(struct usb_ep *ep) 423562306a36Sopenharmony_ci{ 423662306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 423762306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 423862306a36Sopenharmony_ci int dir_in = hs_ep->dir_in; 423962306a36Sopenharmony_ci int index = hs_ep->index; 424062306a36Sopenharmony_ci u32 epctrl_reg; 424162306a36Sopenharmony_ci u32 ctrl; 424262306a36Sopenharmony_ci 424362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep); 424462306a36Sopenharmony_ci 424562306a36Sopenharmony_ci if (ep == &hsotg->eps_out[0]->ep) { 424662306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: called for ep0\n", __func__); 424762306a36Sopenharmony_ci return -EINVAL; 424862306a36Sopenharmony_ci } 424962306a36Sopenharmony_ci 425062306a36Sopenharmony_ci if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 425162306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: called in host mode?\n", __func__); 425262306a36Sopenharmony_ci return -EINVAL; 425362306a36Sopenharmony_ci } 425462306a36Sopenharmony_ci 425562306a36Sopenharmony_ci epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_ci ctrl = dwc2_readl(hsotg, epctrl_reg); 425862306a36Sopenharmony_ci 425962306a36Sopenharmony_ci if (ctrl & DXEPCTL_EPENA) 426062306a36Sopenharmony_ci dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep); 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci ctrl &= ~DXEPCTL_EPENA; 426362306a36Sopenharmony_ci ctrl &= ~DXEPCTL_USBACTEP; 426462306a36Sopenharmony_ci ctrl |= DXEPCTL_SNAK; 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); 426762306a36Sopenharmony_ci dwc2_writel(hsotg, ctrl, epctrl_reg); 426862306a36Sopenharmony_ci 426962306a36Sopenharmony_ci /* disable endpoint interrupts */ 427062306a36Sopenharmony_ci dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); 427162306a36Sopenharmony_ci 427262306a36Sopenharmony_ci /* terminate all requests with shutdown */ 427362306a36Sopenharmony_ci kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); 427462306a36Sopenharmony_ci 427562306a36Sopenharmony_ci hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); 427662306a36Sopenharmony_ci hs_ep->fifo_index = 0; 427762306a36Sopenharmony_ci hs_ep->fifo_size = 0; 427862306a36Sopenharmony_ci 427962306a36Sopenharmony_ci return 0; 428062306a36Sopenharmony_ci} 428162306a36Sopenharmony_ci 428262306a36Sopenharmony_cistatic int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep) 428362306a36Sopenharmony_ci{ 428462306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 428562306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = hs_ep->parent; 428662306a36Sopenharmony_ci unsigned long flags; 428762306a36Sopenharmony_ci int ret; 428862306a36Sopenharmony_ci 428962306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 429062306a36Sopenharmony_ci ret = dwc2_hsotg_ep_disable(ep); 429162306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 429262306a36Sopenharmony_ci return ret; 429362306a36Sopenharmony_ci} 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_ci/** 429662306a36Sopenharmony_ci * on_list - check request is on the given endpoint 429762306a36Sopenharmony_ci * @ep: The endpoint to check. 429862306a36Sopenharmony_ci * @test: The request to test if it is on the endpoint. 429962306a36Sopenharmony_ci */ 430062306a36Sopenharmony_cistatic bool on_list(struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_req *test) 430162306a36Sopenharmony_ci{ 430262306a36Sopenharmony_ci struct dwc2_hsotg_req *req, *treq; 430362306a36Sopenharmony_ci 430462306a36Sopenharmony_ci list_for_each_entry_safe(req, treq, &ep->queue, queue) { 430562306a36Sopenharmony_ci if (req == test) 430662306a36Sopenharmony_ci return true; 430762306a36Sopenharmony_ci } 430862306a36Sopenharmony_ci 430962306a36Sopenharmony_ci return false; 431062306a36Sopenharmony_ci} 431162306a36Sopenharmony_ci 431262306a36Sopenharmony_ci/** 431362306a36Sopenharmony_ci * dwc2_hsotg_ep_dequeue - dequeue given endpoint 431462306a36Sopenharmony_ci * @ep: The endpoint to dequeue. 431562306a36Sopenharmony_ci * @req: The request to be removed from a queue. 431662306a36Sopenharmony_ci */ 431762306a36Sopenharmony_cistatic int dwc2_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) 431862306a36Sopenharmony_ci{ 431962306a36Sopenharmony_ci struct dwc2_hsotg_req *hs_req = our_req(req); 432062306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 432162306a36Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 432262306a36Sopenharmony_ci unsigned long flags; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci dev_dbg(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_ci spin_lock_irqsave(&hs->lock, flags); 432762306a36Sopenharmony_ci 432862306a36Sopenharmony_ci if (!on_list(hs_ep, hs_req)) { 432962306a36Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 433062306a36Sopenharmony_ci return -EINVAL; 433162306a36Sopenharmony_ci } 433262306a36Sopenharmony_ci 433362306a36Sopenharmony_ci /* Dequeue already started request */ 433462306a36Sopenharmony_ci if (req == &hs_ep->req->req) 433562306a36Sopenharmony_ci dwc2_hsotg_ep_stop_xfr(hs, hs_ep); 433662306a36Sopenharmony_ci 433762306a36Sopenharmony_ci dwc2_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); 433862306a36Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 433962306a36Sopenharmony_ci 434062306a36Sopenharmony_ci return 0; 434162306a36Sopenharmony_ci} 434262306a36Sopenharmony_ci 434362306a36Sopenharmony_ci/** 434462306a36Sopenharmony_ci * dwc2_gadget_ep_set_wedge - set wedge on a given endpoint 434562306a36Sopenharmony_ci * @ep: The endpoint to be wedged. 434662306a36Sopenharmony_ci * 434762306a36Sopenharmony_ci */ 434862306a36Sopenharmony_cistatic int dwc2_gadget_ep_set_wedge(struct usb_ep *ep) 434962306a36Sopenharmony_ci{ 435062306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 435162306a36Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 435262306a36Sopenharmony_ci 435362306a36Sopenharmony_ci unsigned long flags; 435462306a36Sopenharmony_ci int ret; 435562306a36Sopenharmony_ci 435662306a36Sopenharmony_ci spin_lock_irqsave(&hs->lock, flags); 435762306a36Sopenharmony_ci hs_ep->wedged = 1; 435862306a36Sopenharmony_ci ret = dwc2_hsotg_ep_sethalt(ep, 1, false); 435962306a36Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 436062306a36Sopenharmony_ci 436162306a36Sopenharmony_ci return ret; 436262306a36Sopenharmony_ci} 436362306a36Sopenharmony_ci 436462306a36Sopenharmony_ci/** 436562306a36Sopenharmony_ci * dwc2_hsotg_ep_sethalt - set halt on a given endpoint 436662306a36Sopenharmony_ci * @ep: The endpoint to set halt. 436762306a36Sopenharmony_ci * @value: Set or unset the halt. 436862306a36Sopenharmony_ci * @now: If true, stall the endpoint now. Otherwise return -EAGAIN if 436962306a36Sopenharmony_ci * the endpoint is busy processing requests. 437062306a36Sopenharmony_ci * 437162306a36Sopenharmony_ci * We need to stall the endpoint immediately if request comes from set_feature 437262306a36Sopenharmony_ci * protocol command handler. 437362306a36Sopenharmony_ci */ 437462306a36Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) 437562306a36Sopenharmony_ci{ 437662306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 437762306a36Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 437862306a36Sopenharmony_ci int index = hs_ep->index; 437962306a36Sopenharmony_ci u32 epreg; 438062306a36Sopenharmony_ci u32 epctl; 438162306a36Sopenharmony_ci u32 xfertype; 438262306a36Sopenharmony_ci 438362306a36Sopenharmony_ci dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); 438462306a36Sopenharmony_ci 438562306a36Sopenharmony_ci if (index == 0) { 438662306a36Sopenharmony_ci if (value) 438762306a36Sopenharmony_ci dwc2_hsotg_stall_ep0(hs); 438862306a36Sopenharmony_ci else 438962306a36Sopenharmony_ci dev_warn(hs->dev, 439062306a36Sopenharmony_ci "%s: can't clear halt on ep0\n", __func__); 439162306a36Sopenharmony_ci return 0; 439262306a36Sopenharmony_ci } 439362306a36Sopenharmony_ci 439462306a36Sopenharmony_ci if (hs_ep->isochronous) { 439562306a36Sopenharmony_ci dev_err(hs->dev, "%s is Isochronous Endpoint\n", ep->name); 439662306a36Sopenharmony_ci return -EINVAL; 439762306a36Sopenharmony_ci } 439862306a36Sopenharmony_ci 439962306a36Sopenharmony_ci if (!now && value && !list_empty(&hs_ep->queue)) { 440062306a36Sopenharmony_ci dev_dbg(hs->dev, "%s request is pending, cannot halt\n", 440162306a36Sopenharmony_ci ep->name); 440262306a36Sopenharmony_ci return -EAGAIN; 440362306a36Sopenharmony_ci } 440462306a36Sopenharmony_ci 440562306a36Sopenharmony_ci if (hs_ep->dir_in) { 440662306a36Sopenharmony_ci epreg = DIEPCTL(index); 440762306a36Sopenharmony_ci epctl = dwc2_readl(hs, epreg); 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_ci if (value) { 441062306a36Sopenharmony_ci epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; 441162306a36Sopenharmony_ci if (epctl & DXEPCTL_EPENA) 441262306a36Sopenharmony_ci epctl |= DXEPCTL_EPDIS; 441362306a36Sopenharmony_ci } else { 441462306a36Sopenharmony_ci epctl &= ~DXEPCTL_STALL; 441562306a36Sopenharmony_ci hs_ep->wedged = 0; 441662306a36Sopenharmony_ci xfertype = epctl & DXEPCTL_EPTYPE_MASK; 441762306a36Sopenharmony_ci if (xfertype == DXEPCTL_EPTYPE_BULK || 441862306a36Sopenharmony_ci xfertype == DXEPCTL_EPTYPE_INTERRUPT) 441962306a36Sopenharmony_ci epctl |= DXEPCTL_SETD0PID; 442062306a36Sopenharmony_ci } 442162306a36Sopenharmony_ci dwc2_writel(hs, epctl, epreg); 442262306a36Sopenharmony_ci } else { 442362306a36Sopenharmony_ci epreg = DOEPCTL(index); 442462306a36Sopenharmony_ci epctl = dwc2_readl(hs, epreg); 442562306a36Sopenharmony_ci 442662306a36Sopenharmony_ci if (value) { 442762306a36Sopenharmony_ci /* Unmask GOUTNAKEFF interrupt */ 442862306a36Sopenharmony_ci dwc2_hsotg_en_gsint(hs, GINTSTS_GOUTNAKEFF); 442962306a36Sopenharmony_ci 443062306a36Sopenharmony_ci if (!(dwc2_readl(hs, GINTSTS) & GINTSTS_GOUTNAKEFF)) 443162306a36Sopenharmony_ci dwc2_set_bit(hs, DCTL, DCTL_SGOUTNAK); 443262306a36Sopenharmony_ci // STALL bit will be set in GOUTNAKEFF interrupt handler 443362306a36Sopenharmony_ci } else { 443462306a36Sopenharmony_ci epctl &= ~DXEPCTL_STALL; 443562306a36Sopenharmony_ci hs_ep->wedged = 0; 443662306a36Sopenharmony_ci xfertype = epctl & DXEPCTL_EPTYPE_MASK; 443762306a36Sopenharmony_ci if (xfertype == DXEPCTL_EPTYPE_BULK || 443862306a36Sopenharmony_ci xfertype == DXEPCTL_EPTYPE_INTERRUPT) 443962306a36Sopenharmony_ci epctl |= DXEPCTL_SETD0PID; 444062306a36Sopenharmony_ci dwc2_writel(hs, epctl, epreg); 444162306a36Sopenharmony_ci } 444262306a36Sopenharmony_ci } 444362306a36Sopenharmony_ci 444462306a36Sopenharmony_ci hs_ep->halted = value; 444562306a36Sopenharmony_ci return 0; 444662306a36Sopenharmony_ci} 444762306a36Sopenharmony_ci 444862306a36Sopenharmony_ci/** 444962306a36Sopenharmony_ci * dwc2_hsotg_ep_sethalt_lock - set halt on a given endpoint with lock held 445062306a36Sopenharmony_ci * @ep: The endpoint to set halt. 445162306a36Sopenharmony_ci * @value: Set or unset the halt. 445262306a36Sopenharmony_ci */ 445362306a36Sopenharmony_cistatic int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) 445462306a36Sopenharmony_ci{ 445562306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep = our_ep(ep); 445662306a36Sopenharmony_ci struct dwc2_hsotg *hs = hs_ep->parent; 445762306a36Sopenharmony_ci unsigned long flags; 445862306a36Sopenharmony_ci int ret; 445962306a36Sopenharmony_ci 446062306a36Sopenharmony_ci spin_lock_irqsave(&hs->lock, flags); 446162306a36Sopenharmony_ci ret = dwc2_hsotg_ep_sethalt(ep, value, false); 446262306a36Sopenharmony_ci spin_unlock_irqrestore(&hs->lock, flags); 446362306a36Sopenharmony_ci 446462306a36Sopenharmony_ci return ret; 446562306a36Sopenharmony_ci} 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_cistatic const struct usb_ep_ops dwc2_hsotg_ep_ops = { 446862306a36Sopenharmony_ci .enable = dwc2_hsotg_ep_enable, 446962306a36Sopenharmony_ci .disable = dwc2_hsotg_ep_disable_lock, 447062306a36Sopenharmony_ci .alloc_request = dwc2_hsotg_ep_alloc_request, 447162306a36Sopenharmony_ci .free_request = dwc2_hsotg_ep_free_request, 447262306a36Sopenharmony_ci .queue = dwc2_hsotg_ep_queue_lock, 447362306a36Sopenharmony_ci .dequeue = dwc2_hsotg_ep_dequeue, 447462306a36Sopenharmony_ci .set_halt = dwc2_hsotg_ep_sethalt_lock, 447562306a36Sopenharmony_ci .set_wedge = dwc2_gadget_ep_set_wedge, 447662306a36Sopenharmony_ci /* note, don't believe we have any call for the fifo routines */ 447762306a36Sopenharmony_ci}; 447862306a36Sopenharmony_ci 447962306a36Sopenharmony_ci/** 448062306a36Sopenharmony_ci * dwc2_hsotg_init - initialize the usb core 448162306a36Sopenharmony_ci * @hsotg: The driver state 448262306a36Sopenharmony_ci */ 448362306a36Sopenharmony_cistatic void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) 448462306a36Sopenharmony_ci{ 448562306a36Sopenharmony_ci /* unmask subset of endpoint interrupts */ 448662306a36Sopenharmony_ci 448762306a36Sopenharmony_ci dwc2_writel(hsotg, DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | 448862306a36Sopenharmony_ci DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, 448962306a36Sopenharmony_ci DIEPMSK); 449062306a36Sopenharmony_ci 449162306a36Sopenharmony_ci dwc2_writel(hsotg, DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | 449262306a36Sopenharmony_ci DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, 449362306a36Sopenharmony_ci DOEPMSK); 449462306a36Sopenharmony_ci 449562306a36Sopenharmony_ci dwc2_writel(hsotg, 0, DAINTMSK); 449662306a36Sopenharmony_ci 449762306a36Sopenharmony_ci /* Be in disconnected state until gadget is registered */ 449862306a36Sopenharmony_ci dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); 449962306a36Sopenharmony_ci 450062306a36Sopenharmony_ci /* setup fifos */ 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 450362306a36Sopenharmony_ci dwc2_readl(hsotg, GRXFSIZ), 450462306a36Sopenharmony_ci dwc2_readl(hsotg, GNPTXFSIZ)); 450562306a36Sopenharmony_ci 450662306a36Sopenharmony_ci dwc2_hsotg_init_fifo(hsotg); 450762306a36Sopenharmony_ci 450862306a36Sopenharmony_ci if (using_dma(hsotg)) 450962306a36Sopenharmony_ci dwc2_set_bit(hsotg, GAHBCFG, GAHBCFG_DMA_EN); 451062306a36Sopenharmony_ci} 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_ci/** 451362306a36Sopenharmony_ci * dwc2_hsotg_udc_start - prepare the udc for work 451462306a36Sopenharmony_ci * @gadget: The usb gadget state 451562306a36Sopenharmony_ci * @driver: The usb gadget driver 451662306a36Sopenharmony_ci * 451762306a36Sopenharmony_ci * Perform initialization to prepare udc device and driver 451862306a36Sopenharmony_ci * to work. 451962306a36Sopenharmony_ci */ 452062306a36Sopenharmony_cistatic int dwc2_hsotg_udc_start(struct usb_gadget *gadget, 452162306a36Sopenharmony_ci struct usb_gadget_driver *driver) 452262306a36Sopenharmony_ci{ 452362306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 452462306a36Sopenharmony_ci unsigned long flags; 452562306a36Sopenharmony_ci int ret; 452662306a36Sopenharmony_ci 452762306a36Sopenharmony_ci if (!hsotg) { 452862306a36Sopenharmony_ci pr_err("%s: called with no device\n", __func__); 452962306a36Sopenharmony_ci return -ENODEV; 453062306a36Sopenharmony_ci } 453162306a36Sopenharmony_ci 453262306a36Sopenharmony_ci if (!driver) { 453362306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: no driver\n", __func__); 453462306a36Sopenharmony_ci return -EINVAL; 453562306a36Sopenharmony_ci } 453662306a36Sopenharmony_ci 453762306a36Sopenharmony_ci if (driver->max_speed < USB_SPEED_FULL) 453862306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: bad speed\n", __func__); 453962306a36Sopenharmony_ci 454062306a36Sopenharmony_ci if (!driver->setup) { 454162306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: missing entry points\n", __func__); 454262306a36Sopenharmony_ci return -EINVAL; 454362306a36Sopenharmony_ci } 454462306a36Sopenharmony_ci 454562306a36Sopenharmony_ci WARN_ON(hsotg->driver); 454662306a36Sopenharmony_ci 454762306a36Sopenharmony_ci hsotg->driver = driver; 454862306a36Sopenharmony_ci hsotg->gadget.dev.of_node = hsotg->dev->of_node; 454962306a36Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_UNKNOWN; 455062306a36Sopenharmony_ci 455162306a36Sopenharmony_ci if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) { 455262306a36Sopenharmony_ci ret = dwc2_lowlevel_hw_enable(hsotg); 455362306a36Sopenharmony_ci if (ret) 455462306a36Sopenharmony_ci goto err; 455562306a36Sopenharmony_ci } 455662306a36Sopenharmony_ci 455762306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(hsotg->uphy)) 455862306a36Sopenharmony_ci otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); 455962306a36Sopenharmony_ci 456062306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 456162306a36Sopenharmony_ci if (dwc2_hw_is_device(hsotg)) { 456262306a36Sopenharmony_ci dwc2_hsotg_init(hsotg); 456362306a36Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, false); 456462306a36Sopenharmony_ci } 456562306a36Sopenharmony_ci 456662306a36Sopenharmony_ci hsotg->enabled = 0; 456762306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 456862306a36Sopenharmony_ci 456962306a36Sopenharmony_ci gadget->sg_supported = using_desc_dma(hsotg); 457062306a36Sopenharmony_ci dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); 457162306a36Sopenharmony_ci 457262306a36Sopenharmony_ci return 0; 457362306a36Sopenharmony_ci 457462306a36Sopenharmony_cierr: 457562306a36Sopenharmony_ci hsotg->driver = NULL; 457662306a36Sopenharmony_ci return ret; 457762306a36Sopenharmony_ci} 457862306a36Sopenharmony_ci 457962306a36Sopenharmony_ci/** 458062306a36Sopenharmony_ci * dwc2_hsotg_udc_stop - stop the udc 458162306a36Sopenharmony_ci * @gadget: The usb gadget state 458262306a36Sopenharmony_ci * 458362306a36Sopenharmony_ci * Stop udc hw block and stay tunned for future transmissions 458462306a36Sopenharmony_ci */ 458562306a36Sopenharmony_cistatic int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) 458662306a36Sopenharmony_ci{ 458762306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 458862306a36Sopenharmony_ci unsigned long flags; 458962306a36Sopenharmony_ci int ep; 459062306a36Sopenharmony_ci 459162306a36Sopenharmony_ci if (!hsotg) 459262306a36Sopenharmony_ci return -ENODEV; 459362306a36Sopenharmony_ci 459462306a36Sopenharmony_ci /* all endpoints should be shutdown */ 459562306a36Sopenharmony_ci for (ep = 1; ep < hsotg->num_of_eps; ep++) { 459662306a36Sopenharmony_ci if (hsotg->eps_in[ep]) 459762306a36Sopenharmony_ci dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); 459862306a36Sopenharmony_ci if (hsotg->eps_out[ep]) 459962306a36Sopenharmony_ci dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); 460062306a36Sopenharmony_ci } 460162306a36Sopenharmony_ci 460262306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_ci hsotg->driver = NULL; 460562306a36Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_UNKNOWN; 460662306a36Sopenharmony_ci hsotg->enabled = 0; 460762306a36Sopenharmony_ci 460862306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 460962306a36Sopenharmony_ci 461062306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(hsotg->uphy)) 461162306a36Sopenharmony_ci otg_set_peripheral(hsotg->uphy->otg, NULL); 461262306a36Sopenharmony_ci 461362306a36Sopenharmony_ci if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 461462306a36Sopenharmony_ci dwc2_lowlevel_hw_disable(hsotg); 461562306a36Sopenharmony_ci 461662306a36Sopenharmony_ci return 0; 461762306a36Sopenharmony_ci} 461862306a36Sopenharmony_ci 461962306a36Sopenharmony_ci/** 462062306a36Sopenharmony_ci * dwc2_hsotg_gadget_getframe - read the frame number 462162306a36Sopenharmony_ci * @gadget: The usb gadget state 462262306a36Sopenharmony_ci * 462362306a36Sopenharmony_ci * Read the {micro} frame number 462462306a36Sopenharmony_ci */ 462562306a36Sopenharmony_cistatic int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget) 462662306a36Sopenharmony_ci{ 462762306a36Sopenharmony_ci return dwc2_hsotg_read_frameno(to_hsotg(gadget)); 462862306a36Sopenharmony_ci} 462962306a36Sopenharmony_ci 463062306a36Sopenharmony_ci/** 463162306a36Sopenharmony_ci * dwc2_hsotg_set_selfpowered - set if device is self/bus powered 463262306a36Sopenharmony_ci * @gadget: The usb gadget state 463362306a36Sopenharmony_ci * @is_selfpowered: Whether the device is self-powered 463462306a36Sopenharmony_ci * 463562306a36Sopenharmony_ci * Set if the device is self or bus powered. 463662306a36Sopenharmony_ci */ 463762306a36Sopenharmony_cistatic int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget, 463862306a36Sopenharmony_ci int is_selfpowered) 463962306a36Sopenharmony_ci{ 464062306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 464162306a36Sopenharmony_ci unsigned long flags; 464262306a36Sopenharmony_ci 464362306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 464462306a36Sopenharmony_ci gadget->is_selfpowered = !!is_selfpowered; 464562306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci return 0; 464862306a36Sopenharmony_ci} 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci/** 465162306a36Sopenharmony_ci * dwc2_hsotg_pullup - connect/disconnect the USB PHY 465262306a36Sopenharmony_ci * @gadget: The usb gadget state 465362306a36Sopenharmony_ci * @is_on: Current state of the USB PHY 465462306a36Sopenharmony_ci * 465562306a36Sopenharmony_ci * Connect/Disconnect the USB PHY pullup 465662306a36Sopenharmony_ci */ 465762306a36Sopenharmony_cistatic int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) 465862306a36Sopenharmony_ci{ 465962306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 466062306a36Sopenharmony_ci unsigned long flags; 466162306a36Sopenharmony_ci 466262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, 466362306a36Sopenharmony_ci hsotg->op_state); 466462306a36Sopenharmony_ci 466562306a36Sopenharmony_ci /* Don't modify pullup state while in host mode */ 466662306a36Sopenharmony_ci if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { 466762306a36Sopenharmony_ci hsotg->enabled = is_on; 466862306a36Sopenharmony_ci return 0; 466962306a36Sopenharmony_ci } 467062306a36Sopenharmony_ci 467162306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 467262306a36Sopenharmony_ci if (is_on) { 467362306a36Sopenharmony_ci hsotg->enabled = 1; 467462306a36Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, false); 467562306a36Sopenharmony_ci /* Enable ACG feature in device mode,if supported */ 467662306a36Sopenharmony_ci dwc2_enable_acg(hsotg); 467762306a36Sopenharmony_ci dwc2_hsotg_core_connect(hsotg); 467862306a36Sopenharmony_ci } else { 467962306a36Sopenharmony_ci dwc2_hsotg_core_disconnect(hsotg); 468062306a36Sopenharmony_ci dwc2_hsotg_disconnect(hsotg); 468162306a36Sopenharmony_ci hsotg->enabled = 0; 468262306a36Sopenharmony_ci } 468362306a36Sopenharmony_ci 468462306a36Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_UNKNOWN; 468562306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 468662306a36Sopenharmony_ci 468762306a36Sopenharmony_ci return 0; 468862306a36Sopenharmony_ci} 468962306a36Sopenharmony_ci 469062306a36Sopenharmony_cistatic int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) 469162306a36Sopenharmony_ci{ 469262306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 469362306a36Sopenharmony_ci unsigned long flags; 469462306a36Sopenharmony_ci 469562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active); 469662306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 469762306a36Sopenharmony_ci 469862306a36Sopenharmony_ci /* 469962306a36Sopenharmony_ci * If controller is in partial power down state, it must exit from 470062306a36Sopenharmony_ci * that state before being initialized / de-initialized 470162306a36Sopenharmony_ci */ 470262306a36Sopenharmony_ci if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) 470362306a36Sopenharmony_ci /* 470462306a36Sopenharmony_ci * No need to check the return value as 470562306a36Sopenharmony_ci * registers are not being restored. 470662306a36Sopenharmony_ci */ 470762306a36Sopenharmony_ci dwc2_exit_partial_power_down(hsotg, 0, false); 470862306a36Sopenharmony_ci 470962306a36Sopenharmony_ci if (is_active) { 471062306a36Sopenharmony_ci hsotg->op_state = OTG_STATE_B_PERIPHERAL; 471162306a36Sopenharmony_ci 471262306a36Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, false); 471362306a36Sopenharmony_ci if (hsotg->enabled) { 471462306a36Sopenharmony_ci /* Enable ACG feature in device mode,if supported */ 471562306a36Sopenharmony_ci dwc2_enable_acg(hsotg); 471662306a36Sopenharmony_ci dwc2_hsotg_core_connect(hsotg); 471762306a36Sopenharmony_ci } 471862306a36Sopenharmony_ci } else { 471962306a36Sopenharmony_ci dwc2_hsotg_core_disconnect(hsotg); 472062306a36Sopenharmony_ci dwc2_hsotg_disconnect(hsotg); 472162306a36Sopenharmony_ci } 472262306a36Sopenharmony_ci 472362306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 472462306a36Sopenharmony_ci return 0; 472562306a36Sopenharmony_ci} 472662306a36Sopenharmony_ci 472762306a36Sopenharmony_ci/** 472862306a36Sopenharmony_ci * dwc2_hsotg_vbus_draw - report bMaxPower field 472962306a36Sopenharmony_ci * @gadget: The usb gadget state 473062306a36Sopenharmony_ci * @mA: Amount of current 473162306a36Sopenharmony_ci * 473262306a36Sopenharmony_ci * Report how much power the device may consume to the phy. 473362306a36Sopenharmony_ci */ 473462306a36Sopenharmony_cistatic int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) 473562306a36Sopenharmony_ci{ 473662306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(gadget); 473762306a36Sopenharmony_ci 473862306a36Sopenharmony_ci if (IS_ERR_OR_NULL(hsotg->uphy)) 473962306a36Sopenharmony_ci return -ENOTSUPP; 474062306a36Sopenharmony_ci return usb_phy_set_power(hsotg->uphy, mA); 474162306a36Sopenharmony_ci} 474262306a36Sopenharmony_ci 474362306a36Sopenharmony_cistatic void dwc2_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed) 474462306a36Sopenharmony_ci{ 474562306a36Sopenharmony_ci struct dwc2_hsotg *hsotg = to_hsotg(g); 474662306a36Sopenharmony_ci unsigned long flags; 474762306a36Sopenharmony_ci 474862306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 474962306a36Sopenharmony_ci switch (speed) { 475062306a36Sopenharmony_ci case USB_SPEED_HIGH: 475162306a36Sopenharmony_ci hsotg->params.speed = DWC2_SPEED_PARAM_HIGH; 475262306a36Sopenharmony_ci break; 475362306a36Sopenharmony_ci case USB_SPEED_FULL: 475462306a36Sopenharmony_ci hsotg->params.speed = DWC2_SPEED_PARAM_FULL; 475562306a36Sopenharmony_ci break; 475662306a36Sopenharmony_ci case USB_SPEED_LOW: 475762306a36Sopenharmony_ci hsotg->params.speed = DWC2_SPEED_PARAM_LOW; 475862306a36Sopenharmony_ci break; 475962306a36Sopenharmony_ci default: 476062306a36Sopenharmony_ci dev_err(hsotg->dev, "invalid speed (%d)\n", speed); 476162306a36Sopenharmony_ci } 476262306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 476362306a36Sopenharmony_ci} 476462306a36Sopenharmony_ci 476562306a36Sopenharmony_cistatic const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { 476662306a36Sopenharmony_ci .get_frame = dwc2_hsotg_gadget_getframe, 476762306a36Sopenharmony_ci .set_selfpowered = dwc2_hsotg_set_selfpowered, 476862306a36Sopenharmony_ci .udc_start = dwc2_hsotg_udc_start, 476962306a36Sopenharmony_ci .udc_stop = dwc2_hsotg_udc_stop, 477062306a36Sopenharmony_ci .pullup = dwc2_hsotg_pullup, 477162306a36Sopenharmony_ci .udc_set_speed = dwc2_gadget_set_speed, 477262306a36Sopenharmony_ci .vbus_session = dwc2_hsotg_vbus_session, 477362306a36Sopenharmony_ci .vbus_draw = dwc2_hsotg_vbus_draw, 477462306a36Sopenharmony_ci}; 477562306a36Sopenharmony_ci 477662306a36Sopenharmony_ci/** 477762306a36Sopenharmony_ci * dwc2_hsotg_initep - initialise a single endpoint 477862306a36Sopenharmony_ci * @hsotg: The device state. 477962306a36Sopenharmony_ci * @hs_ep: The endpoint to be initialised. 478062306a36Sopenharmony_ci * @epnum: The endpoint number 478162306a36Sopenharmony_ci * @dir_in: True if direction is in. 478262306a36Sopenharmony_ci * 478362306a36Sopenharmony_ci * Initialise the given endpoint (as part of the probe and device state 478462306a36Sopenharmony_ci * creation) to give to the gadget driver. Setup the endpoint name, any 478562306a36Sopenharmony_ci * direction information and other state that may be required. 478662306a36Sopenharmony_ci */ 478762306a36Sopenharmony_cistatic void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, 478862306a36Sopenharmony_ci struct dwc2_hsotg_ep *hs_ep, 478962306a36Sopenharmony_ci int epnum, 479062306a36Sopenharmony_ci bool dir_in) 479162306a36Sopenharmony_ci{ 479262306a36Sopenharmony_ci char *dir; 479362306a36Sopenharmony_ci 479462306a36Sopenharmony_ci if (epnum == 0) 479562306a36Sopenharmony_ci dir = ""; 479662306a36Sopenharmony_ci else if (dir_in) 479762306a36Sopenharmony_ci dir = "in"; 479862306a36Sopenharmony_ci else 479962306a36Sopenharmony_ci dir = "out"; 480062306a36Sopenharmony_ci 480162306a36Sopenharmony_ci hs_ep->dir_in = dir_in; 480262306a36Sopenharmony_ci hs_ep->index = epnum; 480362306a36Sopenharmony_ci 480462306a36Sopenharmony_ci snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); 480562306a36Sopenharmony_ci 480662306a36Sopenharmony_ci INIT_LIST_HEAD(&hs_ep->queue); 480762306a36Sopenharmony_ci INIT_LIST_HEAD(&hs_ep->ep.ep_list); 480862306a36Sopenharmony_ci 480962306a36Sopenharmony_ci /* add to the list of endpoints known by the gadget driver */ 481062306a36Sopenharmony_ci if (epnum) 481162306a36Sopenharmony_ci list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); 481262306a36Sopenharmony_ci 481362306a36Sopenharmony_ci hs_ep->parent = hsotg; 481462306a36Sopenharmony_ci hs_ep->ep.name = hs_ep->name; 481562306a36Sopenharmony_ci 481662306a36Sopenharmony_ci if (hsotg->params.speed == DWC2_SPEED_PARAM_LOW) 481762306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&hs_ep->ep, 8); 481862306a36Sopenharmony_ci else 481962306a36Sopenharmony_ci usb_ep_set_maxpacket_limit(&hs_ep->ep, 482062306a36Sopenharmony_ci epnum ? 1024 : EP0_MPS_LIMIT); 482162306a36Sopenharmony_ci hs_ep->ep.ops = &dwc2_hsotg_ep_ops; 482262306a36Sopenharmony_ci 482362306a36Sopenharmony_ci if (epnum == 0) { 482462306a36Sopenharmony_ci hs_ep->ep.caps.type_control = true; 482562306a36Sopenharmony_ci } else { 482662306a36Sopenharmony_ci if (hsotg->params.speed != DWC2_SPEED_PARAM_LOW) { 482762306a36Sopenharmony_ci hs_ep->ep.caps.type_iso = true; 482862306a36Sopenharmony_ci hs_ep->ep.caps.type_bulk = true; 482962306a36Sopenharmony_ci } 483062306a36Sopenharmony_ci hs_ep->ep.caps.type_int = true; 483162306a36Sopenharmony_ci } 483262306a36Sopenharmony_ci 483362306a36Sopenharmony_ci if (dir_in) 483462306a36Sopenharmony_ci hs_ep->ep.caps.dir_in = true; 483562306a36Sopenharmony_ci else 483662306a36Sopenharmony_ci hs_ep->ep.caps.dir_out = true; 483762306a36Sopenharmony_ci 483862306a36Sopenharmony_ci /* 483962306a36Sopenharmony_ci * if we're using dma, we need to set the next-endpoint pointer 484062306a36Sopenharmony_ci * to be something valid. 484162306a36Sopenharmony_ci */ 484262306a36Sopenharmony_ci 484362306a36Sopenharmony_ci if (using_dma(hsotg)) { 484462306a36Sopenharmony_ci u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); 484562306a36Sopenharmony_ci 484662306a36Sopenharmony_ci if (dir_in) 484762306a36Sopenharmony_ci dwc2_writel(hsotg, next, DIEPCTL(epnum)); 484862306a36Sopenharmony_ci else 484962306a36Sopenharmony_ci dwc2_writel(hsotg, next, DOEPCTL(epnum)); 485062306a36Sopenharmony_ci } 485162306a36Sopenharmony_ci} 485262306a36Sopenharmony_ci 485362306a36Sopenharmony_ci/** 485462306a36Sopenharmony_ci * dwc2_hsotg_hw_cfg - read HW configuration registers 485562306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 485662306a36Sopenharmony_ci * 485762306a36Sopenharmony_ci * Read the USB core HW configuration registers 485862306a36Sopenharmony_ci */ 485962306a36Sopenharmony_cistatic int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) 486062306a36Sopenharmony_ci{ 486162306a36Sopenharmony_ci u32 cfg; 486262306a36Sopenharmony_ci u32 ep_type; 486362306a36Sopenharmony_ci u32 i; 486462306a36Sopenharmony_ci 486562306a36Sopenharmony_ci /* check hardware configuration */ 486662306a36Sopenharmony_ci 486762306a36Sopenharmony_ci hsotg->num_of_eps = hsotg->hw_params.num_dev_ep; 486862306a36Sopenharmony_ci 486962306a36Sopenharmony_ci /* Add ep0 */ 487062306a36Sopenharmony_ci hsotg->num_of_eps++; 487162306a36Sopenharmony_ci 487262306a36Sopenharmony_ci hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, 487362306a36Sopenharmony_ci sizeof(struct dwc2_hsotg_ep), 487462306a36Sopenharmony_ci GFP_KERNEL); 487562306a36Sopenharmony_ci if (!hsotg->eps_in[0]) 487662306a36Sopenharmony_ci return -ENOMEM; 487762306a36Sopenharmony_ci /* Same dwc2_hsotg_ep is used in both directions for ep0 */ 487862306a36Sopenharmony_ci hsotg->eps_out[0] = hsotg->eps_in[0]; 487962306a36Sopenharmony_ci 488062306a36Sopenharmony_ci cfg = hsotg->hw_params.dev_ep_dirs; 488162306a36Sopenharmony_ci for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) { 488262306a36Sopenharmony_ci ep_type = cfg & 3; 488362306a36Sopenharmony_ci /* Direction in or both */ 488462306a36Sopenharmony_ci if (!(ep_type & 2)) { 488562306a36Sopenharmony_ci hsotg->eps_in[i] = devm_kzalloc(hsotg->dev, 488662306a36Sopenharmony_ci sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 488762306a36Sopenharmony_ci if (!hsotg->eps_in[i]) 488862306a36Sopenharmony_ci return -ENOMEM; 488962306a36Sopenharmony_ci } 489062306a36Sopenharmony_ci /* Direction out or both */ 489162306a36Sopenharmony_ci if (!(ep_type & 1)) { 489262306a36Sopenharmony_ci hsotg->eps_out[i] = devm_kzalloc(hsotg->dev, 489362306a36Sopenharmony_ci sizeof(struct dwc2_hsotg_ep), GFP_KERNEL); 489462306a36Sopenharmony_ci if (!hsotg->eps_out[i]) 489562306a36Sopenharmony_ci return -ENOMEM; 489662306a36Sopenharmony_ci } 489762306a36Sopenharmony_ci } 489862306a36Sopenharmony_ci 489962306a36Sopenharmony_ci hsotg->fifo_mem = hsotg->hw_params.total_fifo_size; 490062306a36Sopenharmony_ci hsotg->dedicated_fifos = hsotg->hw_params.en_multiple_tx_fifo; 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n", 490362306a36Sopenharmony_ci hsotg->num_of_eps, 490462306a36Sopenharmony_ci hsotg->dedicated_fifos ? "dedicated" : "shared", 490562306a36Sopenharmony_ci hsotg->fifo_mem); 490662306a36Sopenharmony_ci return 0; 490762306a36Sopenharmony_ci} 490862306a36Sopenharmony_ci 490962306a36Sopenharmony_ci/** 491062306a36Sopenharmony_ci * dwc2_hsotg_dump - dump state of the udc 491162306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 491262306a36Sopenharmony_ci * 491362306a36Sopenharmony_ci */ 491462306a36Sopenharmony_cistatic void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) 491562306a36Sopenharmony_ci{ 491662306a36Sopenharmony_ci#ifdef DEBUG 491762306a36Sopenharmony_ci struct device *dev = hsotg->dev; 491862306a36Sopenharmony_ci u32 val; 491962306a36Sopenharmony_ci int idx; 492062306a36Sopenharmony_ci 492162306a36Sopenharmony_ci dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", 492262306a36Sopenharmony_ci dwc2_readl(hsotg, DCFG), dwc2_readl(hsotg, DCTL), 492362306a36Sopenharmony_ci dwc2_readl(hsotg, DIEPMSK)); 492462306a36Sopenharmony_ci 492562306a36Sopenharmony_ci dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n", 492662306a36Sopenharmony_ci dwc2_readl(hsotg, GAHBCFG), dwc2_readl(hsotg, GHWCFG1)); 492762306a36Sopenharmony_ci 492862306a36Sopenharmony_ci dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", 492962306a36Sopenharmony_ci dwc2_readl(hsotg, GRXFSIZ), dwc2_readl(hsotg, GNPTXFSIZ)); 493062306a36Sopenharmony_ci 493162306a36Sopenharmony_ci /* show periodic fifo settings */ 493262306a36Sopenharmony_ci 493362306a36Sopenharmony_ci for (idx = 1; idx < hsotg->num_of_eps; idx++) { 493462306a36Sopenharmony_ci val = dwc2_readl(hsotg, DPTXFSIZN(idx)); 493562306a36Sopenharmony_ci dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, 493662306a36Sopenharmony_ci val >> FIFOSIZE_DEPTH_SHIFT, 493762306a36Sopenharmony_ci val & FIFOSIZE_STARTADDR_MASK); 493862306a36Sopenharmony_ci } 493962306a36Sopenharmony_ci 494062306a36Sopenharmony_ci for (idx = 0; idx < hsotg->num_of_eps; idx++) { 494162306a36Sopenharmony_ci dev_info(dev, 494262306a36Sopenharmony_ci "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, 494362306a36Sopenharmony_ci dwc2_readl(hsotg, DIEPCTL(idx)), 494462306a36Sopenharmony_ci dwc2_readl(hsotg, DIEPTSIZ(idx)), 494562306a36Sopenharmony_ci dwc2_readl(hsotg, DIEPDMA(idx))); 494662306a36Sopenharmony_ci 494762306a36Sopenharmony_ci val = dwc2_readl(hsotg, DOEPCTL(idx)); 494862306a36Sopenharmony_ci dev_info(dev, 494962306a36Sopenharmony_ci "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", 495062306a36Sopenharmony_ci idx, dwc2_readl(hsotg, DOEPCTL(idx)), 495162306a36Sopenharmony_ci dwc2_readl(hsotg, DOEPTSIZ(idx)), 495262306a36Sopenharmony_ci dwc2_readl(hsotg, DOEPDMA(idx))); 495362306a36Sopenharmony_ci } 495462306a36Sopenharmony_ci 495562306a36Sopenharmony_ci dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", 495662306a36Sopenharmony_ci dwc2_readl(hsotg, DVBUSDIS), dwc2_readl(hsotg, DVBUSPULSE)); 495762306a36Sopenharmony_ci#endif 495862306a36Sopenharmony_ci} 495962306a36Sopenharmony_ci 496062306a36Sopenharmony_ci/** 496162306a36Sopenharmony_ci * dwc2_gadget_init - init function for gadget 496262306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 496362306a36Sopenharmony_ci * 496462306a36Sopenharmony_ci */ 496562306a36Sopenharmony_ciint dwc2_gadget_init(struct dwc2_hsotg *hsotg) 496662306a36Sopenharmony_ci{ 496762306a36Sopenharmony_ci struct device *dev = hsotg->dev; 496862306a36Sopenharmony_ci int epnum; 496962306a36Sopenharmony_ci int ret; 497062306a36Sopenharmony_ci 497162306a36Sopenharmony_ci /* Dump fifo information */ 497262306a36Sopenharmony_ci dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", 497362306a36Sopenharmony_ci hsotg->params.g_np_tx_fifo_size); 497462306a36Sopenharmony_ci dev_dbg(dev, "RXFIFO size: %d\n", hsotg->params.g_rx_fifo_size); 497562306a36Sopenharmony_ci 497662306a36Sopenharmony_ci switch (hsotg->params.speed) { 497762306a36Sopenharmony_ci case DWC2_SPEED_PARAM_LOW: 497862306a36Sopenharmony_ci hsotg->gadget.max_speed = USB_SPEED_LOW; 497962306a36Sopenharmony_ci break; 498062306a36Sopenharmony_ci case DWC2_SPEED_PARAM_FULL: 498162306a36Sopenharmony_ci hsotg->gadget.max_speed = USB_SPEED_FULL; 498262306a36Sopenharmony_ci break; 498362306a36Sopenharmony_ci default: 498462306a36Sopenharmony_ci hsotg->gadget.max_speed = USB_SPEED_HIGH; 498562306a36Sopenharmony_ci break; 498662306a36Sopenharmony_ci } 498762306a36Sopenharmony_ci 498862306a36Sopenharmony_ci hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; 498962306a36Sopenharmony_ci hsotg->gadget.name = dev_name(dev); 499062306a36Sopenharmony_ci hsotg->gadget.otg_caps = &hsotg->params.otg_caps; 499162306a36Sopenharmony_ci hsotg->remote_wakeup_allowed = 0; 499262306a36Sopenharmony_ci 499362306a36Sopenharmony_ci if (hsotg->params.lpm) 499462306a36Sopenharmony_ci hsotg->gadget.lpm_capable = true; 499562306a36Sopenharmony_ci 499662306a36Sopenharmony_ci if (hsotg->dr_mode == USB_DR_MODE_OTG) 499762306a36Sopenharmony_ci hsotg->gadget.is_otg = 1; 499862306a36Sopenharmony_ci else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) 499962306a36Sopenharmony_ci hsotg->op_state = OTG_STATE_B_PERIPHERAL; 500062306a36Sopenharmony_ci 500162306a36Sopenharmony_ci ret = dwc2_hsotg_hw_cfg(hsotg); 500262306a36Sopenharmony_ci if (ret) { 500362306a36Sopenharmony_ci dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret); 500462306a36Sopenharmony_ci return ret; 500562306a36Sopenharmony_ci } 500662306a36Sopenharmony_ci 500762306a36Sopenharmony_ci hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, 500862306a36Sopenharmony_ci DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 500962306a36Sopenharmony_ci if (!hsotg->ctrl_buff) 501062306a36Sopenharmony_ci return -ENOMEM; 501162306a36Sopenharmony_ci 501262306a36Sopenharmony_ci hsotg->ep0_buff = devm_kzalloc(hsotg->dev, 501362306a36Sopenharmony_ci DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); 501462306a36Sopenharmony_ci if (!hsotg->ep0_buff) 501562306a36Sopenharmony_ci return -ENOMEM; 501662306a36Sopenharmony_ci 501762306a36Sopenharmony_ci if (using_desc_dma(hsotg)) { 501862306a36Sopenharmony_ci ret = dwc2_gadget_alloc_ctrl_desc_chains(hsotg); 501962306a36Sopenharmony_ci if (ret < 0) 502062306a36Sopenharmony_ci return ret; 502162306a36Sopenharmony_ci } 502262306a36Sopenharmony_ci 502362306a36Sopenharmony_ci ret = devm_request_irq(hsotg->dev, hsotg->irq, dwc2_hsotg_irq, 502462306a36Sopenharmony_ci IRQF_SHARED, dev_name(hsotg->dev), hsotg); 502562306a36Sopenharmony_ci if (ret < 0) { 502662306a36Sopenharmony_ci dev_err(dev, "cannot claim IRQ for gadget\n"); 502762306a36Sopenharmony_ci return ret; 502862306a36Sopenharmony_ci } 502962306a36Sopenharmony_ci 503062306a36Sopenharmony_ci /* hsotg->num_of_eps holds number of EPs other than ep0 */ 503162306a36Sopenharmony_ci 503262306a36Sopenharmony_ci if (hsotg->num_of_eps == 0) { 503362306a36Sopenharmony_ci dev_err(dev, "wrong number of EPs (zero)\n"); 503462306a36Sopenharmony_ci return -EINVAL; 503562306a36Sopenharmony_ci } 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_ci /* setup endpoint information */ 503862306a36Sopenharmony_ci 503962306a36Sopenharmony_ci INIT_LIST_HEAD(&hsotg->gadget.ep_list); 504062306a36Sopenharmony_ci hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep; 504162306a36Sopenharmony_ci 504262306a36Sopenharmony_ci /* allocate EP0 request */ 504362306a36Sopenharmony_ci 504462306a36Sopenharmony_ci hsotg->ctrl_req = dwc2_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep, 504562306a36Sopenharmony_ci GFP_KERNEL); 504662306a36Sopenharmony_ci if (!hsotg->ctrl_req) { 504762306a36Sopenharmony_ci dev_err(dev, "failed to allocate ctrl req\n"); 504862306a36Sopenharmony_ci return -ENOMEM; 504962306a36Sopenharmony_ci } 505062306a36Sopenharmony_ci 505162306a36Sopenharmony_ci /* initialise the endpoints now the core has been initialised */ 505262306a36Sopenharmony_ci for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { 505362306a36Sopenharmony_ci if (hsotg->eps_in[epnum]) 505462306a36Sopenharmony_ci dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], 505562306a36Sopenharmony_ci epnum, 1); 505662306a36Sopenharmony_ci if (hsotg->eps_out[epnum]) 505762306a36Sopenharmony_ci dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], 505862306a36Sopenharmony_ci epnum, 0); 505962306a36Sopenharmony_ci } 506062306a36Sopenharmony_ci 506162306a36Sopenharmony_ci dwc2_hsotg_dump(hsotg); 506262306a36Sopenharmony_ci 506362306a36Sopenharmony_ci return 0; 506462306a36Sopenharmony_ci} 506562306a36Sopenharmony_ci 506662306a36Sopenharmony_ci/** 506762306a36Sopenharmony_ci * dwc2_hsotg_remove - remove function for hsotg driver 506862306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 506962306a36Sopenharmony_ci * 507062306a36Sopenharmony_ci */ 507162306a36Sopenharmony_ciint dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) 507262306a36Sopenharmony_ci{ 507362306a36Sopenharmony_ci usb_del_gadget_udc(&hsotg->gadget); 507462306a36Sopenharmony_ci dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep, hsotg->ctrl_req); 507562306a36Sopenharmony_ci 507662306a36Sopenharmony_ci return 0; 507762306a36Sopenharmony_ci} 507862306a36Sopenharmony_ci 507962306a36Sopenharmony_ciint dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) 508062306a36Sopenharmony_ci{ 508162306a36Sopenharmony_ci unsigned long flags; 508262306a36Sopenharmony_ci 508362306a36Sopenharmony_ci if (hsotg->lx_state != DWC2_L0) 508462306a36Sopenharmony_ci return 0; 508562306a36Sopenharmony_ci 508662306a36Sopenharmony_ci if (hsotg->driver) { 508762306a36Sopenharmony_ci int ep; 508862306a36Sopenharmony_ci 508962306a36Sopenharmony_ci dev_info(hsotg->dev, "suspending usb gadget %s\n", 509062306a36Sopenharmony_ci hsotg->driver->driver.name); 509162306a36Sopenharmony_ci 509262306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 509362306a36Sopenharmony_ci if (hsotg->enabled) 509462306a36Sopenharmony_ci dwc2_hsotg_core_disconnect(hsotg); 509562306a36Sopenharmony_ci dwc2_hsotg_disconnect(hsotg); 509662306a36Sopenharmony_ci hsotg->gadget.speed = USB_SPEED_UNKNOWN; 509762306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 509862306a36Sopenharmony_ci 509962306a36Sopenharmony_ci for (ep = 1; ep < hsotg->num_of_eps; ep++) { 510062306a36Sopenharmony_ci if (hsotg->eps_in[ep]) 510162306a36Sopenharmony_ci dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); 510262306a36Sopenharmony_ci if (hsotg->eps_out[ep]) 510362306a36Sopenharmony_ci dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); 510462306a36Sopenharmony_ci } 510562306a36Sopenharmony_ci } 510662306a36Sopenharmony_ci 510762306a36Sopenharmony_ci return 0; 510862306a36Sopenharmony_ci} 510962306a36Sopenharmony_ci 511062306a36Sopenharmony_ciint dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) 511162306a36Sopenharmony_ci{ 511262306a36Sopenharmony_ci unsigned long flags; 511362306a36Sopenharmony_ci 511462306a36Sopenharmony_ci if (hsotg->lx_state == DWC2_L2) 511562306a36Sopenharmony_ci return 0; 511662306a36Sopenharmony_ci 511762306a36Sopenharmony_ci if (hsotg->driver) { 511862306a36Sopenharmony_ci dev_info(hsotg->dev, "resuming usb gadget %s\n", 511962306a36Sopenharmony_ci hsotg->driver->driver.name); 512062306a36Sopenharmony_ci 512162306a36Sopenharmony_ci spin_lock_irqsave(&hsotg->lock, flags); 512262306a36Sopenharmony_ci dwc2_hsotg_core_init_disconnected(hsotg, false); 512362306a36Sopenharmony_ci if (hsotg->enabled) { 512462306a36Sopenharmony_ci /* Enable ACG feature in device mode,if supported */ 512562306a36Sopenharmony_ci dwc2_enable_acg(hsotg); 512662306a36Sopenharmony_ci dwc2_hsotg_core_connect(hsotg); 512762306a36Sopenharmony_ci } 512862306a36Sopenharmony_ci spin_unlock_irqrestore(&hsotg->lock, flags); 512962306a36Sopenharmony_ci } 513062306a36Sopenharmony_ci 513162306a36Sopenharmony_ci return 0; 513262306a36Sopenharmony_ci} 513362306a36Sopenharmony_ci 513462306a36Sopenharmony_ci/** 513562306a36Sopenharmony_ci * dwc2_backup_device_registers() - Backup controller device registers. 513662306a36Sopenharmony_ci * When suspending usb bus, registers needs to be backuped 513762306a36Sopenharmony_ci * if controller power is disabled once suspended. 513862306a36Sopenharmony_ci * 513962306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 514062306a36Sopenharmony_ci */ 514162306a36Sopenharmony_ciint dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) 514262306a36Sopenharmony_ci{ 514362306a36Sopenharmony_ci struct dwc2_dregs_backup *dr; 514462306a36Sopenharmony_ci int i; 514562306a36Sopenharmony_ci 514662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s\n", __func__); 514762306a36Sopenharmony_ci 514862306a36Sopenharmony_ci /* Backup dev regs */ 514962306a36Sopenharmony_ci dr = &hsotg->dr_backup; 515062306a36Sopenharmony_ci 515162306a36Sopenharmony_ci dr->dcfg = dwc2_readl(hsotg, DCFG); 515262306a36Sopenharmony_ci dr->dctl = dwc2_readl(hsotg, DCTL); 515362306a36Sopenharmony_ci dr->daintmsk = dwc2_readl(hsotg, DAINTMSK); 515462306a36Sopenharmony_ci dr->diepmsk = dwc2_readl(hsotg, DIEPMSK); 515562306a36Sopenharmony_ci dr->doepmsk = dwc2_readl(hsotg, DOEPMSK); 515662306a36Sopenharmony_ci 515762306a36Sopenharmony_ci for (i = 0; i < hsotg->num_of_eps; i++) { 515862306a36Sopenharmony_ci /* Backup IN EPs */ 515962306a36Sopenharmony_ci dr->diepctl[i] = dwc2_readl(hsotg, DIEPCTL(i)); 516062306a36Sopenharmony_ci 516162306a36Sopenharmony_ci /* Ensure DATA PID is correctly configured */ 516262306a36Sopenharmony_ci if (dr->diepctl[i] & DXEPCTL_DPID) 516362306a36Sopenharmony_ci dr->diepctl[i] |= DXEPCTL_SETD1PID; 516462306a36Sopenharmony_ci else 516562306a36Sopenharmony_ci dr->diepctl[i] |= DXEPCTL_SETD0PID; 516662306a36Sopenharmony_ci 516762306a36Sopenharmony_ci dr->dieptsiz[i] = dwc2_readl(hsotg, DIEPTSIZ(i)); 516862306a36Sopenharmony_ci dr->diepdma[i] = dwc2_readl(hsotg, DIEPDMA(i)); 516962306a36Sopenharmony_ci 517062306a36Sopenharmony_ci /* Backup OUT EPs */ 517162306a36Sopenharmony_ci dr->doepctl[i] = dwc2_readl(hsotg, DOEPCTL(i)); 517262306a36Sopenharmony_ci 517362306a36Sopenharmony_ci /* Ensure DATA PID is correctly configured */ 517462306a36Sopenharmony_ci if (dr->doepctl[i] & DXEPCTL_DPID) 517562306a36Sopenharmony_ci dr->doepctl[i] |= DXEPCTL_SETD1PID; 517662306a36Sopenharmony_ci else 517762306a36Sopenharmony_ci dr->doepctl[i] |= DXEPCTL_SETD0PID; 517862306a36Sopenharmony_ci 517962306a36Sopenharmony_ci dr->doeptsiz[i] = dwc2_readl(hsotg, DOEPTSIZ(i)); 518062306a36Sopenharmony_ci dr->doepdma[i] = dwc2_readl(hsotg, DOEPDMA(i)); 518162306a36Sopenharmony_ci dr->dtxfsiz[i] = dwc2_readl(hsotg, DPTXFSIZN(i)); 518262306a36Sopenharmony_ci } 518362306a36Sopenharmony_ci dr->valid = true; 518462306a36Sopenharmony_ci return 0; 518562306a36Sopenharmony_ci} 518662306a36Sopenharmony_ci 518762306a36Sopenharmony_ci/** 518862306a36Sopenharmony_ci * dwc2_restore_device_registers() - Restore controller device registers. 518962306a36Sopenharmony_ci * When resuming usb bus, device registers needs to be restored 519062306a36Sopenharmony_ci * if controller power were disabled. 519162306a36Sopenharmony_ci * 519262306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 519362306a36Sopenharmony_ci * @remote_wakeup: Indicates whether resume is initiated by Device or Host. 519462306a36Sopenharmony_ci * 519562306a36Sopenharmony_ci * Return: 0 if successful, negative error code otherwise 519662306a36Sopenharmony_ci */ 519762306a36Sopenharmony_ciint dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup) 519862306a36Sopenharmony_ci{ 519962306a36Sopenharmony_ci struct dwc2_dregs_backup *dr; 520062306a36Sopenharmony_ci int i; 520162306a36Sopenharmony_ci 520262306a36Sopenharmony_ci dev_dbg(hsotg->dev, "%s\n", __func__); 520362306a36Sopenharmony_ci 520462306a36Sopenharmony_ci /* Restore dev regs */ 520562306a36Sopenharmony_ci dr = &hsotg->dr_backup; 520662306a36Sopenharmony_ci if (!dr->valid) { 520762306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: no device registers to restore\n", 520862306a36Sopenharmony_ci __func__); 520962306a36Sopenharmony_ci return -EINVAL; 521062306a36Sopenharmony_ci } 521162306a36Sopenharmony_ci dr->valid = false; 521262306a36Sopenharmony_ci 521362306a36Sopenharmony_ci if (!remote_wakeup) 521462306a36Sopenharmony_ci dwc2_writel(hsotg, dr->dctl, DCTL); 521562306a36Sopenharmony_ci 521662306a36Sopenharmony_ci dwc2_writel(hsotg, dr->daintmsk, DAINTMSK); 521762306a36Sopenharmony_ci dwc2_writel(hsotg, dr->diepmsk, DIEPMSK); 521862306a36Sopenharmony_ci dwc2_writel(hsotg, dr->doepmsk, DOEPMSK); 521962306a36Sopenharmony_ci 522062306a36Sopenharmony_ci for (i = 0; i < hsotg->num_of_eps; i++) { 522162306a36Sopenharmony_ci /* Restore IN EPs */ 522262306a36Sopenharmony_ci dwc2_writel(hsotg, dr->dieptsiz[i], DIEPTSIZ(i)); 522362306a36Sopenharmony_ci dwc2_writel(hsotg, dr->diepdma[i], DIEPDMA(i)); 522462306a36Sopenharmony_ci dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i)); 522562306a36Sopenharmony_ci /** WA for enabled EPx's IN in DDMA mode. On entering to 522662306a36Sopenharmony_ci * hibernation wrong value read and saved from DIEPDMAx, 522762306a36Sopenharmony_ci * as result BNA interrupt asserted on hibernation exit 522862306a36Sopenharmony_ci * by restoring from saved area. 522962306a36Sopenharmony_ci */ 523062306a36Sopenharmony_ci if (using_desc_dma(hsotg) && 523162306a36Sopenharmony_ci (dr->diepctl[i] & DXEPCTL_EPENA)) 523262306a36Sopenharmony_ci dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma; 523362306a36Sopenharmony_ci dwc2_writel(hsotg, dr->dtxfsiz[i], DPTXFSIZN(i)); 523462306a36Sopenharmony_ci dwc2_writel(hsotg, dr->diepctl[i], DIEPCTL(i)); 523562306a36Sopenharmony_ci /* Restore OUT EPs */ 523662306a36Sopenharmony_ci dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i)); 523762306a36Sopenharmony_ci /* WA for enabled EPx's OUT in DDMA mode. On entering to 523862306a36Sopenharmony_ci * hibernation wrong value read and saved from DOEPDMAx, 523962306a36Sopenharmony_ci * as result BNA interrupt asserted on hibernation exit 524062306a36Sopenharmony_ci * by restoring from saved area. 524162306a36Sopenharmony_ci */ 524262306a36Sopenharmony_ci if (using_desc_dma(hsotg) && 524362306a36Sopenharmony_ci (dr->doepctl[i] & DXEPCTL_EPENA)) 524462306a36Sopenharmony_ci dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma; 524562306a36Sopenharmony_ci dwc2_writel(hsotg, dr->doepdma[i], DOEPDMA(i)); 524662306a36Sopenharmony_ci dwc2_writel(hsotg, dr->doepctl[i], DOEPCTL(i)); 524762306a36Sopenharmony_ci } 524862306a36Sopenharmony_ci 524962306a36Sopenharmony_ci return 0; 525062306a36Sopenharmony_ci} 525162306a36Sopenharmony_ci 525262306a36Sopenharmony_ci/** 525362306a36Sopenharmony_ci * dwc2_gadget_init_lpm - Configure the core to support LPM in device mode 525462306a36Sopenharmony_ci * 525562306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 525662306a36Sopenharmony_ci * 525762306a36Sopenharmony_ci */ 525862306a36Sopenharmony_civoid dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) 525962306a36Sopenharmony_ci{ 526062306a36Sopenharmony_ci u32 val; 526162306a36Sopenharmony_ci 526262306a36Sopenharmony_ci if (!hsotg->params.lpm) 526362306a36Sopenharmony_ci return; 526462306a36Sopenharmony_ci 526562306a36Sopenharmony_ci val = GLPMCFG_LPMCAP | GLPMCFG_APPL1RES; 526662306a36Sopenharmony_ci val |= hsotg->params.hird_threshold_en ? GLPMCFG_HIRD_THRES_EN : 0; 526762306a36Sopenharmony_ci val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; 526862306a36Sopenharmony_ci val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; 526962306a36Sopenharmony_ci val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; 527062306a36Sopenharmony_ci val |= GLPMCFG_LPM_REJECT_CTRL_CONTROL; 527162306a36Sopenharmony_ci val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC; 527262306a36Sopenharmony_ci dwc2_writel(hsotg, val, GLPMCFG); 527362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); 527462306a36Sopenharmony_ci 527562306a36Sopenharmony_ci /* Unmask WKUP_ALERT Interrupt */ 527662306a36Sopenharmony_ci if (hsotg->params.service_interval) 527762306a36Sopenharmony_ci dwc2_set_bit(hsotg, GINTMSK2, GINTMSK2_WKUP_ALERT_INT_MSK); 527862306a36Sopenharmony_ci} 527962306a36Sopenharmony_ci 528062306a36Sopenharmony_ci/** 528162306a36Sopenharmony_ci * dwc2_gadget_program_ref_clk - Program GREFCLK register in device mode 528262306a36Sopenharmony_ci * 528362306a36Sopenharmony_ci * @hsotg: Programming view of DWC_otg controller 528462306a36Sopenharmony_ci * 528562306a36Sopenharmony_ci */ 528662306a36Sopenharmony_civoid dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) 528762306a36Sopenharmony_ci{ 528862306a36Sopenharmony_ci u32 val = 0; 528962306a36Sopenharmony_ci 529062306a36Sopenharmony_ci val |= GREFCLK_REF_CLK_MODE; 529162306a36Sopenharmony_ci val |= hsotg->params.ref_clk_per << GREFCLK_REFCLKPER_SHIFT; 529262306a36Sopenharmony_ci val |= hsotg->params.sof_cnt_wkup_alert << 529362306a36Sopenharmony_ci GREFCLK_SOF_CNT_WKUP_ALERT_SHIFT; 529462306a36Sopenharmony_ci 529562306a36Sopenharmony_ci dwc2_writel(hsotg, val, GREFCLK); 529662306a36Sopenharmony_ci dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK)); 529762306a36Sopenharmony_ci} 529862306a36Sopenharmony_ci 529962306a36Sopenharmony_ci/** 530062306a36Sopenharmony_ci * dwc2_gadget_enter_hibernation() - Put controller in Hibernation. 530162306a36Sopenharmony_ci * 530262306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 530362306a36Sopenharmony_ci * 530462306a36Sopenharmony_ci * Return non-zero if failed to enter to hibernation. 530562306a36Sopenharmony_ci */ 530662306a36Sopenharmony_ciint dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg) 530762306a36Sopenharmony_ci{ 530862306a36Sopenharmony_ci u32 gpwrdn; 530962306a36Sopenharmony_ci int ret = 0; 531062306a36Sopenharmony_ci 531162306a36Sopenharmony_ci /* Change to L2(suspend) state */ 531262306a36Sopenharmony_ci hsotg->lx_state = DWC2_L2; 531362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Start of hibernation completed\n"); 531462306a36Sopenharmony_ci ret = dwc2_backup_global_registers(hsotg); 531562306a36Sopenharmony_ci if (ret) { 531662306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup global registers\n", 531762306a36Sopenharmony_ci __func__); 531862306a36Sopenharmony_ci return ret; 531962306a36Sopenharmony_ci } 532062306a36Sopenharmony_ci ret = dwc2_backup_device_registers(hsotg); 532162306a36Sopenharmony_ci if (ret) { 532262306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup device registers\n", 532362306a36Sopenharmony_ci __func__); 532462306a36Sopenharmony_ci return ret; 532562306a36Sopenharmony_ci } 532662306a36Sopenharmony_ci 532762306a36Sopenharmony_ci gpwrdn = GPWRDN_PWRDNRSTN; 532862306a36Sopenharmony_ci gpwrdn |= GPWRDN_PMUACTV; 532962306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 533062306a36Sopenharmony_ci udelay(10); 533162306a36Sopenharmony_ci 533262306a36Sopenharmony_ci /* Set flag to indicate that we are in hibernation */ 533362306a36Sopenharmony_ci hsotg->hibernated = 1; 533462306a36Sopenharmony_ci 533562306a36Sopenharmony_ci /* Enable interrupts from wake up logic */ 533662306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 533762306a36Sopenharmony_ci gpwrdn |= GPWRDN_PMUINTSEL; 533862306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 533962306a36Sopenharmony_ci udelay(10); 534062306a36Sopenharmony_ci 534162306a36Sopenharmony_ci /* Unmask device mode interrupts in GPWRDN */ 534262306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 534362306a36Sopenharmony_ci gpwrdn |= GPWRDN_RST_DET_MSK; 534462306a36Sopenharmony_ci gpwrdn |= GPWRDN_LNSTSCHG_MSK; 534562306a36Sopenharmony_ci gpwrdn |= GPWRDN_STS_CHGINT_MSK; 534662306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 534762306a36Sopenharmony_ci udelay(10); 534862306a36Sopenharmony_ci 534962306a36Sopenharmony_ci /* Enable Power Down Clamp */ 535062306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 535162306a36Sopenharmony_ci gpwrdn |= GPWRDN_PWRDNCLMP; 535262306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 535362306a36Sopenharmony_ci udelay(10); 535462306a36Sopenharmony_ci 535562306a36Sopenharmony_ci /* Switch off VDD */ 535662306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 535762306a36Sopenharmony_ci gpwrdn |= GPWRDN_PWRDNSWTCH; 535862306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 535962306a36Sopenharmony_ci udelay(10); 536062306a36Sopenharmony_ci 536162306a36Sopenharmony_ci /* Save gpwrdn register for further usage if stschng interrupt */ 536262306a36Sopenharmony_ci hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg, GPWRDN); 536362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Hibernation completed\n"); 536462306a36Sopenharmony_ci 536562306a36Sopenharmony_ci return ret; 536662306a36Sopenharmony_ci} 536762306a36Sopenharmony_ci 536862306a36Sopenharmony_ci/** 536962306a36Sopenharmony_ci * dwc2_gadget_exit_hibernation() 537062306a36Sopenharmony_ci * This function is for exiting from Device mode hibernation by host initiated 537162306a36Sopenharmony_ci * resume/reset and device initiated remote-wakeup. 537262306a36Sopenharmony_ci * 537362306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 537462306a36Sopenharmony_ci * @rem_wakeup: indicates whether resume is initiated by Device or Host. 537562306a36Sopenharmony_ci * @reset: indicates whether resume is initiated by Reset. 537662306a36Sopenharmony_ci * 537762306a36Sopenharmony_ci * Return non-zero if failed to exit from hibernation. 537862306a36Sopenharmony_ci */ 537962306a36Sopenharmony_ciint dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg, 538062306a36Sopenharmony_ci int rem_wakeup, int reset) 538162306a36Sopenharmony_ci{ 538262306a36Sopenharmony_ci u32 pcgcctl; 538362306a36Sopenharmony_ci u32 gpwrdn; 538462306a36Sopenharmony_ci u32 dctl; 538562306a36Sopenharmony_ci int ret = 0; 538662306a36Sopenharmony_ci struct dwc2_gregs_backup *gr; 538762306a36Sopenharmony_ci struct dwc2_dregs_backup *dr; 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_ci gr = &hsotg->gr_backup; 539062306a36Sopenharmony_ci dr = &hsotg->dr_backup; 539162306a36Sopenharmony_ci 539262306a36Sopenharmony_ci if (!hsotg->hibernated) { 539362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Already exited from Hibernation\n"); 539462306a36Sopenharmony_ci return 1; 539562306a36Sopenharmony_ci } 539662306a36Sopenharmony_ci dev_dbg(hsotg->dev, 539762306a36Sopenharmony_ci "%s: called with rem_wakeup = %d reset = %d\n", 539862306a36Sopenharmony_ci __func__, rem_wakeup, reset); 539962306a36Sopenharmony_ci 540062306a36Sopenharmony_ci dwc2_hib_restore_common(hsotg, rem_wakeup, 0); 540162306a36Sopenharmony_ci 540262306a36Sopenharmony_ci if (!reset) { 540362306a36Sopenharmony_ci /* Clear all pending interupts */ 540462306a36Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 540562306a36Sopenharmony_ci } 540662306a36Sopenharmony_ci 540762306a36Sopenharmony_ci /* De-assert Restore */ 540862306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 540962306a36Sopenharmony_ci gpwrdn &= ~GPWRDN_RESTORE; 541062306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 541162306a36Sopenharmony_ci udelay(10); 541262306a36Sopenharmony_ci 541362306a36Sopenharmony_ci if (!rem_wakeup) { 541462306a36Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 541562306a36Sopenharmony_ci pcgcctl &= ~PCGCTL_RSTPDWNMODULE; 541662306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 541762306a36Sopenharmony_ci } 541862306a36Sopenharmony_ci 541962306a36Sopenharmony_ci /* Restore GUSBCFG, DCFG and DCTL */ 542062306a36Sopenharmony_ci dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG); 542162306a36Sopenharmony_ci dwc2_writel(hsotg, dr->dcfg, DCFG); 542262306a36Sopenharmony_ci dwc2_writel(hsotg, dr->dctl, DCTL); 542362306a36Sopenharmony_ci 542462306a36Sopenharmony_ci /* On USB Reset, reset device address to zero */ 542562306a36Sopenharmony_ci if (reset) 542662306a36Sopenharmony_ci dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK); 542762306a36Sopenharmony_ci 542862306a36Sopenharmony_ci /* De-assert Wakeup Logic */ 542962306a36Sopenharmony_ci gpwrdn = dwc2_readl(hsotg, GPWRDN); 543062306a36Sopenharmony_ci gpwrdn &= ~GPWRDN_PMUACTV; 543162306a36Sopenharmony_ci dwc2_writel(hsotg, gpwrdn, GPWRDN); 543262306a36Sopenharmony_ci 543362306a36Sopenharmony_ci if (rem_wakeup) { 543462306a36Sopenharmony_ci udelay(10); 543562306a36Sopenharmony_ci /* Start Remote Wakeup Signaling */ 543662306a36Sopenharmony_ci dwc2_writel(hsotg, dr->dctl | DCTL_RMTWKUPSIG, DCTL); 543762306a36Sopenharmony_ci } else { 543862306a36Sopenharmony_ci udelay(50); 543962306a36Sopenharmony_ci /* Set Device programming done bit */ 544062306a36Sopenharmony_ci dctl = dwc2_readl(hsotg, DCTL); 544162306a36Sopenharmony_ci dctl |= DCTL_PWRONPRGDONE; 544262306a36Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 544362306a36Sopenharmony_ci } 544462306a36Sopenharmony_ci /* Wait for interrupts which must be cleared */ 544562306a36Sopenharmony_ci mdelay(2); 544662306a36Sopenharmony_ci /* Clear all pending interupts */ 544762306a36Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 544862306a36Sopenharmony_ci 544962306a36Sopenharmony_ci /* Restore global registers */ 545062306a36Sopenharmony_ci ret = dwc2_restore_global_registers(hsotg); 545162306a36Sopenharmony_ci if (ret) { 545262306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore registers\n", 545362306a36Sopenharmony_ci __func__); 545462306a36Sopenharmony_ci return ret; 545562306a36Sopenharmony_ci } 545662306a36Sopenharmony_ci 545762306a36Sopenharmony_ci /* Restore device registers */ 545862306a36Sopenharmony_ci ret = dwc2_restore_device_registers(hsotg, rem_wakeup); 545962306a36Sopenharmony_ci if (ret) { 546062306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore device registers\n", 546162306a36Sopenharmony_ci __func__); 546262306a36Sopenharmony_ci return ret; 546362306a36Sopenharmony_ci } 546462306a36Sopenharmony_ci 546562306a36Sopenharmony_ci if (rem_wakeup) { 546662306a36Sopenharmony_ci mdelay(10); 546762306a36Sopenharmony_ci dctl = dwc2_readl(hsotg, DCTL); 546862306a36Sopenharmony_ci dctl &= ~DCTL_RMTWKUPSIG; 546962306a36Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 547062306a36Sopenharmony_ci } 547162306a36Sopenharmony_ci 547262306a36Sopenharmony_ci hsotg->hibernated = 0; 547362306a36Sopenharmony_ci hsotg->lx_state = DWC2_L0; 547462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Hibernation recovery completes here\n"); 547562306a36Sopenharmony_ci 547662306a36Sopenharmony_ci return ret; 547762306a36Sopenharmony_ci} 547862306a36Sopenharmony_ci 547962306a36Sopenharmony_ci/** 548062306a36Sopenharmony_ci * dwc2_gadget_enter_partial_power_down() - Put controller in partial 548162306a36Sopenharmony_ci * power down. 548262306a36Sopenharmony_ci * 548362306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 548462306a36Sopenharmony_ci * 548562306a36Sopenharmony_ci * Return: non-zero if failed to enter device partial power down. 548662306a36Sopenharmony_ci * 548762306a36Sopenharmony_ci * This function is for entering device mode partial power down. 548862306a36Sopenharmony_ci */ 548962306a36Sopenharmony_ciint dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg) 549062306a36Sopenharmony_ci{ 549162306a36Sopenharmony_ci u32 pcgcctl; 549262306a36Sopenharmony_ci int ret = 0; 549362306a36Sopenharmony_ci 549462306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Entering device partial power down started.\n"); 549562306a36Sopenharmony_ci 549662306a36Sopenharmony_ci /* Backup all registers */ 549762306a36Sopenharmony_ci ret = dwc2_backup_global_registers(hsotg); 549862306a36Sopenharmony_ci if (ret) { 549962306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup global registers\n", 550062306a36Sopenharmony_ci __func__); 550162306a36Sopenharmony_ci return ret; 550262306a36Sopenharmony_ci } 550362306a36Sopenharmony_ci 550462306a36Sopenharmony_ci ret = dwc2_backup_device_registers(hsotg); 550562306a36Sopenharmony_ci if (ret) { 550662306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to backup device registers\n", 550762306a36Sopenharmony_ci __func__); 550862306a36Sopenharmony_ci return ret; 550962306a36Sopenharmony_ci } 551062306a36Sopenharmony_ci 551162306a36Sopenharmony_ci /* 551262306a36Sopenharmony_ci * Clear any pending interrupts since dwc2 will not be able to 551362306a36Sopenharmony_ci * clear them after entering partial_power_down. 551462306a36Sopenharmony_ci */ 551562306a36Sopenharmony_ci dwc2_writel(hsotg, 0xffffffff, GINTSTS); 551662306a36Sopenharmony_ci 551762306a36Sopenharmony_ci /* Put the controller in low power state */ 551862306a36Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 551962306a36Sopenharmony_ci 552062306a36Sopenharmony_ci pcgcctl |= PCGCTL_PWRCLMP; 552162306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 552262306a36Sopenharmony_ci udelay(5); 552362306a36Sopenharmony_ci 552462306a36Sopenharmony_ci pcgcctl |= PCGCTL_RSTPDWNMODULE; 552562306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 552662306a36Sopenharmony_ci udelay(5); 552762306a36Sopenharmony_ci 552862306a36Sopenharmony_ci pcgcctl |= PCGCTL_STOPPCLK; 552962306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 553062306a36Sopenharmony_ci 553162306a36Sopenharmony_ci /* Set in_ppd flag to 1 as here core enters suspend. */ 553262306a36Sopenharmony_ci hsotg->in_ppd = 1; 553362306a36Sopenharmony_ci hsotg->lx_state = DWC2_L2; 553462306a36Sopenharmony_ci 553562306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Entering device partial power down completed.\n"); 553662306a36Sopenharmony_ci 553762306a36Sopenharmony_ci return ret; 553862306a36Sopenharmony_ci} 553962306a36Sopenharmony_ci 554062306a36Sopenharmony_ci/* 554162306a36Sopenharmony_ci * dwc2_gadget_exit_partial_power_down() - Exit controller from device partial 554262306a36Sopenharmony_ci * power down. 554362306a36Sopenharmony_ci * 554462306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 554562306a36Sopenharmony_ci * @restore: indicates whether need to restore the registers or not. 554662306a36Sopenharmony_ci * 554762306a36Sopenharmony_ci * Return: non-zero if failed to exit device partial power down. 554862306a36Sopenharmony_ci * 554962306a36Sopenharmony_ci * This function is for exiting from device mode partial power down. 555062306a36Sopenharmony_ci */ 555162306a36Sopenharmony_ciint dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg, 555262306a36Sopenharmony_ci bool restore) 555362306a36Sopenharmony_ci{ 555462306a36Sopenharmony_ci u32 pcgcctl; 555562306a36Sopenharmony_ci u32 dctl; 555662306a36Sopenharmony_ci struct dwc2_dregs_backup *dr; 555762306a36Sopenharmony_ci int ret = 0; 555862306a36Sopenharmony_ci 555962306a36Sopenharmony_ci dr = &hsotg->dr_backup; 556062306a36Sopenharmony_ci 556162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Exiting device partial Power Down started.\n"); 556262306a36Sopenharmony_ci 556362306a36Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 556462306a36Sopenharmony_ci pcgcctl &= ~PCGCTL_STOPPCLK; 556562306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 556662306a36Sopenharmony_ci 556762306a36Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 556862306a36Sopenharmony_ci pcgcctl &= ~PCGCTL_PWRCLMP; 556962306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 557062306a36Sopenharmony_ci 557162306a36Sopenharmony_ci pcgcctl = dwc2_readl(hsotg, PCGCTL); 557262306a36Sopenharmony_ci pcgcctl &= ~PCGCTL_RSTPDWNMODULE; 557362306a36Sopenharmony_ci dwc2_writel(hsotg, pcgcctl, PCGCTL); 557462306a36Sopenharmony_ci 557562306a36Sopenharmony_ci udelay(100); 557662306a36Sopenharmony_ci if (restore) { 557762306a36Sopenharmony_ci ret = dwc2_restore_global_registers(hsotg); 557862306a36Sopenharmony_ci if (ret) { 557962306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore registers\n", 558062306a36Sopenharmony_ci __func__); 558162306a36Sopenharmony_ci return ret; 558262306a36Sopenharmony_ci } 558362306a36Sopenharmony_ci /* Restore DCFG */ 558462306a36Sopenharmony_ci dwc2_writel(hsotg, dr->dcfg, DCFG); 558562306a36Sopenharmony_ci 558662306a36Sopenharmony_ci ret = dwc2_restore_device_registers(hsotg, 0); 558762306a36Sopenharmony_ci if (ret) { 558862306a36Sopenharmony_ci dev_err(hsotg->dev, "%s: failed to restore device registers\n", 558962306a36Sopenharmony_ci __func__); 559062306a36Sopenharmony_ci return ret; 559162306a36Sopenharmony_ci } 559262306a36Sopenharmony_ci } 559362306a36Sopenharmony_ci 559462306a36Sopenharmony_ci /* Set the Power-On Programming done bit */ 559562306a36Sopenharmony_ci dctl = dwc2_readl(hsotg, DCTL); 559662306a36Sopenharmony_ci dctl |= DCTL_PWRONPRGDONE; 559762306a36Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 559862306a36Sopenharmony_ci 559962306a36Sopenharmony_ci /* Set in_ppd flag to 0 as here core exits from suspend. */ 560062306a36Sopenharmony_ci hsotg->in_ppd = 0; 560162306a36Sopenharmony_ci hsotg->lx_state = DWC2_L0; 560262306a36Sopenharmony_ci 560362306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Exiting device partial Power Down completed.\n"); 560462306a36Sopenharmony_ci return ret; 560562306a36Sopenharmony_ci} 560662306a36Sopenharmony_ci 560762306a36Sopenharmony_ci/** 560862306a36Sopenharmony_ci * dwc2_gadget_enter_clock_gating() - Put controller in clock gating. 560962306a36Sopenharmony_ci * 561062306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 561162306a36Sopenharmony_ci * 561262306a36Sopenharmony_ci * Return: non-zero if failed to enter device partial power down. 561362306a36Sopenharmony_ci * 561462306a36Sopenharmony_ci * This function is for entering device mode clock gating. 561562306a36Sopenharmony_ci */ 561662306a36Sopenharmony_civoid dwc2_gadget_enter_clock_gating(struct dwc2_hsotg *hsotg) 561762306a36Sopenharmony_ci{ 561862306a36Sopenharmony_ci u32 pcgctl; 561962306a36Sopenharmony_ci 562062306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Entering device clock gating.\n"); 562162306a36Sopenharmony_ci 562262306a36Sopenharmony_ci /* Set the Phy Clock bit as suspend is received. */ 562362306a36Sopenharmony_ci pcgctl = dwc2_readl(hsotg, PCGCTL); 562462306a36Sopenharmony_ci pcgctl |= PCGCTL_STOPPCLK; 562562306a36Sopenharmony_ci dwc2_writel(hsotg, pcgctl, PCGCTL); 562662306a36Sopenharmony_ci udelay(5); 562762306a36Sopenharmony_ci 562862306a36Sopenharmony_ci /* Set the Gate hclk as suspend is received. */ 562962306a36Sopenharmony_ci pcgctl = dwc2_readl(hsotg, PCGCTL); 563062306a36Sopenharmony_ci pcgctl |= PCGCTL_GATEHCLK; 563162306a36Sopenharmony_ci dwc2_writel(hsotg, pcgctl, PCGCTL); 563262306a36Sopenharmony_ci udelay(5); 563362306a36Sopenharmony_ci 563462306a36Sopenharmony_ci hsotg->lx_state = DWC2_L2; 563562306a36Sopenharmony_ci hsotg->bus_suspended = true; 563662306a36Sopenharmony_ci} 563762306a36Sopenharmony_ci 563862306a36Sopenharmony_ci/* 563962306a36Sopenharmony_ci * dwc2_gadget_exit_clock_gating() - Exit controller from device clock gating. 564062306a36Sopenharmony_ci * 564162306a36Sopenharmony_ci * @hsotg: Programming view of the DWC_otg controller 564262306a36Sopenharmony_ci * @rem_wakeup: indicates whether remote wake up is enabled. 564362306a36Sopenharmony_ci * 564462306a36Sopenharmony_ci * This function is for exiting from device mode clock gating. 564562306a36Sopenharmony_ci */ 564662306a36Sopenharmony_civoid dwc2_gadget_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup) 564762306a36Sopenharmony_ci{ 564862306a36Sopenharmony_ci u32 pcgctl; 564962306a36Sopenharmony_ci u32 dctl; 565062306a36Sopenharmony_ci 565162306a36Sopenharmony_ci dev_dbg(hsotg->dev, "Exiting device clock gating.\n"); 565262306a36Sopenharmony_ci 565362306a36Sopenharmony_ci /* Clear the Gate hclk. */ 565462306a36Sopenharmony_ci pcgctl = dwc2_readl(hsotg, PCGCTL); 565562306a36Sopenharmony_ci pcgctl &= ~PCGCTL_GATEHCLK; 565662306a36Sopenharmony_ci dwc2_writel(hsotg, pcgctl, PCGCTL); 565762306a36Sopenharmony_ci udelay(5); 565862306a36Sopenharmony_ci 565962306a36Sopenharmony_ci /* Phy Clock bit. */ 566062306a36Sopenharmony_ci pcgctl = dwc2_readl(hsotg, PCGCTL); 566162306a36Sopenharmony_ci pcgctl &= ~PCGCTL_STOPPCLK; 566262306a36Sopenharmony_ci dwc2_writel(hsotg, pcgctl, PCGCTL); 566362306a36Sopenharmony_ci udelay(5); 566462306a36Sopenharmony_ci 566562306a36Sopenharmony_ci if (rem_wakeup) { 566662306a36Sopenharmony_ci /* Set Remote Wakeup Signaling */ 566762306a36Sopenharmony_ci dctl = dwc2_readl(hsotg, DCTL); 566862306a36Sopenharmony_ci dctl |= DCTL_RMTWKUPSIG; 566962306a36Sopenharmony_ci dwc2_writel(hsotg, dctl, DCTL); 567062306a36Sopenharmony_ci } 567162306a36Sopenharmony_ci 567262306a36Sopenharmony_ci /* Change to L0 state */ 567362306a36Sopenharmony_ci call_gadget(hsotg, resume); 567462306a36Sopenharmony_ci hsotg->lx_state = DWC2_L0; 567562306a36Sopenharmony_ci hsotg->bus_suspended = false; 567662306a36Sopenharmony_ci} 5677