From d3c08a3ceda4fc47a396cd86d18400a3a929add0 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Fri, 29 Jan 2016 21:14:24 +0530 Subject: [PATCH] USB: dwc3-msm: Disable Update xfer for DBM on ep disable or dequeue Enable update xfer for DBM while configuring dbm endpoint and also clear update xfer before queueing end xfer command as part of endpoint disable as hardware programming guide. CRs-Fixed: 965207 Change-Id: Ib5ec650884ad06394280416ccf877c1ccce1eaaf Signed-off-by: Vijayavardhan Vennapusa Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/dwc3/core.c | 16 ++++++++-------- drivers/usb/dwc3/core.h | 7 ++++--- drivers/usb/dwc3/dbm.c | 38 ++++++++++++++++++++++++++++++++++++- drivers/usb/dwc3/dbm.h | 3 ++- drivers/usb/dwc3/dwc3-msm.c | 16 +++++++++++++++- drivers/usb/dwc3/gadget.c | 26 +++++++++++++++---------- 6 files changed, 82 insertions(+), 24 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 285cd5a47d82..fc91bfb8b8d5 100644 --- a/drivers/usb/dwc3/dbm.c +++ b/drivers/usb/dwc3/dbm.c @@ -1,5 +1,5 @@ /* - * 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 @@ -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__); @@ -337,6 +340,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; } @@ -449,6 +456,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 bb6afb6a7d6d..b2085af28374 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -365,6 +365,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. @@ -1616,7 +1626,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; @@ -1708,6 +1719,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 2450cc52fa24..2858388fe8d1 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -383,7 +383,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; } @@ -1871,7 +1871,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; } @@ -1906,7 +1906,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); @@ -2142,7 +2142,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 = { @@ -2658,6 +2658,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 @@ -2742,7 +2746,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; @@ -2798,7 +2802,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); @@ -2959,7 +2963,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. @@ -2995,7 +2999,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 @@ -3162,7 +3167,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; @@ -3333,7 +3338,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; }