blob: cbccdabe001b05cced779a346fad5bdcea129976 [file] [log] [blame]
/* ==========================================================================
* 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__) */