| /* ========================================================================== |
| * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, |
| * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless |
| * otherwise expressly agreed to in writing between Synopsys and you. |
| * |
| * The Software IS NOT an item of Licensed Software or Licensed Product under |
| * any End User Software License Agreement or Agreement for Licensed Product |
| * with Synopsys or any supplement thereto. You are permitted to use and |
| * redistribute this Software in source and binary forms, with or without |
| * modification, provided that redistributions of source code must retain this |
| * notice. You may not view, use, disclose, copy or distribute this file or |
| * any information contained herein except pursuant to this license grant from |
| * Synopsys. If you do not agree with this notice, including the disclaimer |
| * below, then you are not authorized to use the Software. |
| * |
| * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, |
| * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| * ========================================================================== */ |
| |
| #if !defined(__DWC_OTG_CFI_H__) |
| #define __DWC_OTG_CFI_H__ |
| |
| #include "dwc_otg_pcd.h" |
| #include "dwc_cfi_common.h" |
| |
| /** |
| * @file |
| * This file contains the CFI related OTG PCD specific common constants, |
| * interfaces(functions and macros) and data structures.The CFI Protocol is an |
| * optional interface for internal testing purposes that a DUT may implement to |
| * support testing of configurable features. |
| * |
| */ |
| |
| struct dwc_otg_pcd; |
| struct dwc_otg_pcd_ep; |
| |
| /** OTG CFI Features (properties) ID constants */ |
| /** This is a request for all Core Features */ |
| #define FT_ID_DMA_MODE 0x0001 |
| #define FT_ID_DMA_BUFFER_SETUP 0x0002 |
| #define FT_ID_DMA_BUFF_ALIGN 0x0003 |
| #define FT_ID_DMA_CONCAT_SETUP 0x0004 |
| #define FT_ID_DMA_CIRCULAR 0x0005 |
| #define FT_ID_THRESHOLD_SETUP 0x0006 |
| #define FT_ID_DFIFO_DEPTH 0x0007 |
| #define FT_ID_TX_FIFO_DEPTH 0x0008 |
| #define FT_ID_RX_FIFO_DEPTH 0x0009 |
| |
| /**********************************************************/ |
| #define CFI_INFO_DEF |
| |
| #ifdef CFI_INFO_DEF |
| #define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt); |
| #else |
| #define CFI_INFO(fmt...) |
| #endif |
| |
| #define min(x,y) ({ \ |
| x < y ? x : y; }) |
| |
| #define max(x,y) ({ \ |
| x > y ? x : y; }) |
| |
| /** |
| * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is |
| * also used for setting up a buffer for Circular DDMA. |
| */ |
| struct _ddma_sg_buffer_setup { |
| #define BS_SG_VAL_DESC_LEN 6 |
| /* The OUT EP address */ |
| uint8_t bOutEndpointAddress; |
| /* The IN EP address */ |
| uint8_t bInEndpointAddress; |
| /* Number of bytes to put between transfer segments (must be DWORD boundaries) */ |
| uint8_t bOffset; |
| /* The number of transfer segments (a DMA descriptors per each segment) */ |
| uint8_t bCount; |
| /* Size (in byte) of each transfer segment */ |
| uint16_t wSize; |
| } __attribute__ ((packed)); |
| typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t; |
| |
| /** Descriptor DMA Concatenation Buffer setup structure */ |
| struct _ddma_concat_buffer_setup_hdr { |
| #define BS_CONCAT_VAL_HDR_LEN 4 |
| /* The endpoint for which the buffer is to be set up */ |
| uint8_t bEndpointAddress; |
| /* The count of descriptors to be used */ |
| uint8_t bDescCount; |
| /* The total size of the transfer */ |
| uint16_t wSize; |
| } __attribute__ ((packed)); |
| typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t; |
| |
| /** Descriptor DMA Concatenation Buffer setup structure */ |
| struct _ddma_concat_buffer_setup { |
| /* The SG header */ |
| ddma_concat_buffer_setup_hdr_t hdr; |
| |
| /* The XFER sizes pointer (allocated dynamically) */ |
| uint16_t *wTxBytes; |
| } __attribute__ ((packed)); |
| typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t; |
| |
| /** Descriptor DMA Alignment Buffer setup structure */ |
| struct _ddma_align_buffer_setup { |
| #define BS_ALIGN_VAL_HDR_LEN 2 |
| uint8_t bEndpointAddress; |
| uint8_t bAlign; |
| } __attribute__ ((packed)); |
| typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t; |
| |
| /** Transmit FIFO Size setup structure */ |
| struct _tx_fifo_size_setup { |
| uint8_t bEndpointAddress; |
| uint16_t wDepth; |
| } __attribute__ ((packed)); |
| typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t; |
| |
| /** Transmit FIFO Size setup structure */ |
| struct _rx_fifo_size_setup { |
| uint16_t wDepth; |
| } __attribute__ ((packed)); |
| typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t; |
| |
| /** |
| * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest |
| * This structure encapsulates the standard usb_ctrlrequest and adds a pointer |
| * to the data returned in the data stage of a 3-stage Control Write requests. |
| */ |
| struct cfi_usb_ctrlrequest { |
| uint8_t bRequestType; |
| uint8_t bRequest; |
| uint16_t wValue; |
| uint16_t wIndex; |
| uint16_t wLength; |
| uint8_t *data; |
| } UPACKED; |
| |
| /*---------------------------------------------------------------------------*/ |
| |
| /** |
| * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures. |
| * This structure is used to store the buffer setup data for any |
| * enabled endpoint in the PCD. |
| */ |
| struct cfi_ep { |
| /* Entry for the list container */ |
| dwc_list_link_t lh; |
| /* Pointer to the active PCD endpoint structure */ |
| struct dwc_otg_pcd_ep *ep; |
| /* The last descriptor in the chain of DMA descriptors of the endpoint */ |
| struct dwc_otg_dma_desc *dma_desc_last; |
| /* The SG feature value */ |
| ddma_sg_buffer_setup_t *bm_sg; |
| /* The Circular feature value */ |
| ddma_sg_buffer_setup_t *bm_circ; |
| /* The Concatenation feature value */ |
| ddma_concat_buffer_setup_t *bm_concat; |
| /* The Alignment feature value */ |
| ddma_align_buffer_setup_t *bm_align; |
| /* XFER length */ |
| uint32_t xfer_len; |
| /* |
| * Count of DMA descriptors currently used. |
| * The total should not exceed the MAX_DMA_DESCS_PER_EP value |
| * defined in the dwc_otg_cil.h |
| */ |
| uint32_t desc_count; |
| }; |
| typedef struct cfi_ep cfi_ep_t; |
| |
| typedef struct cfi_dma_buff { |
| #define CFI_IN_BUF_LEN 1024 |
| #define CFI_OUT_BUF_LEN 1024 |
| dma_addr_t addr; |
| uint8_t *buf; |
| } cfi_dma_buff_t; |
| |
| struct cfiobject; |
| |
| /** |
| * This is the interface for the CFI operations. |
| * |
| * @param ep_enable Called when any endpoint is enabled and activated. |
| * @param release Called when the CFI object is released and it needs to correctly |
| * deallocate the dynamic memory |
| * @param ctrl_write_complete Called when the data stage of the request is complete |
| */ |
| typedef struct cfi_ops { |
| int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd, |
| struct dwc_otg_pcd_ep * ep); |
| void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd, |
| struct dwc_otg_pcd_ep * ep, dma_addr_t * dma, |
| unsigned size, gfp_t flags); |
| void (*release) (struct cfiobject * cfi); |
| int (*ctrl_write_complete) (struct cfiobject * cfi, |
| struct dwc_otg_pcd * pcd); |
| void (*build_descriptors) (struct cfiobject * cfi, |
| struct dwc_otg_pcd * pcd, |
| struct dwc_otg_pcd_ep * ep, |
| dwc_otg_pcd_request_t * req); |
| } cfi_ops_t; |
| |
| struct cfiobject { |
| cfi_ops_t ops; |
| struct dwc_otg_pcd *pcd; |
| struct usb_gadget *gadget; |
| |
| /* Buffers used to send/receive CFI-related request data */ |
| cfi_dma_buff_t buf_in; |
| cfi_dma_buff_t buf_out; |
| |
| /* CFI specific Control request wrapper */ |
| struct cfi_usb_ctrlrequest ctrl_req; |
| |
| /* The list of active EP's in the PCD of type cfi_ep_t */ |
| dwc_list_link_t active_eps; |
| |
| /* This flag shall control the propagation of a specific request |
| * to the gadget's processing routines. |
| * 0 - no gadget handling |
| * 1 - the gadget needs to know about this request (w/o completing a status |
| * phase - just return a 0 to the _setup callback) |
| */ |
| uint8_t need_gadget_att; |
| |
| /* Flag indicating whether the status IN phase needs to be |
| * completed by the PCD |
| */ |
| uint8_t need_status_in_complete; |
| }; |
| typedef struct cfiobject cfiobject_t; |
| |
| #define DUMP_MSG |
| |
| #if defined(DUMP_MSG) |
| static inline void dump_msg(const u8 * buf, unsigned int length) |
| { |
| unsigned int start, num, i; |
| char line[52], *p; |
| |
| if (length >= 512) |
| return; |
| |
| start = 0; |
| while (length > 0) { |
| num = min(length, 16u); |
| p = line; |
| for (i = 0; i < num; ++i) { |
| if (i == 8) |
| *p++ = ' '; |
| DWC_SPRINTF(p, " %02x", buf[i]); |
| p += 3; |
| } |
| *p = 0; |
| DWC_DEBUG("%6x: %s\n", start, line); |
| buf += num; |
| start += num; |
| length -= num; |
| } |
| } |
| #else |
| static inline void dump_msg(const u8 * buf, unsigned int length) |
| { |
| } |
| #endif |
| |
| /** |
| * This function returns a pointer to cfi_ep_t object with the addr address. |
| */ |
| static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi, |
| uint8_t addr) |
| { |
| struct cfi_ep *pcfiep; |
| dwc_list_link_t *tmp; |
| |
| DWC_LIST_FOREACH(tmp, &cfi->active_eps) { |
| pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); |
| |
| if (pcfiep->ep->desc->bEndpointAddress == addr) { |
| return pcfiep; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| /** |
| * This function returns a pointer to cfi_ep_t object that matches |
| * the dwc_otg_pcd_ep object. |
| */ |
| static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi, |
| struct dwc_otg_pcd_ep *ep) |
| { |
| struct cfi_ep *pcfiep = NULL; |
| dwc_list_link_t *tmp; |
| |
| DWC_LIST_FOREACH(tmp, &cfi->active_eps) { |
| pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); |
| if (pcfiep->ep == ep) { |
| return pcfiep; |
| } |
| } |
| return NULL; |
| } |
| |
| int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl); |
| |
| #endif /* (__DWC_OTG_CFI_H__) */ |