/* Structures */
-struct dwc3_trb_hw;
+struct dwc3_trb;
/**
* struct dwc3_event_buffer - Software event buffer representation
struct list_head request_list;
struct list_head req_queued;
- struct dwc3_trb_hw *trb_pool;
+ struct dwc3_trb *trb_pool;
dma_addr_t trb_pool_dma;
u32 free_slot;
u32 busy_slot;
DWC3_CONFIGURED_STATE,
};
-/**
- * struct dwc3_trb - transfer request block
- * @bpl: lower 32bit of the buffer
- * @bph: higher 32bit of the buffer
- * @length: buffer size (up to 16mb - 1)
- * @pcm1: packet count m1
- * @trbsts: trb status
- * 0 = ok
- * 1 = missed isoc
- * 2 = setup pending
- * @hwo: hardware owner of descriptor
- * @lst: last trb
- * @chn: chain buffers
- * @csp: continue on short packets (only supported on isoc eps)
- * @trbctl: trb control
- * 1 = normal
- * 2 = control-setup
- * 3 = control-status-2
- * 4 = control-status-3
- * 5 = control-data (first trb of data stage)
- * 6 = isochronous-first (first trb of service interval)
- * 7 = isochronous
- * 8 = link trb
- * others = reserved
- * @isp_imi: interrupt on short packet / interrupt on missed isoc
- * @ioc: interrupt on complete
- * @sid_sofn: Stream ID / SOF Number
- */
-struct dwc3_trb {
- u64 bplh;
-
- union {
- struct {
- u32 length:24;
- u32 pcm1:2;
- u32 reserved27_26:2;
- u32 trbsts:4;
-#define DWC3_TRB_STS_OKAY 0
-#define DWC3_TRB_STS_MISSED_ISOC 1
-#define DWC3_TRB_STS_SETUP_PENDING 2
- };
- u32 len_pcm;
- };
-
- union {
- struct {
- u32 hwo:1;
- u32 lst:1;
- u32 chn:1;
- u32 csp:1;
- u32 trbctl:6;
- u32 isp_imi:1;
- u32 ioc:1;
- u32 reserved13_12:2;
- u32 sid_sofn:16;
- u32 reserved31_30:2;
- };
- u32 control;
- };
-} __packed;
+/* TRB Length, PCM and Status */
+#define DWC3_TRB_SIZE_MASK (0x00ffffff)
+#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
+#define DWC3_TRB_SIZE_PCM1(n) (((n) & 0x03) << 24)
+#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28) >> 28))
+
+#define DWC3_TRBSTS_OK 0
+#define DWC3_TRBSTS_MISSED_ISOC 1
+#define DWC3_TRBSTS_SETUP_PENDING 2
+
+/* TRB Control */
+#define DWC3_TRB_CTRL_HWO (1 << 0)
+#define DWC3_TRB_CTRL_LST (1 << 1)
+#define DWC3_TRB_CTRL_CHN (1 << 2)
+#define DWC3_TRB_CTRL_CSP (1 << 3)
+#define DWC3_TRB_CTRL_TRBCTL(n) (((n) & 0x3f) << 4)
+#define DWC3_TRB_CTRL_ISP_IMI (1 << 10)
+#define DWC3_TRB_CTRL_IOC (1 << 11)
+#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
+
+#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1)
+#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2)
+#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3)
+#define DWC3_TRBCTL_CONTROL_STATUS3 DWC3_TRB_CTRL_TRBCTL(4)
+#define DWC3_TRBCTL_CONTROL_DATA DWC3_TRB_CTRL_TRBCTL(5)
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST DWC3_TRB_CTRL_TRBCTL(6)
+#define DWC3_TRBCTL_ISOCHRONOUS DWC3_TRB_CTRL_TRBCTL(7)
+#define DWC3_TRBCTL_LINK_TRB DWC3_TRB_CTRL_TRBCTL(8)
/**
- * struct dwc3_trb_hw - transfer request block (hw format)
+ * struct dwc3_trb - transfer request block (hw format)
* @bpl: DW0-3
* @bph: DW4-7
* @size: DW8-B
* @trl: DWC-F
*/
-struct dwc3_trb_hw {
- __le32 bpl;
- __le32 bph;
- __le32 size;
- __le32 ctrl;
+struct dwc3_trb {
+ u32 bpl;
+ u32 bph;
+ u32 size;
+ u32 ctrl;
} __packed;
-static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
-{
- hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
- hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
- hw->size = cpu_to_le32p(&nat->len_pcm);
- /* HWO is written last */
- hw->ctrl = cpu_to_le32p(&nat->control);
-}
-
-static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
-{
- u64 bplh;
-
- bplh = le32_to_cpup(&hw->bpl);
- bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
- nat->bplh = bplh;
-
- nat->len_pcm = le32_to_cpup(&hw->size);
- nat->control = le32_to_cpup(&hw->ctrl);
-}
-
/**
* dwc3_hwparams - copy of HWPARAMS registers
* @hwparams0 - GHWPARAMS0
struct dwc3_ep *dep;
u8 epnum;
- struct dwc3_trb_hw *trb;
+ struct dwc3_trb *trb;
dma_addr_t trb_dma;
unsigned direction:1;
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
- struct dwc3_trb_hw *ep0_trb;
+ struct dwc3_trb *ep0_trb;
void *ep0_bounce;
u8 *setup_buf;
dma_addr_t ctrl_req_addr;
/* -------------------------------------------------------------------------- */
-#define DWC3_TRBSTS_OK 0
-#define DWC3_TRBSTS_MISSED_ISOC 1
-#define DWC3_TRBSTS_SETUP_PENDING 2
-
-#define DWC3_TRBCTL_NORMAL 1
-#define DWC3_TRBCTL_CONTROL_SETUP 2
-#define DWC3_TRBCTL_CONTROL_STATUS2 3
-#define DWC3_TRBCTL_CONTROL_STATUS3 4
-#define DWC3_TRBCTL_CONTROL_DATA 5
-#define DWC3_TRBCTL_ISOCHRONOUS_FIRST 6
-#define DWC3_TRBCTL_ISOCHRONOUS 7
-#define DWC3_TRBCTL_LINK_TRB 8
-
/* -------------------------------------------------------------------------- */
struct dwc3_event_type {
u32 len, u32 type)
{
struct dwc3_gadget_ep_cmd_params params;
- struct dwc3_trb_hw *trb_hw;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
struct dwc3_ep *dep;
int ret;
return 0;
}
- trb_hw = dwc->ep0_trb;
- memset(&trb, 0, sizeof(trb));
+ trb = dwc->ep0_trb;
- trb.trbctl = type;
- trb.bplh = buf_dma;
- trb.length = len;
+ trb->bpl = lower_32_bits(buf_dma);
+ trb->bph = upper_32_bits(buf_dma);
+ trb->size = len;
+ trb->ctrl = type;
- trb.hwo = 1;
- trb.lst = 1;
- trb.ioc = 1;
- trb.isp_imi = 1;
-
- dwc3_trb_to_hw(&trb, trb_hw);
+ trb->ctrl |= (DWC3_TRB_CTRL_HWO
+ | DWC3_TRB_CTRL_LST
+ | DWC3_TRB_CTRL_IOC
+ | DWC3_TRB_CTRL_ISP_IMI);
memset(¶ms, 0, sizeof(params));
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
{
struct dwc3_request *r = NULL;
struct usb_request *ur;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
struct dwc3_ep *ep0;
u32 transferred;
+ u32 length;
u8 epnum;
epnum = event->endpoint_number;
r = next_request(&ep0->request_list);
ur = &r->request;
- dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+ trb = dwc->ep0_trb;
+ length = trb->size & DWC3_TRB_SIZE_MASK;
if (dwc->ep0_bounced) {
-
transferred = min_t(u32, ur->length,
- ep0->endpoint.maxpacket - trb.length);
+ ep0->endpoint.maxpacket - length);
memcpy(ur->buf, dwc->ep0_bounce, transferred);
dwc->ep0_bounced = false;
} else {
- transferred = ur->length - trb.length;
+ transferred = ur->length - length;
ur->actual += transferred;
}
}
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
- struct dwc3_trb_hw *trb)
+ struct dwc3_trb *trb)
{
u32 offset = (char *) trb - (char *) dep->trb_pool;
return ret;
if (!(dep->flags & DWC3_EP_ENABLED)) {
- struct dwc3_trb_hw *trb_st_hw;
- struct dwc3_trb_hw *trb_link_hw;
- struct dwc3_trb trb_link;
+ struct dwc3_trb *trb_st_hw;
+ struct dwc3_trb *trb_link;
ret = dwc3_gadget_set_xfer_resource(dwc, dep);
if (ret)
/* Link TRB for ISOC. The HWO but is never reset */
trb_st_hw = &dep->trb_pool[0];
- trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
- trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
- trb_link.hwo = true;
+ trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
- trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
- dwc3_trb_to_hw(&trb_link, trb_link_hw);
+ trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+ trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+ trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
+ trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
}
return 0;
unsigned length, unsigned last, unsigned chain)
{
struct dwc3 *dwc = dep->dwc;
- struct dwc3_trb_hw *trb_hw;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
unsigned int cur_slot;
length, last ? " last" : "",
chain ? " chain" : "");
- trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
cur_slot = dep->free_slot;
dep->free_slot++;
usb_endpoint_xfer_isoc(dep->desc))
return;
- memset(&trb, 0, sizeof(trb));
if (!req->trb) {
dwc3_gadget_move_request_queued(req);
- req->trb = trb_hw;
- req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+ req->trb = trb;
+ req->trb_dma = dwc3_trb_dma_offset(dep, trb);
}
- if (usb_endpoint_xfer_isoc(dep->desc)) {
- trb.isp_imi = true;
- trb.csp = true;
- } else {
- trb.chn = chain;
- trb.lst = last;
- }
-
- if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
- trb.sid_sofn = req->request.stream_id;
+ trb->size = DWC3_TRB_SIZE_LENGTH(length);
+ trb->bpl = lower_32_bits(dma);
+ trb->bph = upper_32_bits(dma);
switch (usb_endpoint_type(dep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
- trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+ trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
break;
case USB_ENDPOINT_XFER_ISOC:
- trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+ trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
/* IOC every DWC3_TRB_NUM / 4 so we can refill */
if (!(cur_slot % (DWC3_TRB_NUM / 4)))
- trb.ioc = last;
+ trb->ctrl |= DWC3_TRB_CTRL_IOC;
break;
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
- trb.trbctl = DWC3_TRBCTL_NORMAL;
+ trb->ctrl = DWC3_TRBCTL_NORMAL;
break;
default:
/*
BUG();
}
- trb.length = length;
- trb.bplh = dma;
- trb.hwo = true;
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
+ trb->ctrl |= DWC3_TRB_CTRL_CSP;
+ } else {
+ if (chain)
+ trb->ctrl |= DWC3_TRB_CTRL_CHN;
+
+ if (last)
+ trb->ctrl |= DWC3_TRB_CTRL_LST;
+ }
+
+ if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+ trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
- dwc3_trb_to_hw(&trb, trb_hw);
+ trb->ctrl |= DWC3_TRB_CTRL_HWO;
}
/*
const struct dwc3_event_depevt *event, int status)
{
struct dwc3_request *req;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
unsigned int count;
unsigned int s_pkt = 0;
return 1;
}
- dwc3_trb_to_nat(req->trb, &trb);
+ trb = req->trb;
- if (trb.hwo && status != -ESHUTDOWN)
+ if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
/*
* We continue despite the error. There is not much we
* can do. If we don't clean in up we loop for ever. If
*/
dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
dep->name, req->trb);
- count = trb.length;
+ count = trb->size & DWC3_TRB_SIZE_MASK;
if (dep->direction) {
if (count) {
dwc3_gadget_giveback(dep, req, status);
if (s_pkt)
break;
- if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+ if ((event->status & DEPEVT_STATUS_LST) &&
+ (trb->ctrl & DWC3_TRB_CTRL_LST))
break;
- if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+ if ((event->status & DEPEVT_STATUS_IOC) &&
+ (trb->ctrl & DWC3_TRB_CTRL_IOC))
break;
} while (1);
- if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+ if ((event->status & DEPEVT_STATUS_IOC) &&
+ (trb->ctrl & DWC3_TRB_CTRL_IOC))
return 0;
return 1;
}