summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/udc/bdc/bdc.h
blob: dc18a20bf040202d2afc65ce96082f94b9a8fc19 (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
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
/*
 * bdc.h - header for the BRCM BDC USB3.0 device controller
 *
 * Copyright (C) 2014 Broadcom Corporation
 *
 * Author: Ashwini Pahuja
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 */

#ifndef	__LINUX_BDC_H__
#define	__LINUX_BDC_H__

#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <asm/unaligned.h>

#define BRCM_BDC_NAME "bdc_usb3"
#define BRCM_BDC_DESC "BDC device controller driver"

#define DMA_ADDR_INVALID        (~(dma_addr_t)0)

/* BDC command operation timeout in usec*/
#define BDC_CMD_TIMEOUT	1000
/* BDC controller operation timeout in usec*/
#define BDC_COP_TIMEOUT	500

/*
 * Maximum size of ep0 response buffer for ch9 requests,
 * the set_sel request uses 6 so far, the max.
*/
#define EP0_RESPONSE_BUFF  6
/* Start with SS as default */
#define EP0_MAX_PKT_SIZE 512

/* 64 entries in a SRR */
#define NUM_SR_ENTRIES	64

/* Num of bds per table */
#define NUM_BDS_PER_TABLE	32

/* Num of tables in bd list for control,bulk and Int ep */
#define NUM_TABLES	2

/* Num of tables in bd list for Isoch ep */
#define NUM_TABLES_ISOCH	6

/* U1 Timeout default: 248usec */
#define U1_TIMEOUT	0xf8

/* Interrupt coalescence in usec */
#define	INT_CLS	500

/* Register offsets */
/* Configuration and Capability registers */
#define BDC_BDCCFG0	0x00
#define BDC_BDCCFG1	0x04
#define BDC_BDCCAP0	0x08
#define BDC_BDCCAP1	0x0c
#define BDC_CMDPAR0	0x10
#define BDC_CMDPAR1	0x14
#define BDC_CMDPAR2	0x18
#define BDC_CMDSC	0x1c
#define BDC_USPC	0x20
#define BDC_USPPMS	0x28
#define BDC_USPPM2	0x2c
#define BDC_SPBBAL	0x38
#define BDC_SPBBAH	0x3c
#define BDC_BDCSC	0x40
#define BDC_XSFNTF	0x4c

#define BDC_DVCSA	0x50
#define BDC_DVCSB	0x54
#define BDC_EPSTS0(n)	(0x60 + (n * 0x10))
#define BDC_EPSTS1(n)	(0x64 + (n * 0x10))
#define BDC_EPSTS2(n)	(0x68 + (n * 0x10))
#define BDC_EPSTS3(n)	(0x6c + (n * 0x10))
#define BDC_EPSTS4(n)	(0x70 + (n * 0x10))
#define BDC_EPSTS5(n)	(0x74 + (n * 0x10))
#define BDC_EPSTS6(n)	(0x78 + (n * 0x10))
#define BDC_EPSTS7(n)	(0x7c + (n * 0x10))
#define BDC_SRRBAL(n)	(0x200 + (n * 0x10))
#define BDC_SRRBAH(n)	(0x204 + (n * 0x10))
#define BDC_SRRINT(n)	(0x208 + (n * 0x10))
#define BDC_INTCTLS(n)	(0x20c + (n * 0x10))

/* Extended capability regs */
#define BDC_FSCNOC	0xcd4
#define BDC_FSCNIC	0xce4
#define NUM_NCS(p)	(p >> 28)

/* Register bit fields and Masks */
/* BDC Configuration 0 */
#define BDC_PGS(p)	(((p) & (0x7 << 8)) >> 8)
#define BDC_SPB(p)	(p & 0x7)

/* BDC Capability1 */
#define BDC_P64		(1 << 0)

/* BDC Command register */
#define BDC_CMD_FH	0xe
#define BDC_CMD_DNC	0x6
#define BDC_CMD_EPO	0x4
#define BDC_CMD_BLA	0x3
#define BDC_CMD_EPC	0x2
#define BDC_CMD_DVC	0x1
#define BDC_CMD_CWS		(0x1 << 5)
#define BDC_CMD_CST(p)		(((p) & (0xf << 6))>>6)
#define BDC_CMD_EPN(p)		((p & 0x1f) << 10)
#define BDC_SUB_CMD_ADD		(0x1 << 17)
#define BDC_SUB_CMD_FWK		(0x4 << 17)
/* Reset sequence number */
#define BDC_CMD_EPO_RST_SN	(0x1 << 16)
#define BDC_CMD_EP0_XSD		(0x1 << 16)
#define BDC_SUB_CMD_ADD_EP	(0x1 << 17)
#define BDC_SUB_CMD_DRP_EP	(0x2 << 17)
#define BDC_SUB_CMD_EP_STP	(0x2 << 17)
#define BDC_SUB_CMD_EP_STL	(0x4 << 17)
#define BDC_SUB_CMD_EP_RST	(0x1 << 17)
#define BDC_CMD_SRD		(1 << 27)

/* CMD completion status */
#define BDC_CMDS_SUCC	0x1
#define BDC_CMDS_PARA	0x3
#define BDC_CMDS_STAT	0x4
#define BDC_CMDS_FAIL	0x5
#define BDC_CMDS_INTL	0x6
#define BDC_CMDS_BUSY	0xf

/* CMDSC Param 2 shifts */
#define EPT_SHIFT	22
#define MP_SHIFT	10
#define MB_SHIFT	6
#define EPM_SHIFT	4

/* BDC USPSC */
#define BDC_VBC		(1 << 31)
#define BDC_PRC		(1 << 30)
#define BDC_PCE		(1 << 29)
#define BDC_CFC		(1 << 28)
#define BDC_PCC		(1 << 27)
#define BDC_PSC		(1 << 26)
#define BDC_VBS		(1 << 25)
#define BDC_PRS		(1 << 24)
#define BDC_PCS		(1 << 23)
#define BDC_PSP(p)	(((p) & (0x7 << 20))>>20)
#define BDC_SCN		(1 << 8)
#define BDC_SDC		(1 << 7)
#define BDC_SWS		(1 << 4)

#define BDC_USPSC_RW	(BDC_SCN|BDC_SDC|BDC_SWS|0xf)
#define BDC_PSP(p)	(((p) & (0x7 << 20))>>20)

#define BDC_SPEED_FS	0x1
#define BDC_SPEED_LS	0x2
#define BDC_SPEED_HS	0x3
#define BDC_SPEED_SS	0x4

#define BDC_PST(p)	(p & 0xf)
#define BDC_PST_MASK	0xf

/* USPPMS */
#define BDC_U2E		(0x1 << 31)
#define BDC_U1E		(0x1 << 30)
#define BDC_U2A		(0x1 << 29)
#define BDC_PORT_W1S	(0x1 << 17)
#define BDC_U1T(p)	((p) & 0xff)
#define BDC_U2T(p)	(((p) & 0xff) << 8)
#define BDC_U1T_MASK	0xff

/* USBPM2 */
/* Hardware LPM Enable */
#define BDC_HLE		(1 << 16)

/* BDC Status and Control */
#define BDC_COP_RST	(1 << 29)
#define BDC_COP_RUN	(2 << 29)
#define BDC_COP_STP	(4 << 29)

#define BDC_COP_MASK (BDC_COP_RST|BDC_COP_RUN|BDC_COP_STP)

#define BDC_COS		(1 << 28)
#define BDC_CSTS(p)	(((p) & (0x7 << 20)) >> 20)
#define BDC_MASK_MCW	(1 << 7)
#define BDC_GIE		(1 << 1)
#define BDC_GIP		(1 << 0)

#define BDC_HLT	1
#define BDC_NOR	2
#define BDC_OIP	7

/* Buffer descriptor and Status report bit fields and masks */
#define BD_TYPE_BITMASK	(0xf)
#define BD_CHAIN	0xf

#define BD_TFS_SHIFT	4
#define BD_SOT		(1 << 26)
#define BD_EOT		(1 << 27)
#define BD_ISP		(1 << 29)
#define BD_IOC		(1 << 30)
#define BD_SBF		(1 << 31)

#define BD_INTR_TARGET(p)	(((p) & 0x1f) << 27)

#define BDC_SRR_RWS		(1 << 4)
#define BDC_SRR_RST		(1 << 3)
#define BDC_SRR_ISR		(1 << 2)
#define BDC_SRR_IE		(1 << 1)
#define BDC_SRR_IP		(1 << 0)
#define BDC_SRR_EPI(p)	(((p) & (0xff << 24)) >> 24)
#define BDC_SRR_DPI(p) (((p) & (0xff << 16)) >> 16)
#define BDC_SRR_DPI_MASK	0x00ff0000

#define MARK_CHAIN_BD	(BD_CHAIN|BD_EOT|BD_SOT)

/* Control transfer BD specific fields */
#define BD_DIR_IN		(1 << 25)

#define BDC_PTC_MASK	0xf0000000

/* status report defines */
#define SR_XSF		0
#define SR_USPC		4
#define SR_BD_LEN(p)    (p & 0xffffff)

#define XSF_SUCC	0x1
#define XSF_SHORT	0x3
#define XSF_BABB	0x4
#define XSF_SETUP_RECV	0x6
#define XSF_DATA_START	0x7
#define XSF_STATUS_START 0x8

#define XSF_STS(p) (((p) >> 28) & 0xf)

/* Transfer BD fields */
#define BD_LEN(p) ((p) & 0x1ffff)
#define BD_LTF		(1 << 25)
#define BD_TYPE_DS	0x1
#define BD_TYPE_SS	0x2

#define BDC_EP_ENABLED     (1 << 0)
#define BDC_EP_STALL       (1 << 1)
#define BDC_EP_STOP        (1 << 2)

/* One BD can transfer max 65536 bytes */
#define BD_MAX_BUFF_SIZE	(1 << 16)
/* Maximum bytes in one XFR, Refer to BDC spec */
#define MAX_XFR_LEN		16777215

/* defines for Force Header command */
#define DEV_NOTF_TYPE 6
#define FWK_SUBTYPE  1
#define TRA_PACKET   4

#define to_bdc_ep(e)		container_of(e, struct bdc_ep, usb_ep)
#define to_bdc_req(r)		container_of(r, struct bdc_req, usb_req)
#define gadget_to_bdc(g)	container_of(g, struct bdc, gadget)

/* FUNCTION WAKE DEV NOTIFICATION interval, USB3 spec table 8.13 */
#define BDC_TNOTIFY 2500 /*in ms*/
/* Devstatus bitfields */
#define REMOTE_WAKEUP_ISSUED	(1 << 16)
#define DEVICE_SUSPENDED	(1 << 17)
#define FUNC_WAKE_ISSUED	(1 << 18)
#define REMOTE_WAKE_ENABLE	(1 << USB_DEVICE_REMOTE_WAKEUP)

/* On disconnect, preserve these bits and clear rest */
#define DEVSTATUS_CLEAR		(1 << USB_DEVICE_SELF_POWERED)
/* Hardware and software Data structures */

/* Endpoint bd: buffer descriptor */
struct bdc_bd {
	__le32 offset[4];
};

/* Status report in Status report ring(srr) */
struct bdc_sr {
	__le32 offset[4];
};

/* bd_table: contigous bd's in a table */
struct bd_table {
	struct bdc_bd *start_bd;
	/* dma address of start bd of table*/
	dma_addr_t dma;
};

/*
 * Each endpoint has a bdl(buffer descriptor list), bdl consists of 1 or more bd
 * table's chained to each other through a chain bd, every table has equal
 * number of bds. the software uses bdi(bd index) to refer to particular bd in
 * the list.
 */
struct bd_list {
	/* Array of bd table pointers*/
	struct bd_table **bd_table_array;
	/* How many tables chained to each other */
	int num_tabs;
	/* Max_bdi = num_tabs * num_bds_table - 1 */
	int max_bdi;
	/* current enq bdi from sw point of view */
	int eqp_bdi;
	/* current deq bdi from sw point of view */
	int hwd_bdi;
	/* numbers of bds per table */
	int num_bds_table;
};

struct bdc_req;

/* Representation of a transfer, one transfer can have multiple bd's */
struct bd_transfer {
	struct bdc_req *req;
	/* start bd index */
	int start_bdi;
	/* this will be the next hw dqp when this transfer completes */
	int next_hwd_bdi;
	/* number of bds in this transfer */
	int num_bds;
};

/*
 * Representation of a gadget request, every gadget request is contained
 * by 1 bd_transfer.
 */
struct bdc_req {
	struct usb_request	usb_req;
	struct list_head	queue;
	struct bdc_ep		*ep;
	/* only one Transfer per request */
	struct bd_transfer bd_xfr;
	int	epnum;
};

/* scratchpad buffer needed by bdc hardware */
struct bdc_scratchpad {
	dma_addr_t sp_dma;
	void *buff;
	u32 size;
};

/* endpoint representation */
struct bdc_ep {
	struct usb_ep	usb_ep;
	struct list_head queue;
	struct bdc *bdc;
	u8  ep_type;
	u8  dir;
	u8  ep_num;
	const struct usb_ss_ep_comp_descriptor	*comp_desc;
	const struct usb_endpoint_descriptor	*desc;
	unsigned int flags;
	char name[20];
	/* endpoint bd list*/
	struct bd_list bd_list;
	/*
	 * HW generates extra event for multi bd tranfers, this flag helps in
	 * ignoring the extra event
	 */
	bool ignore_next_sr;
};

/* bdc cmmand parameter structure */
struct bdc_cmd_params {
	u32	param2;
	u32	param1;
	u32	param0;
};

/* status report ring(srr), currently one srr is supported for entire system */
struct srr {
	struct bdc_sr *sr_bds;
	u16	eqp_index;
	u16	dqp_index;
	dma_addr_t	dma_addr;
};

/* EP0 states */
enum bdc_ep0_state {
	WAIT_FOR_SETUP = 0,
	WAIT_FOR_DATA_START,
	WAIT_FOR_DATA_XMIT,
	WAIT_FOR_STATUS_START,
	WAIT_FOR_STATUS_XMIT,
	STATUS_PENDING
};

/* Link states */
enum bdc_link_state {
	BDC_LINK_STATE_U0	= 0x00,
	BDC_LINK_STATE_U3	= 0x03,
	BDC_LINK_STATE_RX_DET	= 0x05,
	BDC_LINK_STATE_RESUME	= 0x0f
};

/* representation of bdc */
struct bdc {
	struct usb_gadget	gadget;
	struct usb_gadget_driver	*gadget_driver;
	struct device	*dev;
	/* device lock */
	spinlock_t	lock;

	/* num of endpoints for a particular instantiation of IP */
	unsigned int num_eps;
	/*
	 * Array of ep's, it uses the same index covention as bdc hw i.e.
	 * 1 for ep0, 2 for 1out,3 for 1in ....
	 */
	struct bdc_ep		**bdc_ep_array;
	void __iomem		*regs;
	struct bdc_scratchpad	scratchpad;
	u32	sp_buff_size;
	/* current driver supports 1 status ring */
	struct srr	srr;
	/* Last received setup packet */
	struct	usb_ctrlrequest setup_pkt;
	struct	bdc_req ep0_req;
	struct	bdc_req status_req;
	enum	bdc_ep0_state ep0_state;
	bool	delayed_status;
	bool	zlp_needed;
	bool	reinit;
	bool	pullup;
	/* Bits 0-15 are standard and 16-31 for proprietary information */
	u32	devstatus;
	int	irq;
	void	*mem;
	u32	dev_addr;
	/* DMA pools */
	struct dma_pool	*bd_table_pool;
	u8		test_mode;
	/* array of callbacks for various status report handlers */
	void (*sr_handler[2])(struct bdc *, struct bdc_sr *);
	/* ep0 callback handlers */
	void (*sr_xsf_ep0[3])(struct bdc *, struct bdc_sr *);
	/* ep0 response buffer for ch9 requests like GET_STATUS and SET_SEL */
	unsigned char		ep0_response_buff[EP0_RESPONSE_BUFF];
	/*
	 * Timer to check if host resumed transfer after bdc sent Func wake
	 * notification  packet after a remote wakeup. if not, then resend the
	 * Func Wake packet every 2.5 secs. Refer to USB3 spec section 8.5.6.4
	 */
	struct delayed_work	func_wake_notify;
};

static inline u32 bdc_readl(void __iomem *base, u32 offset)
{
	return readl(base + offset);
}

static inline void bdc_writel(void __iomem *base, u32 offset, u32 value)
{
	writel(value, base + offset);
}

/* Buffer descriptor list operations */
void bdc_notify_xfr(struct bdc *, u32);
void bdc_softconn(struct bdc *);
void bdc_softdisconn(struct bdc *);
int bdc_run(struct bdc *);
int bdc_stop(struct bdc *);
int bdc_reset(struct bdc *);
int bdc_udc_init(struct bdc *);
void bdc_udc_exit(struct bdc *);
int bdc_reinit(struct bdc *);

/* Status report handlers */
/* Upstream port status change sr */
void bdc_sr_uspc(struct bdc *, struct bdc_sr *);
/* transfer sr */
void bdc_sr_xsf(struct bdc *, struct bdc_sr *);
/* EP0 XSF handlers */
void bdc_xsf_ep0_setup_recv(struct bdc *, struct bdc_sr *);
void bdc_xsf_ep0_data_start(struct bdc *, struct bdc_sr *);
void bdc_xsf_ep0_status_start(struct bdc *, struct bdc_sr *);

#endif /* __LINUX_BDC_H__ */