aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/dwc_otg/dwc_otg_cfi.h
blob: 55fd337a283c39512eb1409dfc1183c56dfd7680 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/* ==========================================================================
 * 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__) */