Merge "USB: dwc3-msm: Disable Update xfer for DBM on ep disable or dequeue"

This commit is contained in:
Linux Build Service Account 2016-12-19 00:45:04 -08:00 committed by Gerrit - the friendly Code Review server
commit 04d779afaa
6 changed files with 81 additions and 23 deletions

View file

@ -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);

View file

@ -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 */

View file

@ -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)

View file

@ -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);

View file

@ -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;

View file

@ -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;
}