toggle PID on successful transfer only if odd number of packets was sent
[AROS.git] / arch / arm-native / soc / broadcom / 2708 / usb / usb2otg / usb2otg_intr.c
blobf23296dcdadba65e72a1118d147081104156d927
1 /*
2 Copyright � 2013-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
7 #include <aros/debug.h>
9 #include <proto/exec.h>
10 #include <proto/kernel.h>
11 #include <proto/utility.h>
13 #include "usb2otg_intern.h"
15 static void DumpChannelRegs(int channel)
17 D(bug("CHARBASE=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, CHARBASE))));
18 D(bug("SPLITCTRL=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, SPLITCTRL))));
19 D(bug("INTR=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, INTR))));
20 D(bug("INTRMASK=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, INTRMASK))));
21 D(bug("TRANSSIZE=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, TRANSSIZE))));
22 D(bug("DMAADR=%08x\n", rd32le(USB2OTG_CHANNEL_REG(channel, DMAADDR))));
25 static void handle_SOF(struct USB2OTGUnit *USBUnit, struct ExecBase *SysBase, ULONG frnm)
27 static ULONG last_frame = 0;
28 struct IOUsbHWReq *req = NULL, *next = NULL;
30 wr32le(USB2OTG_INTR, USB2OTG_INTRCORE_DMASTARTOFFRAME);
32 if (frnm < last_frame)
34 D(bug("[USB2OTG] SOF, frame wrap %d %d\n", frnm, last_frame));
37 if (frnm != last_frame)
39 ForeachNodeSafe(&USBUnit->hu_IntXFerQueue, req, next)
41 ULONG last_handled = (ULONG)req->iouh_DriverPrivate1;
42 ULONG next_to_handle = (ULONG)req->iouh_DriverPrivate2;
44 /* Is it time to handle the request? If yes, move it to Scheduled list */
45 if (frnm == next_to_handle)
47 //D(bug("[USB2OTG] schedule INT request on time, last=%d, next=%d, frnm=%d\n", last_handled, next_to_handle, frnm));
48 REMOVE(req);
49 ADDTAIL(&USBUnit->hu_IntXFerScheduled, req);
52 If the request is overdued several scenarios are possible:
53 1. frnm is larger than "last" and "next"
54 0......last....next...frnm....2047
55 2. frnm is smaller than "last" and "next"
56 0..frnm.....last....next......2047
57 3. frnm is bigger than "next" but smaller than "last"
58 0..next....frnm......last.....2047
60 else if (
61 (frnm > next_to_handle && frnm > last_handled) ||
62 (frnm < last_handled && frnm > next_to_handle) ||
63 (frnm > next_to_handle && frnm < last_handled)
66 //D(bug("[USB2OTG] overdued INT request, scheduling. last=%d, next=%d, frnm=%d\n", last_handled, next_to_handle, frnm));
67 REMOVE(req);
68 ADDTAIL(&USBUnit->hu_IntXFerScheduled, req);
72 /* If the Scheduled list is not empty process it now */
73 if (!IsListEmpty(&USBUnit->hu_IntXFerScheduled))
74 FNAME_DEV(ScheduleIntTDs)(USBUnit);
76 last_frame = frnm;
80 void FNAME_DEV(GlobalIRQHandler)(struct USB2OTGUnit *USBUnit, struct ExecBase *SysBase)
82 volatile unsigned int otg_RegVal;
83 struct USB2OTGDevice * USB2OTGBase = USBUnit->hu_USB2OTGBase;
84 ULONG frnm = (rd32le(USB2OTG_HOSTFRAMENO) & 0x3fff) >> 3;
86 otg_RegVal = rd32le(USB2OTG_INTR);
87 wr32le(USB2OTG_INTR, otg_RegVal);
89 if (otg_RegVal & USB2OTG_INTRCORE_DMASTARTOFFRAME)
91 handle_SOF(USBUnit, SysBase, frnm);
94 if (otg_RegVal & USB2OTG_INTRCORE_HOSTCHANNEL)
96 unsigned int otg_ChanVal;
97 int chan;
99 otg_ChanVal = rd32le(USB2OTG_HOSTINTR);
100 wr32le(USB2OTG_HOSTINTR, otg_ChanVal);
102 //D(bug("[USB2OTG] HOSTCHANNEL %x frnm %d\n", otg_ChanVal, frnm));
104 for (chan = 0; chan < 8; chan++)
106 if (otg_ChanVal & (1 << chan))
108 struct IOUsbHWReq * req = USBUnit->hu_InProgressXFer[chan];
109 uint32_t tmp = rd32le(USB2OTG_CHANNEL_REG(chan, INTR));
111 if (req)
113 int do_split = rd32le(USB2OTG_CHANNEL_REG(chan, SPLITCTRL)) & 0x80010000;
115 Channel closed with ACK but not comleted yet and split is active. Complete split now, do not continue with
116 normal processing of this channel
118 if (tmp == 0x22 && do_split)
121 uint32_t split = rd32le(USB2OTG_CHANNEL_REG(chan, SPLITCTRL));
122 //D(bug("[USB2OTG] Completing split transaction in interrupt. SPLITCTRL=%08x\n", split));
124 split |= 1 << 16; /* Set "do complete split" */
125 wr32le(USB2OTG_CHANNEL_REG(chan, SPLITCTRL), split);
127 /* Clear interrupt flags */
128 wr32le(USB2OTG_CHANNEL_REG(chan, INTR), 0x7ff);
130 /* Enable channel again */
131 tmp = rd32le(USB2OTG_CHANNEL_REG(chan, CHARBASE));
132 tmp |= USB2OTG_HOSTCHAR_ENABLE;
133 wr32le(USB2OTG_CHANNEL_REG(chan, CHARBASE), tmp);
135 else if (tmp == 0x42 && do_split == 0x80010000)
137 ULONG last = (ULONG)req->iouh_DriverPrivate1;
138 ULONG thresh = (last + (ULONG)req->iouh_Interval / 2) % 2047;
140 /* Clear interrupt flags */
141 wr32le(USB2OTG_CHANNEL_REG(chan, INTR), 0x7ff);
143 if ((chan >= CHAN_INT1 && chan <= CHAN_INT3) &&
144 ((frnm > thresh && frnm > last) ||
145 (frnm < thresh && frnm < last) ||
146 (frnm > thresh && frnm < last)))
148 //D(bug("[USB2OTG] restarting transaction... %d, %d, %d\n", frnm, req->iouh_DriverPrivate1, req->iouh_DriverPrivate2));
150 /* Disable channel */
151 wr32le(USB2OTG_CHANNEL_REG(chan, CHARBASE), 0);
153 /* Put transfer back into queue */
154 if (req->iouh_Req.io_Command == UHCMD_CONTROLXFER)
155 ADDHEAD(&USBUnit->hu_CtrlXFerQueue, req);
156 if (req->iouh_Req.io_Command == UHCMD_BULKXFER)
157 ADDHEAD(&USBUnit->hu_BulkXFerQueue, req);
158 if (req->iouh_Req.io_Command == UHCMD_INTXFER)
159 ADDHEAD(&USBUnit->hu_IntXFerQueue, req);
161 /* Mark channel free */
162 USBUnit->hu_InProgressXFer[chan] = NULL;
164 else
166 //D(bug("!!! Channel %d, Restarting CSPLIT phase! %d, %d, %d\n", chan, frnm, req->iouh_DriverPrivate1, req->iouh_DriverPrivate2));
167 /* Enable channel again */
168 tmp = rd32le(USB2OTG_CHANNEL_REG(chan, CHARBASE));
169 tmp |= USB2OTG_HOSTCHAR_ENABLE;
170 wr32le(USB2OTG_CHANNEL_REG(chan, CHARBASE), tmp);
174 else if (tmp == 0x12 && do_split)
175 //&& (chan < CHAN_INT1 || chan > CHAN_INT3))
177 /* NAK response from split transaction. Restart the request from beginning */
178 /* D(bug("[USB2OTG] Restarting split transaction\n"));
180 DumpChannelRegs(chan);*/
182 /* Clear interrupt flags */
183 wr32le(USB2OTG_CHANNEL_REG(chan, INTR), 0x7ff);
185 /* Disable channel */
186 wr32le(USB2OTG_CHANNEL_REG(chan, CHARBASE), 0);
188 /* Put transfer back into queue */
189 if (req->iouh_Req.io_Command == UHCMD_CONTROLXFER)
190 ADDHEAD(&USBUnit->hu_CtrlXFerQueue, req);
191 if (req->iouh_Req.io_Command == UHCMD_BULKXFER)
192 ADDHEAD(&USBUnit->hu_BulkXFerQueue, req);
193 if (req->iouh_Req.io_Command == UHCMD_INTXFER)
194 ADDHEAD(&USBUnit->hu_IntXFerQueue, req);
196 /* Mark channel free */
197 USBUnit->hu_InProgressXFer[chan] = NULL;
199 else
201 /* Ignore NAK on INT channels when reporting closed channel */
202 if (tmp != 0x12 || (chan < CHAN_INT1 && chan > CHAN_INT3))
203 D(bug("[USB2OTG] Channel %d closed. INTR=%08x\n", chan, tmp));
205 if (tmp == 0x23)
207 /* Determine number of packets involved in last transfer. If it is even, toggle
208 the PID (the OTG was toggling it itself) */
209 int txsize = rd32le(USB2OTG_CHANNEL_REG(chan, TRANSSIZE)) & 524287;
210 int pktcnt = (txsize + req->iouh_MaxPktSize - 1) / req->iouh_MaxPktSize;
211 if (pktcnt & 1)
213 /* Toggle PID */
214 USBUnit->hu_PIDBits[req->iouh_DevAddr] ^= (2 << (2 * req->iouh_Endpoint));
216 req->iouh_Actual += txsize;
217 req->iouh_Req.io_Error = 0;
219 else if (tmp & 0x80)
221 req->iouh_Actual = 0;
222 req->iouh_Req.io_Error = UHIOERR_TIMEOUT;
223 DumpChannelRegs(chan);
225 else if (tmp & 0x08)
227 req->iouh_Actual = 0;
228 req->iouh_Req.io_Error = UHIOERR_STALL;
229 DumpChannelRegs(chan);
231 else if (tmp & 0x10)
233 /* In case of INT requests NAK is silently ignored. Just put the request back to the IntXferQueue */
234 if (chan >= CHAN_INT1 && chan <= CHAN_INT3)
236 ADDTAIL(&USBUnit->hu_IntXFerQueue, req);
237 req = NULL;
239 else
241 req->iouh_Actual = 0;
242 req->iouh_Req.io_Error = UHIOERR_NAK;
243 DumpChannelRegs(chan);
246 else if (tmp & 0x100)
248 req->iouh_Actual = 0;
249 req->iouh_Req.io_Error = UHIOERR_BABBLE;
250 DumpChannelRegs(chan);
252 else if (tmp & 0x400)
254 req->iouh_Actual = 0;
255 req->iouh_Req.io_Error = UHIOERR_HOSTERROR;
256 DumpChannelRegs(chan);
259 USBUnit->hu_InProgressXFer[chan] = NULL;
260 if (req) FNAME_DEV(TermIO)(req, USB2OTGBase);
262 wr32le(USB2OTG_CHANNEL_REG(chan, INTR), tmp);
269 FNAME_DEV(Cause)(USB2OTGBase, &USBUnit->hu_PendingInt);
273 AROS_INTH1(FNAME_DEV(PendingInt), struct USB2OTGUnit *, otg_Unit)
275 AROS_INTFUNC_INIT
277 //struct USB2OTGDevice * USB2OTGBase = otg_Unit->hu_USB2OTGBase;
278 //D(bug("[USB2OTG] [0x%p:PEND] Pending Work Interupt\n", otg_Unit));
280 /* **************** PROCESS DONE TRANSFERS **************** */
282 FNAME_ROOTHUB(PendingIO)(otg_Unit);
284 // FNAME_DEV(DoFinishedTDs)(otg_Unit);
286 if (otg_Unit->hu_CtrlXFerQueue.lh_Head->ln_Succ)
288 D(bug("[USB2OTG] [0x%p:PEND] Process CtrlXFer ..\n", otg_Unit));
289 FNAME_DEV(ScheduleCtrlTDs)(otg_Unit);
292 if (otg_Unit->hu_IntXFerQueue.lh_Head->ln_Succ)
294 // D(bug("[USB2OTG] [0x%p:PEND] Process IntXFer ..\n", otg_Unit));
295 FNAME_DEV(ScheduleIntTDs)(otg_Unit);
298 if (otg_Unit->hu_BulkXFerQueue.lh_Head->ln_Succ)
300 D(bug("[USB2OTG] [0x%p:PEND] Process BulkXFer ..\n", otg_Unit));
301 // FNAME_DEV(ScheduleBulkTDs)(otg_Unit);
304 //D(bug("[USB2OTG] [0x%p:PEND] finished\n", otg_Unit));
306 return FALSE;
308 AROS_INTFUNC_EXIT
311 AROS_INTH1(FNAME_DEV(NakTimeoutInt), struct USB2OTGUnit *, otg_Unit)
313 AROS_INTFUNC_INIT
315 // struct IOUsbHWReq *ioreq;
317 D(bug("[USB2OTG] [0x%p:NAK] NakTimeout Interupt\n", otg_Unit));
319 // ULONG framecnt;
320 // uhciUpdateFrameCounter(hc);
321 // framecnt = hc->hc_FrameCounter;
322 #if (0)
323 ioreq = (struct IOUsbHWReq *) otg_Unit->hu_TDQueue.lh_Head;
324 while(((struct Node *) ioreq)->ln_Succ)
326 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
328 /* uqh = (struct UhciQH *) ioreq->iouh_DriverPrivate1;
329 if(uqh)
331 KPRINTF(1, ("Examining IOReq=%p with UQH=%p\n", ioreq, uqh));
332 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
333 linkelem = READMEM32_LE(&uqh->uqh_Element);
334 if(linkelem & UHCI_TERMINATE)
336 KPRINTF(1, ("UQH terminated %08lx\n", linkelem));
337 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
339 // give the thing the chance to exit gracefully
340 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
341 causeint = TRUE;
343 } else {
344 utd = (struct UhciTD *) (((IPTR)linkelem & UHCI_PTRMASK) - hc->hc_PCIVirtualAdjust - 16); // struct UhciTD starts 16 before physical TD
345 ctrlstatus = READMEM32_LE(&utd->utd_CtrlStatus);
346 if(ctrlstatus & UTCF_ACTIVE)
348 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
350 // give the thing the chance to exit gracefully
351 KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
352 ctrlstatus &= ~UTCF_ACTIVE;
353 WRITEMEM32_LE(&utd->utd_CtrlStatus, ctrlstatus);
354 causeint = TRUE;
356 } else {
357 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
359 // give the thing the chance to exit gracefully
360 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
361 causeint = TRUE;
367 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
370 // uhciCheckPortStatusChange(hc);
371 #endif
372 FNAME_ROOTHUB(PendingIO)(otg_Unit);
374 otg_Unit->hu_NakTimeoutReq.tr_time.tv_micro = 150 * 1000;
375 SendIO((APTR) &otg_Unit->hu_NakTimeoutReq);
377 D(bug("[USB2OTG] [0x%p:NAK] processed\n", otg_Unit));
379 return FALSE;
381 AROS_INTFUNC_EXIT