+// SPDX-License-Identifier: GPL-2.0
/**
* gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
*
* to uboot.
*
* commit 8e74475b0e : usb: dwc3: gadget: use udc-core's reset notifier
- *
- * SPDX-License-Identifier: GPL-2.0
*/
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
+#include <common.h>
+#include <malloc.h>
+#include <asm/dma-mapping.h>
+#include <usb/lin_gadget_compat.h>
+#include <linux/bug.h>
#include <linux/list.h>
-#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include "debug.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
+#include "linux-compat.h"
+
/**
* dwc3_gadget_set_test_mode - Enables USB2 Test Modes
* @dwc: pointer to our context structure
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
{
int last_fifo_depth = 0;
- int ram1_depth;
int fifo_size;
int mdwidth;
int num;
if (!dwc->needs_fifo_resize)
return 0;
- ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
/* MDWIDTH is represented in bits, we need it in bytes */
int status)
{
struct dwc3 *dwc = dep->dwc;
- int i;
if (req->queued) {
- i = 0;
- do {
+ dep->busy_slot++;
+ /*
+ * Skip LINK TRB. We can't use req->trb and check for
+ * DWC3_TRBCTL_LINK_TRB because it points the TRB we
+ * just completed (not the LINK TRB).
+ */
+ if (((dep->busy_slot & DWC3_TRB_MASK) ==
+ DWC3_TRB_NUM- 1) &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
dep->busy_slot++;
- /*
- * Skip LINK TRB. We can't use req->trb and check for
- * DWC3_TRBCTL_LINK_TRB because it points the TRB we
- * just completed (not the LINK TRB).
- */
- if (((dep->busy_slot & DWC3_TRB_MASK) ==
- DWC3_TRB_NUM- 1) &&
- usb_endpoint_xfer_isoc(dep->endpoint.desc))
- dep->busy_slot++;
- } while(++i < req->request.num_mapped_sgs);
req->queued = false;
}
+
list_del(&req->list);
req->trb = NULL;
+ dwc3_flush_cache((uintptr_t)req->request.dma, req->request.length);
if (req->request.status == -EINPROGRESS)
req->request.status = status;
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
req, dep->name, req->request.actual,
req->request.length, status);
- trace_dwc3_gadget_giveback(req);
spin_unlock(&dwc->lock);
usb_gadget_giveback_request(&dep->endpoint, &req->request);
u32 timeout = 500;
u32 reg;
- trace_dwc3_gadget_generic_cmd(cmd, param);
-
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
- struct dwc3_ep *dep = dwc->eps[ep];
u32 timeout = 500;
u32 reg;
- trace_dwc3_gadget_ep_cmd(dep, cmd, params);
-
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
{
- struct dwc3 *dwc = dep->dwc;
-
if (dep->trb_pool)
return 0;
if (dep->number == 0 || dep->number == 1)
return 0;
- dep->trb_pool = dma_alloc_coherent(dwc->dev,
- sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
- &dep->trb_pool_dma, GFP_KERNEL);
+ dep->trb_pool = dma_alloc_coherent(sizeof(struct dwc3_trb) *
+ DWC3_TRB_NUM,
+ (unsigned long *)&dep->trb_pool_dma);
if (!dep->trb_pool) {
dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
dep->name);
static void dwc3_free_trb_pool(struct dwc3_ep *dep)
{
- struct dwc3 *dwc = dep->dwc;
-
- dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
- dep->trb_pool, dep->trb_pool_dma);
+ dma_free_coherent(dep->trb_pool);
dep->trb_pool = NULL;
dep->trb_pool_dma = 0;
const struct usb_endpoint_descriptor *desc)
{
struct dwc3_ep *dep;
- struct dwc3 *dwc;
unsigned long flags;
int ret;
}
dep = to_dwc3_ep(ep);
- dwc = dep->dwc;
if (dep->flags & DWC3_EP_ENABLED) {
- dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
+ WARN(true, "%s is already enabled\n",
dep->name);
return 0;
}
static int dwc3_gadget_ep_disable(struct usb_ep *ep)
{
struct dwc3_ep *dep;
- struct dwc3 *dwc;
unsigned long flags;
int ret;
}
dep = to_dwc3_ep(ep);
- dwc = dep->dwc;
if (!(dep->flags & DWC3_EP_ENABLED)) {
- dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
+ WARN(true, "%s is already disabled\n",
dep->name);
return 0;
}
req->epnum = dep->number;
req->dep = dep;
- trace_dwc3_alloc_request(req);
-
return &req->request;
}
{
struct dwc3_request *req = to_dwc3_request(request);
- trace_dwc3_free_request(req);
kfree(req);
}
struct dwc3_request *req, dma_addr_t dma,
unsigned length, unsigned last, unsigned chain, unsigned node)
{
- struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb;
dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
trb->ctrl |= DWC3_TRB_CTRL_HWO;
- trace_dwc3_prepare_trb(dep, trb);
+ dwc3_flush_cache((uintptr_t)dma, length);
+ dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
}
/*
struct dwc3_request *req, *n;
u32 trbs_left;
u32 max;
- unsigned int last_one = 0;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
list_for_each_entry_safe(req, n, &dep->request_list, list) {
unsigned length;
dma_addr_t dma;
- last_one = false;
-
- if (req->request.num_mapped_sgs > 0) {
- struct usb_request *request = &req->request;
- struct scatterlist *sg = request->sg;
- struct scatterlist *s;
- int i;
-
- for_each_sg(sg, s, request->num_mapped_sgs, i) {
- unsigned chain = true;
-
- length = sg_dma_len(s);
- dma = sg_dma_address(s);
-
- if (i == (request->num_mapped_sgs - 1) ||
- sg_is_last(s)) {
- if (list_is_last(&req->list,
- &dep->request_list))
- last_one = true;
- chain = false;
- }
-
- trbs_left--;
- if (!trbs_left)
- last_one = true;
-
- if (last_one)
- chain = false;
-
- dwc3_prepare_one_trb(dep, req, dma, length,
- last_one, chain, i);
-
- if (last_one)
- break;
- }
- } else {
- dma = req->request.dma;
- length = req->request.length;
- trbs_left--;
- if (!trbs_left)
- last_one = 1;
+ dma = req->request.dma;
+ length = req->request.length;
- /* Is this the last request? */
- if (list_is_last(&req->list, &dep->request_list))
- last_one = 1;
+ dwc3_prepare_one_trb(dep, req, dma, length,
+ true, false, 0);
- dwc3_prepare_one_trb(dep, req, dma, length,
- last_one, false, 0);
-
- if (last_one)
- break;
- }
+ break;
}
}
req->direction = dep->direction;
req->epnum = dep->number;
+ /*
+ * DWC3 hangs on OUT requests smaller than maxpacket size,
+ * so HACK the request length
+ */
+ if (dep->direction == 0 &&
+ req->request.length < dep->endpoint.maxpacket)
+ req->request.length = dep->endpoint.maxpacket;
+
/*
* We only add to our list of requests now and
* start consuming the list once we get XferNotReady
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
if (ret && ret != -EBUSY) {
- struct dwc3 *dwc = dep->dwc;
-
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
}
{
struct dwc3_request *req = to_dwc3_request(request);
struct dwc3_ep *dep = to_dwc3_ep(ep);
- struct dwc3 *dwc = dep->dwc;
unsigned long flags;
goto out;
}
- if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
- request, req->dep->name)) {
+ if (req->dep != dep) {
+ WARN(true, "request %p belongs to '%s'\n",
+ request, req->dep->name);
ret = -EINVAL;
goto out;
}
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
request, ep->name, request->length);
- trace_dwc3_ep_queue(req);
ret = __dwc3_gadget_ep_queue(dep, req);
unsigned long flags;
int ret = 0;
- trace_dwc3_ep_dequeue(req);
-
spin_lock_irqsave(&dwc->lock, flags);
list_for_each_entry(r, &dep->request_list, list) {
static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
- struct dwc3 *dwc = dep->dwc;
unsigned long flags;
static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
- struct dwc3 *dwc = dep->dwc;
unsigned long flags;
int ret;
}
/* poll until Link State changes to ON */
- timeout = jiffies + msecs_to_jiffies(100);
+ timeout = 1000;
- while (!time_after(jiffies, timeout)) {
+ while (timeout--) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
/* in HS, means ON */
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
}
-static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
-static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
-
static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
struct dwc3_ep *dep;
unsigned long flags;
int ret = 0;
- int irq;
u32 reg;
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
- ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
- IRQF_SHARED, "dwc3", dwc);
- if (ret) {
- dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
- irq, ret);
- goto err0;
- }
-
spin_lock_irqsave(&dwc->lock, flags);
if (dwc->gadget_driver) {
dev_err(dwc->dev, "%s is already bound to %s\n",
dwc->gadget.name,
- dwc->gadget_driver->driver.name);
+ dwc->gadget_driver->function);
ret = -EBUSY;
goto err1;
}
err1:
spin_unlock_irqrestore(&dwc->lock, flags);
- free_irq(irq, dwc);
-
-err0:
return ret;
}
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
- int irq;
spin_lock_irqsave(&dwc->lock, flags);
spin_unlock_irqrestore(&dwc->lock, flags);
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
- free_irq(irq, dwc);
-
return 0;
}
} else {
int ret;
- usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);
+ usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
dep->endpoint.max_streams = 15;
dep->endpoint.ops = &dwc3_gadget_ep_ops;
list_add_tail(&dep->endpoint.ep_list,
unsigned int s_pkt = 0;
unsigned int trb_status;
- trace_dwc3_complete_trb(dep, trb);
-
if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
/*
* We continue despite the error. There is not much we
struct dwc3_request *req;
struct dwc3_trb *trb;
unsigned int slot;
- unsigned int i;
- int ret;
- do {
- req = next_request(&dep->req_queued);
- if (!req) {
- WARN_ON_ONCE(1);
- return 1;
- }
- i = 0;
- do {
- slot = req->start_slot + i;
- if ((slot == DWC3_TRB_NUM - 1) &&
- usb_endpoint_xfer_isoc(dep->endpoint.desc))
- slot++;
- slot %= DWC3_TRB_NUM;
- trb = &dep->trb_pool[slot];
-
- ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
- event, status);
- if (ret)
- break;
- }while (++i < req->request.num_mapped_sgs);
+ req = next_request(&dep->req_queued);
+ if (!req) {
+ WARN_ON_ONCE(1);
+ return 1;
+ }
- dwc3_gadget_giveback(dep, req, status);
+ slot = req->start_slot;
+ if ((slot == DWC3_TRB_NUM - 1) &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
+ slot++;
+ slot %= DWC3_TRB_NUM;
+ trb = &dep->trb_pool[slot];
- if (ret)
- break;
- } while (1);
+ dwc3_flush_cache((uintptr_t)trb, sizeof(*trb));
+ __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status);
+ dwc3_gadget_giveback(dep, req, status);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
* BESL value in the LPM token is less than or equal to LPM
* NYET threshold.
*/
- WARN_ONCE(dwc->revision < DWC3_REVISION_240A
- && dwc->has_lpm_erratum,
- "LPM Erratum not available on dwc3 revisisions < 2.40a\n");
+ if (dwc->revision < DWC3_REVISION_240A && dwc->has_lpm_erratum)
+ WARN(true, "LPM Erratum not available on dwc3 revisisions < 2.40a\n");
if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A)
reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold);
static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
- unsigned int is_ss = evtinfo & BIT(4);
+ unsigned int is_ss = evtinfo & (1UL << 4);
/**
* WORKAROUND: DWC3 revison 2.20a with hibernation support
dwc3_gadget_wakeup_interrupt(dwc);
break;
case DWC3_DEVICE_EVENT_HIBER_REQ:
- if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
- "unexpected hibernation event\n"))
+ if (!dwc->has_hibernation) {
+ WARN(1 ,"unexpected hibernation event\n");
break;
-
+ }
dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
static void dwc3_process_event_entry(struct dwc3 *dwc,
const union dwc3_event *event)
{
- trace_dwc3_event(event->raw);
-
/* Endpoint IRQ, handle it and return early */
if (event->type.is_devspec == 0) {
/* depevt */
{
int ret;
- dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
- &dwc->ctrl_req_addr, GFP_KERNEL);
+ dwc->ctrl_req = dma_alloc_coherent(sizeof(*dwc->ctrl_req),
+ (unsigned long *)&dwc->ctrl_req_addr);
if (!dwc->ctrl_req) {
dev_err(dwc->dev, "failed to allocate ctrl request\n");
ret = -ENOMEM;
goto err0;
}
- dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
- &dwc->ep0_trb_addr, GFP_KERNEL);
+ dwc->ep0_trb = dma_alloc_coherent(sizeof(*dwc->ep0_trb) * 2,
+ (unsigned long *)&dwc->ep0_trb_addr);
if (!dwc->ep0_trb) {
dev_err(dwc->dev, "failed to allocate ep0 trb\n");
ret = -ENOMEM;
goto err1;
}
- dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
+ dwc->setup_buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
+ DWC3_EP0_BOUNCE_SIZE);
if (!dwc->setup_buf) {
ret = -ENOMEM;
goto err2;
}
- dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
- DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
- GFP_KERNEL);
+ dwc->ep0_bounce = dma_alloc_coherent(DWC3_EP0_BOUNCE_SIZE,
+ (unsigned long *)&dwc->ep0_bounce_addr);
if (!dwc->ep0_bounce) {
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
ret = -ENOMEM;
dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
- dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
/*
err4:
dwc3_gadget_free_endpoints(dwc);
- dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
- dwc->ep0_bounce, dwc->ep0_bounce_addr);
+ dma_free_coherent(dwc->ep0_bounce);
err3:
kfree(dwc->setup_buf);
err2:
- dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
- dwc->ep0_trb, dwc->ep0_trb_addr);
+ dma_free_coherent(dwc->ep0_trb);
err1:
- dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
- dwc->ctrl_req, dwc->ctrl_req_addr);
+ dma_free_coherent(dwc->ctrl_req);
err0:
return ret;
dwc3_gadget_free_endpoints(dwc);
- dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
- dwc->ep0_bounce, dwc->ep0_bounce_addr);
+ dma_free_coherent(dwc->ep0_bounce);
kfree(dwc->setup_buf);
- dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
- dwc->ep0_trb, dwc->ep0_trb_addr);
+ dma_free_coherent(dwc->ep0_trb);
- dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
- dwc->ctrl_req, dwc->ctrl_req_addr);
+ dma_free_coherent(dwc->ctrl_req);
}
-int dwc3_gadget_suspend(struct dwc3 *dwc)
+/**
+ * dwc3_gadget_uboot_handle_interrupt - handle dwc3 gadget interrupt
+ * @dwc: struct dwce *
+ *
+ * Handles ep0 and gadget interrupt
+ *
+ * Should be called from dwc3 core.
+ */
+void dwc3_gadget_uboot_handle_interrupt(struct dwc3 *dwc)
{
- if (dwc->pullups_connected) {
- dwc3_gadget_disable_irq(dwc);
- dwc3_gadget_run_stop(dwc, true, true);
- }
-
- __dwc3_gadget_ep_disable(dwc->eps[0]);
- __dwc3_gadget_ep_disable(dwc->eps[1]);
+ int ret = dwc3_interrupt(0, dwc);
- dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
-
- return 0;
-}
+ if (ret == IRQ_WAKE_THREAD) {
+ int i;
+ struct dwc3_event_buffer *evt;
-int dwc3_gadget_resume(struct dwc3 *dwc)
-{
- struct dwc3_ep *dep;
- int ret;
-
- /* Start with SuperSpeed Default */
- dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+ dwc3_thread_interrupt(0, dwc);
- dep = dwc->eps[0];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
- false);
- if (ret)
- goto err0;
-
- dep = dwc->eps[1];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
- false);
- if (ret)
- goto err1;
-
- /* begin to receive SETUP packets */
- dwc->ep0state = EP0_SETUP_PHASE;
- dwc3_ep0_out_start(dwc);
-
- dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
-
- if (dwc->pullups_connected) {
- dwc3_gadget_enable_irq(dwc);
- dwc3_gadget_run_stop(dwc, true, false);
+ /* Clean + Invalidate the buffers after touching them */
+ for (i = 0; i < dwc->num_event_buffers; i++) {
+ evt = dwc->ev_buffs[i];
+ dwc3_flush_cache((uintptr_t)evt->buf, evt->length);
+ }
}
-
- return 0;
-
-err1:
- __dwc3_gadget_ep_disable(dwc->eps[0]);
-
-err0:
- return ret;
}