forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
9.7 KiB
320 lines
9.7 KiB
/* ========================================================================== |
|
* 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__) */
|
|
|