1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * bdc_udc.c - BRCM BDC USB3.0 device controller gagdet ops
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2014 Broadcom Corporation
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Ashwini Pahuja
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Based on drivers under drivers/usb/gadget/udc/
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/pci.h>
13*4882a593Smuzhiyun #include <linux/dma-mapping.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/delay.h>
16*4882a593Smuzhiyun #include <linux/ioport.h>
17*4882a593Smuzhiyun #include <linux/sched.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include <linux/errno.h>
20*4882a593Smuzhiyun #include <linux/init.h>
21*4882a593Smuzhiyun #include <linux/timer.h>
22*4882a593Smuzhiyun #include <linux/list.h>
23*4882a593Smuzhiyun #include <linux/interrupt.h>
24*4882a593Smuzhiyun #include <linux/moduleparam.h>
25*4882a593Smuzhiyun #include <linux/device.h>
26*4882a593Smuzhiyun #include <linux/usb/ch9.h>
27*4882a593Smuzhiyun #include <linux/usb/gadget.h>
28*4882a593Smuzhiyun #include <linux/usb/otg.h>
29*4882a593Smuzhiyun #include <linux/pm.h>
30*4882a593Smuzhiyun #include <linux/io.h>
31*4882a593Smuzhiyun #include <linux/irq.h>
32*4882a593Smuzhiyun #include <asm/unaligned.h>
33*4882a593Smuzhiyun #include <linux/platform_device.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include "bdc.h"
36*4882a593Smuzhiyun #include "bdc_ep.h"
37*4882a593Smuzhiyun #include "bdc_cmd.h"
38*4882a593Smuzhiyun #include "bdc_dbg.h"
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static const struct usb_gadget_ops bdc_gadget_ops;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static const char * const conn_speed_str[] = {
43*4882a593Smuzhiyun "Not connected",
44*4882a593Smuzhiyun "Full Speed",
45*4882a593Smuzhiyun "Low Speed",
46*4882a593Smuzhiyun "High Speed",
47*4882a593Smuzhiyun "Super Speed",
48*4882a593Smuzhiyun };
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* EP0 initial descripror */
51*4882a593Smuzhiyun static struct usb_endpoint_descriptor bdc_gadget_ep0_desc = {
52*4882a593Smuzhiyun .bLength = USB_DT_ENDPOINT_SIZE,
53*4882a593Smuzhiyun .bDescriptorType = USB_DT_ENDPOINT,
54*4882a593Smuzhiyun .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
55*4882a593Smuzhiyun .bEndpointAddress = 0,
56*4882a593Smuzhiyun .wMaxPacketSize = cpu_to_le16(EP0_MAX_PKT_SIZE),
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* Advance the srr dqp maintained by SW */
srr_dqp_index_advc(struct bdc * bdc,u32 srr_num)60*4882a593Smuzhiyun static void srr_dqp_index_advc(struct bdc *bdc, u32 srr_num)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct srr *srr;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun srr = &bdc->srr;
65*4882a593Smuzhiyun dev_dbg_ratelimited(bdc->dev, "srr->dqp_index:%d\n", srr->dqp_index);
66*4882a593Smuzhiyun srr->dqp_index++;
67*4882a593Smuzhiyun /* rollback to 0 if we are past the last */
68*4882a593Smuzhiyun if (srr->dqp_index == NUM_SR_ENTRIES)
69*4882a593Smuzhiyun srr->dqp_index = 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* connect sr */
bdc_uspc_connected(struct bdc * bdc)73*4882a593Smuzhiyun static void bdc_uspc_connected(struct bdc *bdc)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun u32 speed, temp;
76*4882a593Smuzhiyun u32 usppms;
77*4882a593Smuzhiyun int ret;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun temp = bdc_readl(bdc->regs, BDC_USPC);
80*4882a593Smuzhiyun speed = BDC_PSP(temp);
81*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s speed=%x\n", __func__, speed);
82*4882a593Smuzhiyun switch (speed) {
83*4882a593Smuzhiyun case BDC_SPEED_SS:
84*4882a593Smuzhiyun bdc_gadget_ep0_desc.wMaxPacketSize =
85*4882a593Smuzhiyun cpu_to_le16(EP0_MAX_PKT_SIZE);
86*4882a593Smuzhiyun bdc->gadget.ep0->maxpacket = EP0_MAX_PKT_SIZE;
87*4882a593Smuzhiyun bdc->gadget.speed = USB_SPEED_SUPER;
88*4882a593Smuzhiyun /* Enable U1T in SS mode */
89*4882a593Smuzhiyun usppms = bdc_readl(bdc->regs, BDC_USPPMS);
90*4882a593Smuzhiyun usppms &= ~BDC_U1T(0xff);
91*4882a593Smuzhiyun usppms |= BDC_U1T(U1_TIMEOUT);
92*4882a593Smuzhiyun usppms |= BDC_PORT_W1S;
93*4882a593Smuzhiyun bdc_writel(bdc->regs, BDC_USPPMS, usppms);
94*4882a593Smuzhiyun break;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun case BDC_SPEED_HS:
97*4882a593Smuzhiyun bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
98*4882a593Smuzhiyun bdc->gadget.ep0->maxpacket = 64;
99*4882a593Smuzhiyun bdc->gadget.speed = USB_SPEED_HIGH;
100*4882a593Smuzhiyun break;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun case BDC_SPEED_FS:
103*4882a593Smuzhiyun bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
104*4882a593Smuzhiyun bdc->gadget.ep0->maxpacket = 64;
105*4882a593Smuzhiyun bdc->gadget.speed = USB_SPEED_FULL;
106*4882a593Smuzhiyun break;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun case BDC_SPEED_LS:
109*4882a593Smuzhiyun bdc_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
110*4882a593Smuzhiyun bdc->gadget.ep0->maxpacket = 8;
111*4882a593Smuzhiyun bdc->gadget.speed = USB_SPEED_LOW;
112*4882a593Smuzhiyun break;
113*4882a593Smuzhiyun default:
114*4882a593Smuzhiyun dev_err(bdc->dev, "UNDEFINED SPEED\n");
115*4882a593Smuzhiyun return;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun dev_dbg(bdc->dev, "connected at %s\n", conn_speed_str[speed]);
118*4882a593Smuzhiyun /* Now we know the speed, configure ep0 */
119*4882a593Smuzhiyun bdc->bdc_ep_array[1]->desc = &bdc_gadget_ep0_desc;
120*4882a593Smuzhiyun ret = bdc_config_ep(bdc, bdc->bdc_ep_array[1]);
121*4882a593Smuzhiyun if (ret)
122*4882a593Smuzhiyun dev_err(bdc->dev, "EP0 config failed\n");
123*4882a593Smuzhiyun bdc->bdc_ep_array[1]->usb_ep.desc = &bdc_gadget_ep0_desc;
124*4882a593Smuzhiyun bdc->bdc_ep_array[1]->flags |= BDC_EP_ENABLED;
125*4882a593Smuzhiyun usb_gadget_set_state(&bdc->gadget, USB_STATE_DEFAULT);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* device got disconnected */
bdc_uspc_disconnected(struct bdc * bdc,bool reinit)129*4882a593Smuzhiyun static void bdc_uspc_disconnected(struct bdc *bdc, bool reinit)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun struct bdc_ep *ep;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s\n", __func__);
134*4882a593Smuzhiyun /*
135*4882a593Smuzhiyun * Only stop ep0 from here, rest of the endpoints will be disabled
136*4882a593Smuzhiyun * from gadget_disconnect
137*4882a593Smuzhiyun */
138*4882a593Smuzhiyun ep = bdc->bdc_ep_array[1];
139*4882a593Smuzhiyun if (ep && (ep->flags & BDC_EP_ENABLED))
140*4882a593Smuzhiyun /* if enabled then stop and remove requests */
141*4882a593Smuzhiyun bdc_ep_disable(ep);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun if (bdc->gadget_driver && bdc->gadget_driver->disconnect) {
144*4882a593Smuzhiyun spin_unlock(&bdc->lock);
145*4882a593Smuzhiyun bdc->gadget_driver->disconnect(&bdc->gadget);
146*4882a593Smuzhiyun spin_lock(&bdc->lock);
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun /* Set Unknown speed */
149*4882a593Smuzhiyun bdc->gadget.speed = USB_SPEED_UNKNOWN;
150*4882a593Smuzhiyun bdc->devstatus &= DEVSTATUS_CLEAR;
151*4882a593Smuzhiyun bdc->delayed_status = false;
152*4882a593Smuzhiyun bdc->reinit = reinit;
153*4882a593Smuzhiyun bdc->test_mode = false;
154*4882a593Smuzhiyun usb_gadget_set_state(&bdc->gadget, USB_STATE_NOTATTACHED);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* TNotify wkaeup timer */
bdc_func_wake_timer(struct work_struct * work)158*4882a593Smuzhiyun static void bdc_func_wake_timer(struct work_struct *work)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun struct bdc *bdc = container_of(work, struct bdc, func_wake_notify.work);
161*4882a593Smuzhiyun unsigned long flags;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s\n", __func__);
164*4882a593Smuzhiyun spin_lock_irqsave(&bdc->lock, flags);
165*4882a593Smuzhiyun /*
166*4882a593Smuzhiyun * Check if host has started transferring on endpoints
167*4882a593Smuzhiyun * FUNC_WAKE_ISSUED is cleared when transfer has started after resume
168*4882a593Smuzhiyun */
169*4882a593Smuzhiyun if (bdc->devstatus & FUNC_WAKE_ISSUED) {
170*4882a593Smuzhiyun dev_dbg(bdc->dev, "FUNC_WAKE_ISSUED FLAG IS STILL SET\n");
171*4882a593Smuzhiyun /* flag is still set, so again send func wake */
172*4882a593Smuzhiyun bdc_function_wake_fh(bdc, 0);
173*4882a593Smuzhiyun schedule_delayed_work(&bdc->func_wake_notify,
174*4882a593Smuzhiyun msecs_to_jiffies(BDC_TNOTIFY));
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun spin_unlock_irqrestore(&bdc->lock, flags);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* handler for Link state change condition */
handle_link_state_change(struct bdc * bdc,u32 uspc)180*4882a593Smuzhiyun static void handle_link_state_change(struct bdc *bdc, u32 uspc)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun u32 link_state;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun dev_dbg(bdc->dev, "Link state change");
185*4882a593Smuzhiyun link_state = BDC_PST(uspc);
186*4882a593Smuzhiyun switch (link_state) {
187*4882a593Smuzhiyun case BDC_LINK_STATE_U3:
188*4882a593Smuzhiyun if ((bdc->gadget.speed != USB_SPEED_UNKNOWN) &&
189*4882a593Smuzhiyun bdc->gadget_driver->suspend) {
190*4882a593Smuzhiyun dev_dbg(bdc->dev, "Entered Suspend mode\n");
191*4882a593Smuzhiyun spin_unlock(&bdc->lock);
192*4882a593Smuzhiyun bdc->devstatus |= DEVICE_SUSPENDED;
193*4882a593Smuzhiyun bdc->gadget_driver->suspend(&bdc->gadget);
194*4882a593Smuzhiyun spin_lock(&bdc->lock);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun case BDC_LINK_STATE_U0:
198*4882a593Smuzhiyun if (bdc->devstatus & REMOTE_WAKEUP_ISSUED) {
199*4882a593Smuzhiyun bdc->devstatus &= ~REMOTE_WAKEUP_ISSUED;
200*4882a593Smuzhiyun if (bdc->gadget.speed == USB_SPEED_SUPER) {
201*4882a593Smuzhiyun bdc_function_wake_fh(bdc, 0);
202*4882a593Smuzhiyun bdc->devstatus |= FUNC_WAKE_ISSUED;
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun * Start a Notification timer and check if the
205*4882a593Smuzhiyun * Host transferred anything on any of the EPs,
206*4882a593Smuzhiyun * if not then send function wake again every
207*4882a593Smuzhiyun * TNotification secs until host initiates
208*4882a593Smuzhiyun * transfer to BDC, USB3 spec Table 8.13
209*4882a593Smuzhiyun */
210*4882a593Smuzhiyun schedule_delayed_work(
211*4882a593Smuzhiyun &bdc->func_wake_notify,
212*4882a593Smuzhiyun msecs_to_jiffies(BDC_TNOTIFY));
213*4882a593Smuzhiyun dev_dbg(bdc->dev, "sched func_wake_notify\n");
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun break;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun case BDC_LINK_STATE_RESUME:
219*4882a593Smuzhiyun dev_dbg(bdc->dev, "Resumed from Suspend\n");
220*4882a593Smuzhiyun if (bdc->devstatus & DEVICE_SUSPENDED) {
221*4882a593Smuzhiyun bdc->gadget_driver->resume(&bdc->gadget);
222*4882a593Smuzhiyun bdc->devstatus &= ~DEVICE_SUSPENDED;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun break;
225*4882a593Smuzhiyun default:
226*4882a593Smuzhiyun dev_dbg(bdc->dev, "link state:%d\n", link_state);
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /* something changes on upstream port, handle it here */
bdc_sr_uspc(struct bdc * bdc,struct bdc_sr * sreport)231*4882a593Smuzhiyun void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun u32 clear_flags = 0;
234*4882a593Smuzhiyun u32 uspc;
235*4882a593Smuzhiyun bool connected = false;
236*4882a593Smuzhiyun bool disconn = false;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun uspc = bdc_readl(bdc->regs, BDC_USPC);
239*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s uspc=0x%08x\n", __func__, uspc);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun /* Port connect changed */
242*4882a593Smuzhiyun if (uspc & BDC_PCC) {
243*4882a593Smuzhiyun /* Vbus not present, and not connected to Downstream port */
244*4882a593Smuzhiyun if ((uspc & BDC_VBC) && !(uspc & BDC_VBS) && !(uspc & BDC_PCS))
245*4882a593Smuzhiyun disconn = true;
246*4882a593Smuzhiyun else if ((uspc & BDC_PCS) && !BDC_PST(uspc))
247*4882a593Smuzhiyun connected = true;
248*4882a593Smuzhiyun clear_flags |= BDC_PCC;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun /* Change in VBus and VBus is present */
252*4882a593Smuzhiyun if ((uspc & BDC_VBC) && (uspc & BDC_VBS)) {
253*4882a593Smuzhiyun if (bdc->pullup) {
254*4882a593Smuzhiyun dev_dbg(bdc->dev, "Do a softconnect\n");
255*4882a593Smuzhiyun /* Attached state, do a softconnect */
256*4882a593Smuzhiyun bdc_softconn(bdc);
257*4882a593Smuzhiyun usb_gadget_set_state(&bdc->gadget, USB_STATE_POWERED);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun clear_flags |= BDC_VBC;
260*4882a593Smuzhiyun } else if ((uspc & BDC_PRS) || (uspc & BDC_PRC) || disconn) {
261*4882a593Smuzhiyun /* Hot reset, warm reset, 2.0 bus reset or disconn */
262*4882a593Smuzhiyun dev_dbg(bdc->dev, "Port reset or disconn\n");
263*4882a593Smuzhiyun bdc_uspc_disconnected(bdc, disconn);
264*4882a593Smuzhiyun clear_flags |= BDC_PRC;
265*4882a593Smuzhiyun } else if ((uspc & BDC_PSC) && (uspc & BDC_PCS)) {
266*4882a593Smuzhiyun /* Change in Link state */
267*4882a593Smuzhiyun handle_link_state_change(bdc, uspc);
268*4882a593Smuzhiyun clear_flags |= BDC_PSC;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /*
272*4882a593Smuzhiyun * In SS we might not have PRC bit set before connection, but in 2.0
273*4882a593Smuzhiyun * the PRC bit is set before connection, so moving this condition out
274*4882a593Smuzhiyun * of bus reset to handle both SS/2.0 speeds.
275*4882a593Smuzhiyun */
276*4882a593Smuzhiyun if (connected) {
277*4882a593Smuzhiyun /* This is the connect event for U0/L0 */
278*4882a593Smuzhiyun dev_dbg(bdc->dev, "Connected\n");
279*4882a593Smuzhiyun bdc_uspc_connected(bdc);
280*4882a593Smuzhiyun bdc->devstatus &= ~(DEVICE_SUSPENDED);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun uspc = bdc_readl(bdc->regs, BDC_USPC);
283*4882a593Smuzhiyun uspc &= (~BDC_USPSC_RW);
284*4882a593Smuzhiyun dev_dbg(bdc->dev, "uspc=%x\n", uspc);
285*4882a593Smuzhiyun bdc_writel(bdc->regs, BDC_USPC, clear_flags);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /* Main interrupt handler for bdc */
bdc_udc_interrupt(int irq,void * _bdc)289*4882a593Smuzhiyun static irqreturn_t bdc_udc_interrupt(int irq, void *_bdc)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun u32 eqp_index, dqp_index, sr_type, srr_int;
292*4882a593Smuzhiyun struct bdc_sr *sreport;
293*4882a593Smuzhiyun struct bdc *bdc = _bdc;
294*4882a593Smuzhiyun u32 status;
295*4882a593Smuzhiyun int ret;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun spin_lock(&bdc->lock);
298*4882a593Smuzhiyun status = bdc_readl(bdc->regs, BDC_BDCSC);
299*4882a593Smuzhiyun if (!(status & BDC_GIP)) {
300*4882a593Smuzhiyun spin_unlock(&bdc->lock);
301*4882a593Smuzhiyun return IRQ_NONE;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0));
304*4882a593Smuzhiyun /* Check if the SRR IP bit it set? */
305*4882a593Smuzhiyun if (!(srr_int & BDC_SRR_IP)) {
306*4882a593Smuzhiyun dev_warn(bdc->dev, "Global irq pending but SRR IP is 0\n");
307*4882a593Smuzhiyun spin_unlock(&bdc->lock);
308*4882a593Smuzhiyun return IRQ_NONE;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun eqp_index = BDC_SRR_EPI(srr_int);
311*4882a593Smuzhiyun dqp_index = BDC_SRR_DPI(srr_int);
312*4882a593Smuzhiyun dev_dbg(bdc->dev,
313*4882a593Smuzhiyun "%s eqp_index=%d dqp_index=%d srr.dqp_index=%d\n\n",
314*4882a593Smuzhiyun __func__, eqp_index, dqp_index, bdc->srr.dqp_index);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun /* check for ring empty condition */
317*4882a593Smuzhiyun if (eqp_index == dqp_index) {
318*4882a593Smuzhiyun dev_dbg(bdc->dev, "SRR empty?\n");
319*4882a593Smuzhiyun spin_unlock(&bdc->lock);
320*4882a593Smuzhiyun return IRQ_HANDLED;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun while (bdc->srr.dqp_index != eqp_index) {
324*4882a593Smuzhiyun sreport = &bdc->srr.sr_bds[bdc->srr.dqp_index];
325*4882a593Smuzhiyun /* sreport is read before using it */
326*4882a593Smuzhiyun rmb();
327*4882a593Smuzhiyun sr_type = le32_to_cpu(sreport->offset[3]) & BD_TYPE_BITMASK;
328*4882a593Smuzhiyun dev_dbg_ratelimited(bdc->dev, "sr_type=%d\n", sr_type);
329*4882a593Smuzhiyun switch (sr_type) {
330*4882a593Smuzhiyun case SR_XSF:
331*4882a593Smuzhiyun bdc->sr_handler[0](bdc, sreport);
332*4882a593Smuzhiyun break;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun case SR_USPC:
335*4882a593Smuzhiyun bdc->sr_handler[1](bdc, sreport);
336*4882a593Smuzhiyun break;
337*4882a593Smuzhiyun default:
338*4882a593Smuzhiyun dev_warn(bdc->dev, "SR:%d not handled\n", sr_type);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun /* Advance the srr dqp index */
341*4882a593Smuzhiyun srr_dqp_index_advc(bdc, 0);
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun /* update the hw dequeue pointer */
344*4882a593Smuzhiyun srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0));
345*4882a593Smuzhiyun srr_int &= ~BDC_SRR_DPI_MASK;
346*4882a593Smuzhiyun srr_int &= ~(BDC_SRR_RWS|BDC_SRR_RST|BDC_SRR_ISR);
347*4882a593Smuzhiyun srr_int |= ((bdc->srr.dqp_index) << 16);
348*4882a593Smuzhiyun srr_int |= BDC_SRR_IP;
349*4882a593Smuzhiyun bdc_writel(bdc->regs, BDC_SRRINT(0), srr_int);
350*4882a593Smuzhiyun srr_int = bdc_readl(bdc->regs, BDC_SRRINT(0));
351*4882a593Smuzhiyun if (bdc->reinit) {
352*4882a593Smuzhiyun ret = bdc_reinit(bdc);
353*4882a593Smuzhiyun if (ret)
354*4882a593Smuzhiyun dev_err(bdc->dev, "err in bdc reinit\n");
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun spin_unlock(&bdc->lock);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun return IRQ_HANDLED;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun /* Gadget ops */
bdc_udc_start(struct usb_gadget * gadget,struct usb_gadget_driver * driver)363*4882a593Smuzhiyun static int bdc_udc_start(struct usb_gadget *gadget,
364*4882a593Smuzhiyun struct usb_gadget_driver *driver)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun struct bdc *bdc = gadget_to_bdc(gadget);
367*4882a593Smuzhiyun unsigned long flags;
368*4882a593Smuzhiyun int ret = 0;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s()\n", __func__);
371*4882a593Smuzhiyun spin_lock_irqsave(&bdc->lock, flags);
372*4882a593Smuzhiyun if (bdc->gadget_driver) {
373*4882a593Smuzhiyun dev_err(bdc->dev, "%s is already bound to %s\n",
374*4882a593Smuzhiyun bdc->gadget.name,
375*4882a593Smuzhiyun bdc->gadget_driver->driver.name);
376*4882a593Smuzhiyun ret = -EBUSY;
377*4882a593Smuzhiyun goto err;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun /*
380*4882a593Smuzhiyun * Run the controller from here and when BDC is connected to
381*4882a593Smuzhiyun * Host then driver will receive a USPC SR with VBUS present
382*4882a593Smuzhiyun * and then driver will do a softconnect.
383*4882a593Smuzhiyun */
384*4882a593Smuzhiyun ret = bdc_run(bdc);
385*4882a593Smuzhiyun if (ret) {
386*4882a593Smuzhiyun dev_err(bdc->dev, "%s bdc run fail\n", __func__);
387*4882a593Smuzhiyun goto err;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun bdc->gadget_driver = driver;
390*4882a593Smuzhiyun bdc->gadget.dev.driver = &driver->driver;
391*4882a593Smuzhiyun err:
392*4882a593Smuzhiyun spin_unlock_irqrestore(&bdc->lock, flags);
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun return ret;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
bdc_udc_stop(struct usb_gadget * gadget)397*4882a593Smuzhiyun static int bdc_udc_stop(struct usb_gadget *gadget)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun struct bdc *bdc = gadget_to_bdc(gadget);
400*4882a593Smuzhiyun unsigned long flags;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s()\n", __func__);
403*4882a593Smuzhiyun spin_lock_irqsave(&bdc->lock, flags);
404*4882a593Smuzhiyun bdc_stop(bdc);
405*4882a593Smuzhiyun bdc->gadget_driver = NULL;
406*4882a593Smuzhiyun bdc->gadget.dev.driver = NULL;
407*4882a593Smuzhiyun spin_unlock_irqrestore(&bdc->lock, flags);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun return 0;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
bdc_udc_pullup(struct usb_gadget * gadget,int is_on)412*4882a593Smuzhiyun static int bdc_udc_pullup(struct usb_gadget *gadget, int is_on)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun struct bdc *bdc = gadget_to_bdc(gadget);
415*4882a593Smuzhiyun unsigned long flags;
416*4882a593Smuzhiyun u32 uspc;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s() is_on:%d\n", __func__, is_on);
419*4882a593Smuzhiyun if (!gadget)
420*4882a593Smuzhiyun return -EINVAL;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun spin_lock_irqsave(&bdc->lock, flags);
423*4882a593Smuzhiyun if (!is_on) {
424*4882a593Smuzhiyun bdc_softdisconn(bdc);
425*4882a593Smuzhiyun bdc->pullup = false;
426*4882a593Smuzhiyun } else {
427*4882a593Smuzhiyun /*
428*4882a593Smuzhiyun * For a self powered device, we need to wait till we receive
429*4882a593Smuzhiyun * a VBUS change and Vbus present event, then if pullup flag
430*4882a593Smuzhiyun * is set, then only we present the Termintation.
431*4882a593Smuzhiyun */
432*4882a593Smuzhiyun bdc->pullup = true;
433*4882a593Smuzhiyun /*
434*4882a593Smuzhiyun * Check if BDC is already connected to Host i.e Vbus=1,
435*4882a593Smuzhiyun * if yes, then present TERM now, this is typical for bus
436*4882a593Smuzhiyun * powered devices.
437*4882a593Smuzhiyun */
438*4882a593Smuzhiyun uspc = bdc_readl(bdc->regs, BDC_USPC);
439*4882a593Smuzhiyun if (uspc & BDC_VBS)
440*4882a593Smuzhiyun bdc_softconn(bdc);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun spin_unlock_irqrestore(&bdc->lock, flags);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun return 0;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
bdc_udc_set_selfpowered(struct usb_gadget * gadget,int is_self)447*4882a593Smuzhiyun static int bdc_udc_set_selfpowered(struct usb_gadget *gadget,
448*4882a593Smuzhiyun int is_self)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun struct bdc *bdc = gadget_to_bdc(gadget);
451*4882a593Smuzhiyun unsigned long flags;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s()\n", __func__);
454*4882a593Smuzhiyun gadget->is_selfpowered = (is_self != 0);
455*4882a593Smuzhiyun spin_lock_irqsave(&bdc->lock, flags);
456*4882a593Smuzhiyun if (!is_self)
457*4882a593Smuzhiyun bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
458*4882a593Smuzhiyun else
459*4882a593Smuzhiyun bdc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun spin_unlock_irqrestore(&bdc->lock, flags);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun return 0;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
bdc_udc_wakeup(struct usb_gadget * gadget)466*4882a593Smuzhiyun static int bdc_udc_wakeup(struct usb_gadget *gadget)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun struct bdc *bdc = gadget_to_bdc(gadget);
469*4882a593Smuzhiyun unsigned long flags;
470*4882a593Smuzhiyun u8 link_state;
471*4882a593Smuzhiyun u32 uspc;
472*4882a593Smuzhiyun int ret = 0;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun dev_dbg(bdc->dev,
475*4882a593Smuzhiyun "%s() bdc->devstatus=%08x\n",
476*4882a593Smuzhiyun __func__, bdc->devstatus);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun if (!(bdc->devstatus & REMOTE_WAKE_ENABLE))
479*4882a593Smuzhiyun return -EOPNOTSUPP;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun spin_lock_irqsave(&bdc->lock, flags);
482*4882a593Smuzhiyun uspc = bdc_readl(bdc->regs, BDC_USPC);
483*4882a593Smuzhiyun link_state = BDC_PST(uspc);
484*4882a593Smuzhiyun dev_dbg(bdc->dev, "link_state =%d portsc=%x", link_state, uspc);
485*4882a593Smuzhiyun if (link_state != BDC_LINK_STATE_U3) {
486*4882a593Smuzhiyun dev_warn(bdc->dev,
487*4882a593Smuzhiyun "can't wakeup from link state %d\n",
488*4882a593Smuzhiyun link_state);
489*4882a593Smuzhiyun ret = -EINVAL;
490*4882a593Smuzhiyun goto out;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun if (bdc->gadget.speed == USB_SPEED_SUPER)
493*4882a593Smuzhiyun bdc->devstatus |= REMOTE_WAKEUP_ISSUED;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun uspc &= ~BDC_PST_MASK;
496*4882a593Smuzhiyun uspc &= (~BDC_USPSC_RW);
497*4882a593Smuzhiyun uspc |= BDC_PST(BDC_LINK_STATE_U0);
498*4882a593Smuzhiyun uspc |= BDC_SWS;
499*4882a593Smuzhiyun bdc_writel(bdc->regs, BDC_USPC, uspc);
500*4882a593Smuzhiyun uspc = bdc_readl(bdc->regs, BDC_USPC);
501*4882a593Smuzhiyun link_state = BDC_PST(uspc);
502*4882a593Smuzhiyun dev_dbg(bdc->dev, "link_state =%d portsc=%x", link_state, uspc);
503*4882a593Smuzhiyun out:
504*4882a593Smuzhiyun spin_unlock_irqrestore(&bdc->lock, flags);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun return ret;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun static const struct usb_gadget_ops bdc_gadget_ops = {
510*4882a593Smuzhiyun .wakeup = bdc_udc_wakeup,
511*4882a593Smuzhiyun .set_selfpowered = bdc_udc_set_selfpowered,
512*4882a593Smuzhiyun .pullup = bdc_udc_pullup,
513*4882a593Smuzhiyun .udc_start = bdc_udc_start,
514*4882a593Smuzhiyun .udc_stop = bdc_udc_stop,
515*4882a593Smuzhiyun };
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun /* Init the gadget interface and register the udc */
bdc_udc_init(struct bdc * bdc)518*4882a593Smuzhiyun int bdc_udc_init(struct bdc *bdc)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun u32 temp;
521*4882a593Smuzhiyun int ret;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s()\n", __func__);
524*4882a593Smuzhiyun bdc->gadget.ops = &bdc_gadget_ops;
525*4882a593Smuzhiyun bdc->gadget.max_speed = USB_SPEED_SUPER;
526*4882a593Smuzhiyun bdc->gadget.speed = USB_SPEED_UNKNOWN;
527*4882a593Smuzhiyun bdc->gadget.dev.parent = bdc->dev;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun bdc->gadget.sg_supported = false;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun bdc->gadget.name = BRCM_BDC_NAME;
533*4882a593Smuzhiyun ret = devm_request_irq(bdc->dev, bdc->irq, bdc_udc_interrupt,
534*4882a593Smuzhiyun IRQF_SHARED , BRCM_BDC_NAME, bdc);
535*4882a593Smuzhiyun if (ret) {
536*4882a593Smuzhiyun dev_err(bdc->dev,
537*4882a593Smuzhiyun "failed to request irq #%d %d\n",
538*4882a593Smuzhiyun bdc->irq, ret);
539*4882a593Smuzhiyun return ret;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun ret = bdc_init_ep(bdc);
543*4882a593Smuzhiyun if (ret) {
544*4882a593Smuzhiyun dev_err(bdc->dev, "bdc init ep fail: %d\n", ret);
545*4882a593Smuzhiyun return ret;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget);
549*4882a593Smuzhiyun if (ret) {
550*4882a593Smuzhiyun dev_err(bdc->dev, "failed to register udc\n");
551*4882a593Smuzhiyun goto err0;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun usb_gadget_set_state(&bdc->gadget, USB_STATE_NOTATTACHED);
554*4882a593Smuzhiyun bdc->bdc_ep_array[1]->desc = &bdc_gadget_ep0_desc;
555*4882a593Smuzhiyun /*
556*4882a593Smuzhiyun * Allocate bd list for ep0 only, ep0 will be enabled on connect
557*4882a593Smuzhiyun * status report when the speed is known
558*4882a593Smuzhiyun */
559*4882a593Smuzhiyun ret = bdc_ep_enable(bdc->bdc_ep_array[1]);
560*4882a593Smuzhiyun if (ret) {
561*4882a593Smuzhiyun dev_err(bdc->dev, "fail to enable %s\n",
562*4882a593Smuzhiyun bdc->bdc_ep_array[1]->name);
563*4882a593Smuzhiyun goto err1;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun INIT_DELAYED_WORK(&bdc->func_wake_notify, bdc_func_wake_timer);
566*4882a593Smuzhiyun /* Enable Interrupts */
567*4882a593Smuzhiyun temp = bdc_readl(bdc->regs, BDC_BDCSC);
568*4882a593Smuzhiyun temp |= BDC_GIE;
569*4882a593Smuzhiyun bdc_writel(bdc->regs, BDC_BDCSC, temp);
570*4882a593Smuzhiyun return 0;
571*4882a593Smuzhiyun err1:
572*4882a593Smuzhiyun usb_del_gadget_udc(&bdc->gadget);
573*4882a593Smuzhiyun err0:
574*4882a593Smuzhiyun bdc_free_ep(bdc);
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun return ret;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
bdc_udc_exit(struct bdc * bdc)579*4882a593Smuzhiyun void bdc_udc_exit(struct bdc *bdc)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun unsigned long flags;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun dev_dbg(bdc->dev, "%s()\n", __func__);
584*4882a593Smuzhiyun spin_lock_irqsave(&bdc->lock, flags);
585*4882a593Smuzhiyun bdc_ep_disable(bdc->bdc_ep_array[1]);
586*4882a593Smuzhiyun spin_unlock_irqrestore(&bdc->lock, flags);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun usb_del_gadget_udc(&bdc->gadget);
589*4882a593Smuzhiyun bdc_free_ep(bdc);
590*4882a593Smuzhiyun }
591