summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-12-19 00:45:04 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-12-19 00:45:03 -0800
commit04d779afaa34b9bd8d6351658d80efa618ec4fdb (patch)
tree33c83520a8458f8c9959e76cc3df2e1ba6a00d4a
parenta1c3d6511fd31e1d77a178ce5fd6fc73e24f58eb (diff)
parentd3c08a3ceda4fc47a396cd86d18400a3a929add0 (diff)
Merge "USB: dwc3-msm: Disable Update xfer for DBM on ep disable or dequeue"
-rw-r--r--drivers/usb/dwc3/core.c16
-rw-r--r--drivers/usb/dwc3/core.h7
-rw-r--r--drivers/usb/dwc3/dbm.c36
-rw-r--r--drivers/usb/dwc3/dbm.h3
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c16
-rw-r--r--drivers/usb/dwc3/gadget.c26
6 files changed, 81 insertions, 23 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 07867ead2413..85410a2214da 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -180,9 +180,9 @@ static int dwc3_core_reset(struct dwc3 *dwc)
reg &= ~DWC3_GUSB3PIPECTL_DELAYP1TRANS;
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
- dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT, 0);
- dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT, 0);
return 0;
}
@@ -908,19 +908,19 @@ void dwc3_post_host_reset_core_init(struct dwc3 *dwc)
dwc3_gadget_restart(dwc);
}
-static void (*notify_event) (struct dwc3 *, unsigned);
-void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned))
+static void (*notify_event)(struct dwc3 *, unsigned, unsigned);
+void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned, unsigned))
{
notify_event = notify;
}
EXPORT_SYMBOL(dwc3_set_notifier);
-int dwc3_notify_event(struct dwc3 *dwc, unsigned event)
+int dwc3_notify_event(struct dwc3 *dwc, unsigned event, unsigned value)
{
int ret = 0;
if (dwc->notify_event)
- dwc->notify_event(dwc, event);
+ dwc->notify_event(dwc, event, value);
else
ret = -ENODEV;
@@ -1317,7 +1317,7 @@ static int dwc3_suspend(struct device *dev)
unsigned long flags;
/* Check if platform glue driver handling PM, if not then handle here */
- if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT))
+ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT, 0))
return 0;
spin_lock_irqsave(&dwc->lock, flags);
@@ -1353,7 +1353,7 @@ static int dwc3_resume(struct device *dev)
int ret;
/* Check if platform glue driver handling PM, if not then handle here */
- if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
+ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0))
return 0;
pinctrl_pm_select_default_state(dev);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 1fb5ce9caf98..c2cdfd1a823b 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -731,6 +731,7 @@ struct dwc3_scratchpad_array {
#define DWC3_CONTROLLER_NOTIFY_OTG_EVENT 6
#define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT 7
#define DWC3_CONTROLLER_RESTART_USB_SESSION 8
+#define DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER 9
#define MAX_INTR_STATS 10
/**
@@ -952,7 +953,7 @@ struct dwc3 {
const char *hsphy_interface;
- void (*notify_event) (struct dwc3 *, unsigned);
+ void (*notify_event)(struct dwc3 *, unsigned, unsigned);
struct work_struct wakeup_work;
unsigned delayed_status:1;
@@ -1252,7 +1253,7 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc);
void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
extern void dwc3_set_notifier(
- void (*notify) (struct dwc3 *dwc3, unsigned event));
-extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned event);
+ void (*notify)(struct dwc3 *dwc3, unsigned event, unsigned value));
+extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned event, unsigned value);
#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/dbm.c b/drivers/usb/dwc3/dbm.c
index 34a1b6259d1b..0fbb1fb39f5c 100644
--- a/drivers/usb/dwc3/dbm.c
+++ b/drivers/usb/dwc3/dbm.c
@@ -37,6 +37,7 @@ enum dbm_reg {
DBM_HW_TRB2_EP,
DBM_HW_TRB3_EP,
DBM_PIPE_CFG,
+ DBM_DISABLE_UPDXFER,
DBM_SOFT_RESET,
DBM_GEN_CFG,
DBM_GEVNTADR_LSB,
@@ -103,6 +104,7 @@ static const struct dbm_reg_data dbm_1_5_regtable[] = {
[DBM_HW_TRB2_EP] = { 0x0240, 0x4 },
[DBM_HW_TRB3_EP] = { 0x0250, 0x4 },
[DBM_PIPE_CFG] = { 0x0274, 0x0 },
+ [DBM_DISABLE_UPDXFER] = { 0x0298, 0x0 },
[DBM_SOFT_RESET] = { 0x020C, 0x0 },
[DBM_GEN_CFG] = { 0x0210, 0x0 },
[DBM_GEVNTADR_LSB] = { 0x0260, 0x0 },
@@ -291,6 +293,7 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer,
{
int dbm_ep;
u32 ep_cfg;
+ u32 data;
if (!dbm) {
pr_err("%s: dbm pointer is NULL!\n", __func__);
@@ -334,6 +337,10 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer,
msm_dbm_write_ep_reg_field(dbm, DBM_EP_CFG, dbm_ep, DBM_EN_EP, 1);
+ data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER);
+ data &= ~(0x1 << dbm_ep);
+ msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data);
+
return dbm_ep;
}
@@ -433,6 +440,35 @@ int dbm_event_buffer_config(struct dbm *dbm, u32 addr_lo, u32 addr_hi, int size)
return 0;
}
+/**
+ * Disable update xfer before queueing stop xfer command to USB3 core.
+ *
+ * @usb_ep - USB physical EP number.
+ *
+ */
+int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep)
+{
+ u32 data;
+ u8 dbm_ep;
+
+ if (!dbm) {
+ pr_err("%s: dbm pointer is NULL!\n", __func__);
+ return -EPERM;
+ }
+
+ dbm_ep = find_matching_dbm_ep(dbm, usb_ep);
+
+ if (dbm_ep < 0) {
+ pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep);
+ return -ENODEV;
+ }
+
+ data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER);
+ data |= (0x1 << dbm_ep);
+ msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data);
+
+ return 0;
+}
int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, phys_addr_t addr,
u32 size, u8 dst_pipe_idx)
diff --git a/drivers/usb/dwc3/dbm.h b/drivers/usb/dwc3/dbm.h
index 260afc241015..bf20d7cbd454 100644
--- a/drivers/usb/dwc3/dbm.h
+++ b/drivers/usb/dwc3/dbm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -63,6 +63,7 @@ int dbm_ep_unconfig(struct dbm *dbm, u8 usb_ep);
int dbm_get_num_of_eps_configured(struct dbm *dbm);
int dbm_event_buffer_config(struct dbm *dbm, u32 addr_lo, u32 addr_hi,
int size);
+int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep);
int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, phys_addr_t addr,
u32 size, u8 dst_pipe_idx);
void dbm_set_speed(struct dbm *dbm, bool speed);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 15c994294c63..8a1b0d870e7a 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -367,6 +367,16 @@ static inline bool dwc3_msm_is_superspeed(struct dwc3_msm *mdwc)
return dwc3_msm_is_dev_superspeed(mdwc);
}
+int dwc3_msm_dbm_disable_updxfer(struct dwc3 *dwc, u8 usb_ep)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+ dev_dbg(mdwc->dev, "%s\n", __func__);
+ dwc3_dbm_disable_update_xfer(mdwc->dbm, usb_ep);
+
+ return 0;
+}
+
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
/**
* Configure the DBM with the BAM's data fifo.
@@ -1625,7 +1635,8 @@ static void dwc3_msm_vbus_draw_work(struct work_struct *w)
dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw);
}
-static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event,
+ unsigned value)
{
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
u32 reg;
@@ -1717,6 +1728,9 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESTART_USB_SESSION received\n");
schedule_work(&mdwc->restart_usb_work);
break;
+ case DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER:
+ dwc3_msm_dbm_disable_updxfer(dwc, value);
+ break;
default:
dev_dbg(mdwc->dev, "unknown dwc3 event\n");
break;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index b6442fad550a..251ae0a7a5ee 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -384,7 +384,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
if (!(cmd & DWC3_DEPCMD_ENDTRANSFER)) {
dwc->ep_cmd_timeout_cnt++;
dwc3_notify_event(dwc,
- DWC3_CONTROLLER_RESTART_USB_SESSION);
+ DWC3_CONTROLLER_RESTART_USB_SESSION, 0);
}
return -ETIMEDOUT;
}
@@ -1872,7 +1872,7 @@ static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned mA)
dwc->vbus_draw = mA;
dev_dbg(dwc->dev, "Notify controller from %s. mA = %d\n", __func__, mA);
- dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, 0);
return 0;
}
@@ -1907,7 +1907,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
*/
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = false;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
ret = dwc3_gadget_run_stop(dwc, is_on, false);
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -2143,7 +2143,7 @@ static int dwc3_gadget_restart_usb_session(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
- return dwc3_notify_event(dwc, DWC3_CONTROLLER_RESTART_USB_SESSION);
+ return dwc3_notify_event(dwc, DWC3_CONTROLLER_RESTART_USB_SESSION, 0);
}
static const struct usb_gadget_ops dwc3_gadget_ops = {
@@ -2659,6 +2659,10 @@ void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
if (!dep->resource_index)
return;
+ if (dep->endpoint.endless)
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER,
+ dep->number);
+
/*
* NOTICE: We are violating what the Databook says about the
* EndTransfer command. Ideally we would _always_ wait for the
@@ -2743,7 +2747,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = false;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_INITU1ENA;
@@ -2799,7 +2803,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = false;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
dwc3_usb3_phy_suspend(dwc, false);
usb_gadget_vbus_draw(&dwc->gadget, 100);
@@ -2960,7 +2964,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
return;
}
- dwc3_notify_event(dwc, DWC3_CONTROLLER_CONNDONE_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_CONNDONE_EVENT, 0);
/*
* Configure PHY via GUSB3PIPECTLn if required.
@@ -2996,7 +3000,8 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, bool remote_wakeup)
*/
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = false;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc,
+ DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
/*
* set state to U0 as function level resume is trying to queue
@@ -3163,7 +3168,7 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
dwc->b_suspend = true;
- dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0);
}
dwc->link_state = next;
@@ -3334,7 +3339,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
evt->lpos = (evt->lpos + left) %
DWC3_EVENT_BUFFERS_SIZE;
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), left);
- if (dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT))
+ if (dwc3_notify_event(dwc,
+ DWC3_CONTROLLER_ERROR_EVENT, 0))
dwc->err_evt_seen = 0;
break;
}