diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-12-19 00:45:04 -0800 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-12-19 00:45:03 -0800 |
| commit | 04d779afaa34b9bd8d6351658d80efa618ec4fdb (patch) | |
| tree | 33c83520a8458f8c9959e76cc3df2e1ba6a00d4a | |
| parent | a1c3d6511fd31e1d77a178ce5fd6fc73e24f58eb (diff) | |
| parent | d3c08a3ceda4fc47a396cd86d18400a3a929add0 (diff) | |
Merge "USB: dwc3-msm: Disable Update xfer for DBM on ep disable or dequeue"
| -rw-r--r-- | drivers/usb/dwc3/core.c | 16 | ||||
| -rw-r--r-- | drivers/usb/dwc3/core.h | 7 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dbm.c | 36 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dbm.h | 3 | ||||
| -rw-r--r-- | drivers/usb/dwc3/dwc3-msm.c | 16 | ||||
| -rw-r--r-- | drivers/usb/dwc3/gadget.c | 26 |
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; } |
