2 * bdc_cmd.c - BRCM BDC USB3.0 device controller
4 * Copyright (C) 2014 Broadcom Corporation
6 * Author: Ashwini Pahuja
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
14 #include <linux/scatterlist.h>
15 #include <linux/slab.h>
21 /* Issues a cmd to cmd processor and waits for cmd completion */
22 static int bdc_issue_cmd(struct bdc
*bdc
, u32 cmd_sc
, u32 param0
,
23 u32 param1
, u32 param2
)
25 u32 timeout
= BDC_CMD_TIMEOUT
;
29 bdc_writel(bdc
->regs
, BDC_CMDPAR0
, param0
);
30 bdc_writel(bdc
->regs
, BDC_CMDPAR1
, param1
);
31 bdc_writel(bdc
->regs
, BDC_CMDPAR2
, param2
);
34 /* Make sure the cmd params are written before asking HW to exec cmd */
36 bdc_writel(bdc
->regs
, BDC_CMDSC
, cmd_sc
| BDC_CMD_CWS
| BDC_CMD_SRD
);
38 temp
= bdc_readl(bdc
->regs
, BDC_CMDSC
);
39 dev_dbg_ratelimited(bdc
->dev
, "cmdsc=%x", temp
);
40 cmd_status
= BDC_CMD_CST(temp
);
41 if (cmd_status
!= BDC_CMDS_BUSY
) {
43 "command completed cmd_sts:%x\n", cmd_status
);
50 "command operation timedout cmd_status=%d\n", cmd_status
);
55 /* Submits cmd and analyze the return value of bdc_issue_cmd */
56 static int bdc_submit_cmd(struct bdc
*bdc
, u32 cmd_sc
,
57 u32 param0
, u32 param1
, u32 param2
)
62 temp
= bdc_readl(bdc
->regs
, BDC_CMDSC
);
64 "%s:CMDSC:%08x cmdsc:%08x param0=%08x param1=%08x param2=%08x\n",
65 __func__
, temp
, cmd_sc
, param0
, param1
, param2
);
67 cmd_status
= BDC_CMD_CST(temp
);
68 if (cmd_status
== BDC_CMDS_BUSY
) {
69 dev_err(bdc
->dev
, "command processor busy: %x\n", cmd_status
);
72 ret
= bdc_issue_cmd(bdc
, cmd_sc
, param0
, param1
, param2
);
75 dev_dbg(bdc
->dev
, "command completed successfully\n");
80 dev_err(bdc
->dev
, "command parameter error\n");
85 dev_err(bdc
->dev
, "Invalid device/ep state\n");
90 dev_err(bdc
->dev
, "Command failed?\n");
95 dev_err(bdc
->dev
, "BDC Internal error\n");
101 "command timedout waited for %dusec\n",
106 dev_dbg(bdc
->dev
, "Unknown command completion code:%x\n", ret
);
112 /* Deconfigure the endpoint from HW */
113 int bdc_dconfig_ep(struct bdc
*bdc
, struct bdc_ep
*ep
)
117 cmd_sc
= BDC_SUB_CMD_DRP_EP
|BDC_CMD_EPN(ep
->ep_num
)|BDC_CMD_EPC
;
118 dev_dbg(bdc
->dev
, "%s ep->ep_num =%d cmd_sc=%x\n", __func__
,
121 return bdc_submit_cmd(bdc
, cmd_sc
, 0, 0, 0);
124 /* Reinitalize the bdlist after config ep command */
125 static void ep_bd_list_reinit(struct bdc_ep
*ep
)
127 struct bdc
*bdc
= ep
->bdc
;
130 ep
->bd_list
.eqp_bdi
= 0;
131 ep
->bd_list
.hwd_bdi
= 0;
132 bd
= ep
->bd_list
.bd_table_array
[0]->start_bd
;
133 dev_dbg(bdc
->dev
, "%s ep:%p bd:%p\n", __func__
, ep
, bd
);
134 memset(bd
, 0, sizeof(struct bdc_bd
));
135 bd
->offset
[3] |= cpu_to_le32(BD_SBF
);
138 /* Configure an endpoint */
139 int bdc_config_ep(struct bdc
*bdc
, struct bdc_ep
*ep
)
141 const struct usb_ss_ep_comp_descriptor
*comp_desc
;
142 const struct usb_endpoint_descriptor
*desc
;
143 u32 param0
, param1
, param2
, cmd_sc
;
144 u32 mps
, mbs
, mul
, si
;
148 comp_desc
= ep
->comp_desc
;
149 cmd_sc
= mul
= mbs
= param2
= 0;
150 param0
= lower_32_bits(ep
->bd_list
.bd_table_array
[0]->dma
);
151 param1
= upper_32_bits(ep
->bd_list
.bd_table_array
[0]->dma
);
152 cpu_to_le32s(¶m0
);
153 cpu_to_le32s(¶m1
);
155 dev_dbg(bdc
->dev
, "%s: param0=%08x param1=%08x",
156 __func__
, param0
, param1
);
157 si
= desc
->bInterval
;
158 si
= clamp_val(si
, 1, 16) - 1;
160 mps
= usb_endpoint_maxp(desc
);
162 param2
|= mps
<< MP_SHIFT
;
163 param2
|= usb_endpoint_type(desc
) << EPT_SHIFT
;
165 switch (bdc
->gadget
.speed
) {
166 case USB_SPEED_SUPER
:
167 if (usb_endpoint_xfer_int(desc
) ||
168 usb_endpoint_xfer_isoc(desc
)) {
170 if (usb_endpoint_xfer_isoc(desc
) && comp_desc
)
171 mul
= comp_desc
->bmAttributes
;
174 param2
|= mul
<< EPM_SHIFT
;
176 mbs
= comp_desc
->bMaxBurst
;
177 param2
|= mbs
<< MB_SHIFT
;
181 if (usb_endpoint_xfer_isoc(desc
) ||
182 usb_endpoint_xfer_int(desc
)) {
185 mbs
= usb_endpoint_maxp_mult(desc
);
186 param2
|= mbs
<< MB_SHIFT
;
192 /* the hardware accepts SI in 125usec range */
193 if (usb_endpoint_xfer_isoc(desc
))
197 * FS Int endpoints can have si of 1-255ms but the controller
198 * accepts 2^bInterval*125usec, so convert ms to nearest power
201 if (usb_endpoint_xfer_int(desc
))
202 si
= fls(desc
->bInterval
* 8) - 1;
207 dev_err(bdc
->dev
, "UNKNOWN speed ERR\n");
211 cmd_sc
|= BDC_CMD_EPC
|BDC_CMD_EPN(ep
->ep_num
)|BDC_SUB_CMD_ADD_EP
;
213 dev_dbg(bdc
->dev
, "cmd_sc=%x param2=%08x\n", cmd_sc
, param2
);
214 ret
= bdc_submit_cmd(bdc
, cmd_sc
, param0
, param1
, param2
);
216 dev_err(bdc
->dev
, "command failed :%x\n", ret
);
219 ep_bd_list_reinit(ep
);
225 * Change the HW deq pointer, if this command is successful, HW will start
226 * fetching the next bd from address dma_addr.
228 int bdc_ep_bla(struct bdc
*bdc
, struct bdc_ep
*ep
, dma_addr_t dma_addr
)
233 dev_dbg(bdc
->dev
, "%s: add=%08llx\n", __func__
,
234 (unsigned long long)(dma_addr
));
235 param0
= lower_32_bits(dma_addr
);
236 param1
= upper_32_bits(dma_addr
);
237 cpu_to_le32s(¶m0
);
238 cpu_to_le32s(¶m1
);
240 cmd_sc
|= BDC_CMD_EPN(ep
->ep_num
)|BDC_CMD_BLA
;
241 dev_dbg(bdc
->dev
, "cmd_sc=%x\n", cmd_sc
);
243 return bdc_submit_cmd(bdc
, cmd_sc
, param0
, param1
, 0);
246 /* Set the address sent bu Host in SET_ADD request */
247 int bdc_address_device(struct bdc
*bdc
, u32 add
)
252 dev_dbg(bdc
->dev
, "%s: add=%d\n", __func__
, add
);
253 cmd_sc
|= BDC_SUB_CMD_ADD
|BDC_CMD_DVC
;
256 return bdc_submit_cmd(bdc
, cmd_sc
, 0, 0, param2
);
259 /* Send a Function Wake notification packet using FH command */
260 int bdc_function_wake_fh(struct bdc
*bdc
, u8 intf
)
266 dev_dbg(bdc
->dev
, "%s intf=%d\n", __func__
, intf
);
267 cmd_sc
|= BDC_CMD_FH
;
268 param0
|= TRA_PACKET
;
269 param0
|= (bdc
->dev_addr
<< 25);
270 param1
|= DEV_NOTF_TYPE
;
271 param1
|= (FWK_SUBTYPE
<<4);
272 dev_dbg(bdc
->dev
, "param0=%08x param1=%08x\n", param0
, param1
);
274 return bdc_submit_cmd(bdc
, cmd_sc
, param0
, param1
, 0);
277 /* Send a Function Wake notification packet using DNC command */
278 int bdc_function_wake(struct bdc
*bdc
, u8 intf
)
283 dev_dbg(bdc
->dev
, "%s intf=%d", __func__
, intf
);
285 cmd_sc
|= BDC_SUB_CMD_FWK
|BDC_CMD_DNC
;
287 return bdc_submit_cmd(bdc
, cmd_sc
, 0, 0, param2
);
290 /* Stall the endpoint */
291 int bdc_ep_set_stall(struct bdc
*bdc
, int epnum
)
295 dev_dbg(bdc
->dev
, "%s epnum=%d\n", __func__
, epnum
);
296 /* issue a stall endpoint command */
297 cmd_sc
|= BDC_SUB_CMD_EP_STL
| BDC_CMD_EPN(epnum
) | BDC_CMD_EPO
;
299 return bdc_submit_cmd(bdc
, cmd_sc
, 0, 0, 0);
302 /* resets the endpoint, called when host sends CLEAR_FEATURE(HALT) */
303 int bdc_ep_clear_stall(struct bdc
*bdc
, int epnum
)
309 dev_dbg(bdc
->dev
, "%s: epnum=%d\n", __func__
, epnum
);
310 ep
= bdc
->bdc_ep_array
[epnum
];
312 * If we are not in stalled then stall Endpoint and issue clear stall,
313 * his will reset the seq number for non EP0.
316 /* if the endpoint it not stallled */
317 if (!(ep
->flags
& BDC_EP_STALL
)) {
318 ret
= bdc_ep_set_stall(bdc
, epnum
);
323 /* Preserve the seq number for ep0 only */
325 cmd_sc
|= BDC_CMD_EPO_RST_SN
;
327 /* issue a reset endpoint command */
328 cmd_sc
|= BDC_SUB_CMD_EP_RST
| BDC_CMD_EPN(epnum
) | BDC_CMD_EPO
;
330 ret
= bdc_submit_cmd(bdc
, cmd_sc
, 0, 0, 0);
332 dev_err(bdc
->dev
, "command failed:%x\n", ret
);
335 bdc_notify_xfr(bdc
, epnum
);
340 /* Stop the endpoint, called when software wants to dequeue some request */
341 int bdc_stop_ep(struct bdc
*bdc
, int epnum
)
347 ep
= bdc
->bdc_ep_array
[epnum
];
348 dev_dbg(bdc
->dev
, "%s: ep:%s ep->flags:%08x\n", __func__
,
349 ep
->name
, ep
->flags
);
350 /* Endpoint has to be in running state to execute stop ep command */
351 if (!(ep
->flags
& BDC_EP_ENABLED
)) {
352 dev_err(bdc
->dev
, "stop endpoint called for disabled ep\n");
355 if ((ep
->flags
& BDC_EP_STALL
) || (ep
->flags
& BDC_EP_STOP
))
358 /* issue a stop endpoint command */
359 cmd_sc
|= BDC_CMD_EP0_XSD
| BDC_SUB_CMD_EP_STP
360 | BDC_CMD_EPN(epnum
) | BDC_CMD_EPO
;
362 ret
= bdc_submit_cmd(bdc
, cmd_sc
, 0, 0, 0);
365 "stop endpoint command didn't complete:%d ep:%s\n",
369 ep
->flags
|= BDC_EP_STOP
;