// SPDX-License-Identifier: GPL-2.0 /* * Cadence USBSS DRD Driver - gadget side. * * Copyright (C) 2018-2019 Cadence Design Systems. * Copyright (C) 2017-2018 NXP * * Authors: Pawel Jez <[email protected]>, * Pawel Laszczak <[email protected]> * Peter Chen <[email protected]> */ /* * Work around 1: * At some situations, the controller may get stale data address in TRB * at below sequences: * 1. Controller read TRB includes data address * 2. Software updates TRBs includes data address and Cycle bit * 3. Controller read TRB which includes Cycle bit * 4. DMA run with stale data address * * To fix this problem, driver needs to make the first TRB in TD as invalid. * After preparing all TRBs driver needs to check the position of DMA and * if the DMA point to the first just added TRB and doorbell is 1, * then driver must defer making this TRB as valid. This TRB will be make * as valid during adding next TRB only if DMA is stopped or at TRBERR * interrupt. * * Issue has been fixed in DEV_VER_V3 version of controller. * * Work around 2: * Controller for OUT endpoints has shared on-chip buffers for all incoming * packets, including ep0out. It's FIFO buffer, so packets must be handle by DMA * in correct order. If the first packet in the buffer will not be handled, * then the following packets directed for other endpoints and functions * will be blocked. * Additionally the packets directed to one endpoint can block entire on-chip * buffers. In this case transfer to other endpoints also will blocked. * * To resolve this issue after raising the descriptor missing interrupt * driver prepares internal usb_request object and use it to arm DMA transfer. * * The problematic situation was observed in case when endpoint has been enabled * but no usb_request were queued. Driver try detects such endpoints and will * use this workaround only for these endpoint. * * Driver use limited number of buffer. This number can be set by macro * CDNS3_WA2_NUM_BUFFERS. * * Such blocking situation was observed on ACM gadget. For this function * host send OUT data packet but ACM function is not prepared for this packet. * It's cause that buffer placed in on chip memory block transfer to other * endpoints. * * Issue has been fixed in DEV_VER_V2 version of controller. * */ #include <linux/dma-mapping.h> #include <linux/usb/gadget.h> #include <linux/module.h> #include <linux/dmapool.h> #include <linux/iopoll.h> #include <linux/property.h> #include "core.h" #include "gadget-export.h" #include "cdns3-gadget.h" #include "cdns3-trace.h" #include "drd.h" static int __cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags); static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, struct usb_request *request); static int cdns3_ep_run_stream_transfer(struct cdns3_endpoint *priv_ep, struct usb_request *request); /** * cdns3_clear_register_bit - clear bit in given register. * @ptr: address of device controller register to be read and changed * @mask: bits requested to clar */ static void cdns3_clear_register_bit(void __iomem *ptr, u32 mask) { … } /** * cdns3_set_register_bit - set bit in given register. * @ptr: address of device controller register to be read and changed * @mask: bits requested to set */ void cdns3_set_register_bit(void __iomem *ptr, u32 mask) { … } /** * cdns3_ep_addr_to_index - Macro converts endpoint address to * index of endpoint object in cdns3_device.eps[] container * @ep_addr: endpoint address for which endpoint object is required * */ u8 cdns3_ep_addr_to_index(u8 ep_addr) { … } static int cdns3_get_dma_pos(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep) { … } /** * cdns3_next_request - returns next request from list * @list: list containing requests * * Returns request or NULL if no requests in list */ struct usb_request *cdns3_next_request(struct list_head *list) { … } /** * cdns3_next_align_buf - returns next buffer from list * @list: list containing buffers * * Returns buffer or NULL if no buffers in list */ static struct cdns3_aligned_buf *cdns3_next_align_buf(struct list_head *list) { … } /** * cdns3_next_priv_request - returns next request from list * @list: list containing requests * * Returns request or NULL if no requests in list */ static struct cdns3_request *cdns3_next_priv_request(struct list_head *list) { … } /** * cdns3_select_ep - selects endpoint * @priv_dev: extended gadget object * @ep: endpoint address */ void cdns3_select_ep(struct cdns3_device *priv_dev, u32 ep) { … } /** * cdns3_get_tdl - gets current tdl for selected endpoint. * @priv_dev: extended gadget object * * Before calling this function the appropriate endpoint must * be selected by means of cdns3_select_ep function. */ static int cdns3_get_tdl(struct cdns3_device *priv_dev) { … } dma_addr_t cdns3_trb_virt_to_dma(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb) { … } static void cdns3_free_trb_pool(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_allocate_trb_pool - Allocates TRB's pool for selected endpoint * @priv_ep: endpoint object * * Function will return 0 on success or -ENOMEM on allocation error */ int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_ep_stall_flush - Stalls and flushes selected endpoint * @priv_ep: endpoint object * * Endpoint must be selected before call to this function */ static void cdns3_ep_stall_flush(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_hw_reset_eps_config - reset endpoints configuration kept by controller. * @priv_dev: extended gadget object */ void cdns3_hw_reset_eps_config(struct cdns3_device *priv_dev) { … } /** * cdns3_ep_inc_trb - increment a trb index. * @index: Pointer to the TRB index to increment. * @cs: Cycle state * @trb_in_seg: number of TRBs in segment * * The index should never point to the link TRB. After incrementing, * if it is point to the link TRB, wrap around to the beginning and revert * cycle state bit The * link TRB is always at the last TRB entry. */ static void cdns3_ep_inc_trb(int *index, u8 *cs, int trb_in_seg) { … } /** * cdns3_ep_inc_enq - increment endpoint's enqueue pointer * @priv_ep: The endpoint whose enqueue pointer we're incrementing */ static void cdns3_ep_inc_enq(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_ep_inc_deq - increment endpoint's dequeue pointer * @priv_ep: The endpoint whose dequeue pointer we're incrementing */ static void cdns3_ep_inc_deq(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_allow_enable_l1 - enable/disable permits to transition to L1. * @priv_dev: Extended gadget object * @enable: Enable/disable permit to transition to L1. * * If bit USB_CONF_L1EN is set and device receive Extended Token packet, * then controller answer with ACK handshake. * If bit USB_CONF_L1DS is set and device receive Extended Token packet, * then controller answer with NYET handshake. */ void cdns3_allow_enable_l1(struct cdns3_device *priv_dev, int enable) { … } enum usb_device_speed cdns3_get_speed(struct cdns3_device *priv_dev) { … } /** * cdns3_start_all_request - add to ring all request not started * @priv_dev: Extended gadget object * @priv_ep: The endpoint for whom request will be started. * * Returns return ENOMEM if transfer ring i not enough TRBs to start * all requests. */ static int cdns3_start_all_request(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep) { … } /* * WA2: Set flag for all not ISOC OUT endpoints. If this flag is set * driver try to detect whether endpoint need additional internal * buffer for unblocking on-chip FIFO buffer. This flag will be cleared * if before first DESCMISS interrupt the DMA will be armed. */ #define cdns3_wa2_enable_detection(priv_dev, priv_ep, reg) … static void __cdns3_descmiss_copy_data(struct usb_request *request, struct usb_request *descmiss_req) { … } /** * cdns3_wa2_descmiss_copy_data - copy data from internal requests to * request queued by class driver. * @priv_ep: extended endpoint object * @request: request object */ static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep, struct usb_request *request) { … } static struct usb_request *cdns3_wa2_gadget_giveback(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep, struct cdns3_request *priv_req) { … } static int cdns3_wa2_gadget_ep_queue(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep, struct cdns3_request *priv_req) { … } static void cdns3_wa2_remove_old_request(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_wa2_descmissing_packet - handles descriptor missing event. * @priv_ep: extended gadget object * * This function is used only for WA2. For more information see Work around 2 * description. */ static void cdns3_wa2_descmissing_packet(struct cdns3_endpoint *priv_ep) { … } static void cdns3_wa2_reset_tdl(struct cdns3_device *priv_dev) { … } static void cdns3_wa2_check_outq_status(struct cdns3_device *priv_dev) { … } /** * cdns3_gadget_giveback - call struct usb_request's ->complete callback * @priv_ep: The endpoint to whom the request belongs to * @priv_req: The request we're giving back * @status: completion code for the request * * Must be called with controller's lock held and interrupts disabled. This * function will unmap @req and call its ->complete() callback to notify upper * layers that it has completed. */ void cdns3_gadget_giveback(struct cdns3_endpoint *priv_ep, struct cdns3_request *priv_req, int status) { … } static void cdns3_wa1_restore_cycle_bit(struct cdns3_endpoint *priv_ep) { … } static void cdns3_free_aligned_request_buf(struct work_struct *work) { … } static int cdns3_prepare_aligned_request_buf(struct cdns3_request *priv_req) { … } static int cdns3_wa1_update_guard(struct cdns3_endpoint *priv_ep, struct cdns3_trb *trb) { … } static void cdns3_wa1_tray_restore_cycle_bit(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep) { … } static int cdns3_ep_run_stream_transfer(struct cdns3_endpoint *priv_ep, struct usb_request *request) { … } static void cdns3_rearm_drdy_if_needed(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_ep_run_transfer - start transfer on no-default endpoint hardware * @priv_ep: endpoint object * @request: request object * * Returns zero on success or negative value on failure */ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep, struct usb_request *request) { … } void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) { … } /** * cdns3_trb_handled - check whether trb has been handled by DMA * * @priv_ep: extended endpoint object. * @priv_req: request object for checking * * Endpoint must be selected before invoking this function. * * Returns false if request has not been handled by DMA, else returns true. * * SR - start ring * ER - end ring * DQ = priv_ep->dequeue - dequeue position * EQ = priv_ep->enqueue - enqueue position * ST = priv_req->start_trb - index of first TRB in transfer ring * ET = priv_req->end_trb - index of last TRB in transfer ring * CI = current_index - index of processed TRB by DMA. * * As first step, we check if the TRB between the ST and ET. * Then, we check if cycle bit for index priv_ep->dequeue * is correct. * * some rules: * 1. priv_ep->dequeue never equals to current_index. * 2 priv_ep->enqueue never exceed priv_ep->dequeue * 3. exception: priv_ep->enqueue == priv_ep->dequeue * and priv_ep->free_trbs is zero. * This case indicate that TR is full. * * At below two cases, the request have been handled. * Case 1 - priv_ep->dequeue < current_index * SR ... EQ ... DQ ... CI ... ER * SR ... DQ ... CI ... EQ ... ER * * Case 2 - priv_ep->dequeue > current_index * This situation takes place when CI go through the LINK TRB at the end of * transfer ring. * SR ... CI ... EQ ... DQ ... ER */ static bool cdns3_trb_handled(struct cdns3_endpoint *priv_ep, struct cdns3_request *priv_req) { … } static void cdns3_transfer_completed(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep) { … } void cdns3_rearm_transfer(struct cdns3_endpoint *priv_ep, u8 rearm) { … } static void cdns3_reprogram_tdl(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_check_ep_interrupt_proceed - Processes interrupt related to endpoint * @priv_ep: endpoint object * * Returns 0 */ static int cdns3_check_ep_interrupt_proceed(struct cdns3_endpoint *priv_ep) { … } static void cdns3_disconnect_gadget(struct cdns3_device *priv_dev) { … } /** * cdns3_check_usb_interrupt_proceed - Processes interrupt related to device * @priv_dev: extended gadget object * @usb_ists: bitmap representation of device's reported interrupts * (usb_ists register value) */ static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev, u32 usb_ists) __must_hold(&priv_dev->lock) { … } /** * cdns3_device_irq_handler - interrupt handler for device part of controller * * @irq: irq number for cdns3 core device * @data: structure of cdns3 * * Returns IRQ_HANDLED or IRQ_NONE */ static irqreturn_t cdns3_device_irq_handler(int irq, void *data) { … } /** * cdns3_device_thread_irq_handler - interrupt handler for device part * of controller * * @irq: irq number for cdns3 core device * @data: structure of cdns3 * * Returns IRQ_HANDLED or IRQ_NONE */ static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data) { … } /** * cdns3_ep_onchip_buffer_reserve - Try to reserve onchip buf for EP * * The real reservation will occur during write to EP_CFG register, * this function is used to check if the 'size' reservation is allowed. * * @priv_dev: extended gadget object * @size: the size (KB) for EP would like to allocate * @is_in: endpoint direction * * Return 0 if the required size can met or negative value on failure */ static int cdns3_ep_onchip_buffer_reserve(struct cdns3_device *priv_dev, int size, int is_in) { … } static void cdns3_configure_dmult(struct cdns3_device *priv_dev, struct cdns3_endpoint *priv_ep) { … } /** * cdns3_ep_config - Configure hardware endpoint * @priv_ep: extended endpoint object * @enable: set EP_CFG_ENABLE bit in ep_cfg register. */ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable) { … } /* Find correct direction for HW endpoint according to description */ static int cdns3_ep_dir_is_correct(struct usb_endpoint_descriptor *desc, struct cdns3_endpoint *priv_ep) { … } static struct cdns3_endpoint *cdns3_find_available_ep(struct cdns3_device *priv_dev, struct usb_endpoint_descriptor *desc) { … } /* * Cadence IP has one limitation that all endpoints must be configured * (Type & MaxPacketSize) before setting configuration through hardware * register, it means we can't change endpoints configuration after * set_configuration. * * This function set EP_CLAIMED flag which is added when the gadget driver * uses usb_ep_autoconfig to configure specific endpoint; * When the udc driver receives set_configurion request, * it goes through all claimed endpoints, and configure all endpoints * accordingly. * * At usb_ep_ops.enable/disable, we only enable and disable endpoint through * ep_cfg register which can be changed after set_configuration, and do * some software operation accordingly. */ static struct usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget, struct usb_endpoint_descriptor *desc, struct usb_ss_ep_comp_descriptor *comp_desc) { … } /** * cdns3_gadget_ep_alloc_request - Allocates request * @ep: endpoint object associated with request * @gfp_flags: gfp flags * * Returns allocated request address, NULL on allocation error */ struct usb_request *cdns3_gadget_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { … } /** * cdns3_gadget_ep_free_request - Free memory occupied by request * @ep: endpoint object associated with request * @request: request to free memory */ void cdns3_gadget_ep_free_request(struct usb_ep *ep, struct usb_request *request) { … } /** * cdns3_gadget_ep_enable - Enable endpoint * @ep: endpoint object * @desc: endpoint descriptor * * Returns 0 on success, error code elsewhere */ static int cdns3_gadget_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { … } /** * cdns3_gadget_ep_disable - Disable endpoint * @ep: endpoint object * * Returns 0 on success, error code elsewhere */ static int cdns3_gadget_ep_disable(struct usb_ep *ep) { … } /** * __cdns3_gadget_ep_queue - Transfer data on endpoint * @ep: endpoint object * @request: request object * @gfp_flags: gfp flags * * Returns 0 on success, error code elsewhere */ static int __cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags) { … } static int cdns3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags) { … } /** * cdns3_gadget_ep_dequeue - Remove request from transfer queue * @ep: endpoint object associated with request * @request: request object * * Returns 0 on success, error code elsewhere */ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *request) { … } /** * __cdns3_gadget_ep_set_halt - Sets stall on selected endpoint * Should be called after acquiring spin_lock and selecting ep * @priv_ep: endpoint object to set stall on. */ void __cdns3_gadget_ep_set_halt(struct cdns3_endpoint *priv_ep) { … } /** * __cdns3_gadget_ep_clear_halt - Clears stall on selected endpoint * Should be called after acquiring spin_lock and selecting ep * @priv_ep: endpoint object to clear stall on */ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep) { … } /** * cdns3_gadget_ep_set_halt - Sets/clears stall on selected endpoint * @ep: endpoint object to set/clear stall on * @value: 1 for set stall, 0 for clear stall * * Returns 0 on success, error code elsewhere */ int cdns3_gadget_ep_set_halt(struct usb_ep *ep, int value) { … } extern const struct usb_ep_ops cdns3_gadget_ep0_ops; static const struct usb_ep_ops cdns3_gadget_ep_ops = …; /** * cdns3_gadget_get_frame - Returns number of actual ITP frame * @gadget: gadget object * * Returns number of actual ITP frame */ static int cdns3_gadget_get_frame(struct usb_gadget *gadget) { … } int __cdns3_gadget_wakeup(struct cdns3_device *priv_dev) { … } static int cdns3_gadget_wakeup(struct usb_gadget *gadget) { … } static int cdns3_gadget_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) { … } static int cdns3_gadget_pullup(struct usb_gadget *gadget, int is_on) { … } static void cdns3_gadget_config(struct cdns3_device *priv_dev) { … } /** * cdns3_gadget_udc_start - Gadget start * @gadget: gadget object * @driver: driver which operates on this gadget * * Returns 0 on success, error code elsewhere */ static int cdns3_gadget_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { … } /** * cdns3_gadget_udc_stop - Stops gadget * @gadget: gadget object * * Returns 0 */ static int cdns3_gadget_udc_stop(struct usb_gadget *gadget) { … } /** * cdns3_gadget_check_config - ensure cdns3 can support the USB configuration * @gadget: pointer to the USB gadget * * Used to record the maximum number of endpoints being used in a USB composite * device. (across all configurations) This is to be used in the calculation * of the TXFIFO sizes when resizing internal memory for individual endpoints. * It will help ensured that the resizing logic reserves enough space for at * least one max packet. */ static int cdns3_gadget_check_config(struct usb_gadget *gadget) { … } static const struct usb_gadget_ops cdns3_gadget_ops = …; static void cdns3_free_all_eps(struct cdns3_device *priv_dev) { … } /** * cdns3_init_eps - Initializes software endpoints of gadget * @priv_dev: extended gadget object * * Returns 0 on success, error code elsewhere */ static int cdns3_init_eps(struct cdns3_device *priv_dev) { … } static void cdns3_gadget_release(struct device *dev) { … } static void cdns3_gadget_exit(struct cdns *cdns) { … } static int cdns3_gadget_start(struct cdns *cdns) { … } static int __cdns3_gadget_init(struct cdns *cdns) { … } static int cdns3_gadget_suspend(struct cdns *cdns, bool do_wakeup) __must_hold(&cdns->lock) { … } static int cdns3_gadget_resume(struct cdns *cdns, bool hibernated) { … } /** * cdns3_gadget_init - initialize device structure * * @cdns: cdns instance * * This function initializes the gadget. */ int cdns3_gadget_init(struct cdns *cdns) { … }