Merge conflicts
This commit is contained in:
parent
a0d8cb2cf5
commit
9c7e1469fe
544
sys/external/bsd/dwc2/dist/dwc2_core.c
vendored
544
sys/external/bsd/dwc2/dist/dwc2_core.c
vendored
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dwc2_core.c,v 1.7 2015/05/01 06:58:40 hikaru Exp $ */
|
||||
/* $NetBSD: dwc2_core.c,v 1.8 2015/08/30 12:59:59 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* core.c - DesignWare HS OTG Controller common routines
|
||||
@ -43,7 +43,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_core.c,v 1.7 2015/05/01 06:58:40 hikaru Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_core.c,v 1.8 2015/08/30 12:59:59 skrll Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/bus.h>
|
||||
@ -67,6 +67,364 @@ __KERNEL_RCSID(0, "$NetBSD: dwc2_core.c,v 1.7 2015/05/01 06:58:40 hikaru Exp $")
|
||||
#include "dwc2_core.h"
|
||||
#include "dwc2_hcd.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
/**
|
||||
* dwc2_backup_host_registers() - Backup controller host registers.
|
||||
* When suspending usb bus, registers needs to be backuped
|
||||
* if controller power is disabled once suspended.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
static int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_hregs_backup *hr;
|
||||
int i;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s\n", __func__);
|
||||
|
||||
/* Backup Host regs */
|
||||
hr = &hsotg->hr_backup;
|
||||
hr->hcfg = DWC2_READ_4(hsotg, HCFG);
|
||||
hr->haintmsk = DWC2_READ_4(hsotg, HAINTMSK);
|
||||
for (i = 0; i < hsotg->core_params->host_channels; ++i)
|
||||
hr->hcintmsk[i] = DWC2_READ_4(hsotg, HCINTMSK(i));
|
||||
|
||||
hr->hprt0 = DWC2_READ_4(hsotg, HPRT0);
|
||||
hr->hfir = DWC2_READ_4(hsotg, HFIR);
|
||||
hr->valid = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_restore_host_registers() - Restore controller host registers.
|
||||
* When resuming usb bus, device registers needs to be restored
|
||||
* if controller power were disabled.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
static int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_hregs_backup *hr;
|
||||
int i;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s\n", __func__);
|
||||
|
||||
/* Restore host regs */
|
||||
hr = &hsotg->hr_backup;
|
||||
if (!hr->valid) {
|
||||
dev_err(hsotg->dev, "%s: no host registers to restore\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
hr->valid = false;
|
||||
|
||||
DWC2_WRITE_4(hsotg, HCFG, hr->hcfg);
|
||||
DWC2_WRITE_4(hsotg, HAINTMSK, hr->haintmsk);
|
||||
|
||||
for (i = 0; i < hsotg->core_params->host_channels; ++i)
|
||||
DWC2_WRITE_4(hsotg, HCINTMSK(i), hr->hcintmsk[i]);
|
||||
|
||||
DWC2_WRITE_4(hsotg, HPRT0, hr->hprt0);
|
||||
DWC2_WRITE_4(hsotg, HFIR, hr->hfir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
|
||||
static inline int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
|
||||
IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
/**
|
||||
* dwc2_backup_device_registers() - Backup controller device registers.
|
||||
* When suspending usb bus, registers needs to be backuped
|
||||
* if controller power is disabled once suspended.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
static int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_dregs_backup *dr;
|
||||
int i;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s\n", __func__);
|
||||
|
||||
/* Backup dev regs */
|
||||
dr = &hsotg->dr_backup;
|
||||
|
||||
dr->dcfg = DWC2_READ_4(hsotg, DCFG);
|
||||
dr->dctl = DWC2_READ_4(hsotg, DCTL);
|
||||
dr->daintmsk = DWC2_READ_4(hsotg, DAINTMSK);
|
||||
dr->diepmsk = DWC2_READ_4(hsotg, DIEPMSK);
|
||||
dr->doepmsk = DWC2_READ_4(hsotg, DOEPMSK);
|
||||
|
||||
for (i = 0; i < hsotg->num_of_eps; i++) {
|
||||
/* Backup IN EPs */
|
||||
dr->diepctl[i] = DWC2_READ_4(hsotg, DIEPCTL(i));
|
||||
|
||||
/* Ensure DATA PID is correctly configured */
|
||||
if (dr->diepctl[i] & DXEPCTL_DPID)
|
||||
dr->diepctl[i] |= DXEPCTL_SETD1PID;
|
||||
else
|
||||
dr->diepctl[i] |= DXEPCTL_SETD0PID;
|
||||
|
||||
dr->dieptsiz[i] = DWC2_READ_4(hsotg, DIEPTSIZ(i));
|
||||
dr->diepdma[i] = DWC2_READ_4(hsotg, DIEPDMA(i));
|
||||
|
||||
/* Backup OUT EPs */
|
||||
dr->doepctl[i] = DWC2_READ_4(hsotg, DOEPCTL(i));
|
||||
|
||||
/* Ensure DATA PID is correctly configured */
|
||||
if (dr->doepctl[i] & DXEPCTL_DPID)
|
||||
dr->doepctl[i] |= DXEPCTL_SETD1PID;
|
||||
else
|
||||
dr->doepctl[i] |= DXEPCTL_SETD0PID;
|
||||
|
||||
dr->doeptsiz[i] = DWC2_READ_4(hsotg, DOEPTSIZ(i));
|
||||
dr->doepdma[i] = DWC2_READ_4(hsotg, DOEPDMA(i));
|
||||
}
|
||||
dr->valid = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_restore_device_registers() - Restore controller device registers.
|
||||
* When resuming usb bus, device registers needs to be restored
|
||||
* if controller power were disabled.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
static int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_dregs_backup *dr;
|
||||
u32 dctl;
|
||||
int i;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s\n", __func__);
|
||||
|
||||
/* Restore dev regs */
|
||||
dr = &hsotg->dr_backup;
|
||||
if (!dr->valid) {
|
||||
dev_err(hsotg->dev, "%s: no device registers to restore\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
dr->valid = false;
|
||||
|
||||
DWC2_WRITE_4(hsotg, DCFG, dr->dcfg);
|
||||
DWC2_WRITE_4(hsotg, DCTL, dr->dctl);
|
||||
DWC2_WRITE_4(hsotg, DAINTMSK, dr->daintmsk);
|
||||
DWC2_WRITE_4(hsotg, DIEPMSK, dr->diepmsk);
|
||||
DWC2_WRITE_4(hsotg, DOEPMSK, dr->doepmsk);
|
||||
|
||||
for (i = 0; i < hsotg->num_of_eps; i++) {
|
||||
/* Restore IN EPs */
|
||||
DWC2_WRITE_4(hsotg, DIEPCTL(i), dr->diepctl[i]);
|
||||
DWC2_WRITE_4(hsotg, DIEPTSIZ(i), dr->dieptsiz[i]);
|
||||
DWC2_WRITE_4(hsotg, DIEPDMA(i), dr->diepdma[i]);
|
||||
|
||||
/* Restore OUT EPs */
|
||||
DWC2_WRITE_4(hsotg, DOEPCTL(i), dr->doepctl[i]);
|
||||
DWC2_WRITE_4(hsotg, DOEPTSIZ(i), dr->doeptsiz[i]);
|
||||
DWC2_WRITE_4(hsotg, DOEPDMA(i), dr->doepdma[i]);
|
||||
}
|
||||
|
||||
/* Set the Power-On Programming done bit */
|
||||
dctl = DWC2_READ_4(hsotg, DCTL);
|
||||
dctl |= DCTL_PWRONPRGDONE;
|
||||
DWC2_WRITE_4(hsotg, DCTL, dctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
|
||||
static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dwc2_backup_global_registers() - Backup global controller registers.
|
||||
* When suspending usb bus, registers needs to be backuped
|
||||
* if controller power is disabled once suspended.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
static int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_gregs_backup *gr;
|
||||
int i;
|
||||
|
||||
/* Backup global regs */
|
||||
gr = &hsotg->gr_backup;
|
||||
|
||||
gr->gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
|
||||
gr->gintmsk = DWC2_READ_4(hsotg, GINTMSK);
|
||||
gr->gahbcfg = DWC2_READ_4(hsotg, GAHBCFG);
|
||||
gr->gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
|
||||
gr->grxfsiz = DWC2_READ_4(hsotg, GRXFSIZ);
|
||||
gr->gnptxfsiz = DWC2_READ_4(hsotg, GNPTXFSIZ);
|
||||
gr->hptxfsiz = DWC2_READ_4(hsotg, HPTXFSIZ);
|
||||
gr->gdfifocfg = DWC2_READ_4(hsotg, GDFIFOCFG);
|
||||
for (i = 0; i < MAX_EPS_CHANNELS; i++)
|
||||
gr->dtxfsiz[i] = DWC2_READ_4(hsotg, DPTXFSIZN(i));
|
||||
|
||||
gr->valid = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_restore_global_registers() - Restore controller global registers.
|
||||
* When resuming usb bus, device registers needs to be restored
|
||||
* if controller power were disabled.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_gregs_backup *gr;
|
||||
int i;
|
||||
|
||||
dev_dbg(hsotg->dev, "%s\n", __func__);
|
||||
|
||||
/* Restore global regs */
|
||||
gr = &hsotg->gr_backup;
|
||||
if (!gr->valid) {
|
||||
dev_err(hsotg->dev, "%s: no global registers to restore\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
gr->valid = false;
|
||||
|
||||
DWC2_WRITE_4(hsotg, GINTSTS, 0xffffffff);
|
||||
DWC2_WRITE_4(hsotg, GOTGCTL, gr->gotgctl);
|
||||
DWC2_WRITE_4(hsotg, GINTMSK, gr->gintmsk);
|
||||
DWC2_WRITE_4(hsotg, GUSBCFG, gr->gusbcfg);
|
||||
DWC2_WRITE_4(hsotg, GAHBCFG, gr->gahbcfg);
|
||||
DWC2_WRITE_4(hsotg, GRXFSIZ, gr->grxfsiz);
|
||||
DWC2_WRITE_4(hsotg, GNPTXFSIZ, gr->gnptxfsiz);
|
||||
DWC2_WRITE_4(hsotg, HPTXFSIZ, gr->hptxfsiz);
|
||||
DWC2_WRITE_4(hsotg, GDFIFOCFG, gr->gdfifocfg);
|
||||
for (i = 0; i < MAX_EPS_CHANNELS; i++)
|
||||
DWC2_WRITE_4(hsotg, DPTXFSIZN(i), gr->dtxfsiz[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_exit_hibernation() - Exit controller from Partial Power Down.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
* @restore: Controller registers need to be restored
|
||||
*/
|
||||
int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore)
|
||||
{
|
||||
u32 pcgcctl;
|
||||
int ret = 0;
|
||||
|
||||
if (!hsotg->core_params->hibernation)
|
||||
return -ENOTSUPP;
|
||||
|
||||
pcgcctl = DWC2_READ_4(hsotg, PCGCTL);
|
||||
pcgcctl &= ~PCGCTL_STOPPCLK;
|
||||
DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl);
|
||||
|
||||
pcgcctl = DWC2_READ_4(hsotg, PCGCTL);
|
||||
pcgcctl &= ~PCGCTL_PWRCLMP;
|
||||
DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl);
|
||||
|
||||
pcgcctl = DWC2_READ_4(hsotg, PCGCTL);
|
||||
pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
|
||||
DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl);
|
||||
|
||||
udelay(100);
|
||||
if (restore) {
|
||||
ret = dwc2_restore_global_registers(hsotg);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev, "%s: failed to restore registers\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
if (dwc2_is_host_mode(hsotg)) {
|
||||
ret = dwc2_restore_host_registers(hsotg);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = dwc2_restore_device_registers(hsotg);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_enter_hibernation() - Put controller in Partial Power Down.
|
||||
*
|
||||
* @hsotg: Programming view of the DWC_otg controller
|
||||
*/
|
||||
int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 pcgcctl;
|
||||
int ret = 0;
|
||||
|
||||
if (!hsotg->core_params->hibernation)
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* Backup all registers */
|
||||
ret = dwc2_backup_global_registers(hsotg);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dwc2_is_host_mode(hsotg)) {
|
||||
ret = dwc2_backup_host_registers(hsotg);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = dwc2_backup_device_registers(hsotg);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev, "%s: failed to backup device registers\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the controller in low power state */
|
||||
pcgcctl = DWC2_READ_4(hsotg, PCGCTL);
|
||||
|
||||
pcgcctl |= PCGCTL_PWRCLMP;
|
||||
DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl);
|
||||
ndelay(20);
|
||||
|
||||
pcgcctl |= PCGCTL_RSTPDWNMODULE;
|
||||
DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl);
|
||||
ndelay(20);
|
||||
|
||||
pcgcctl |= PCGCTL_STOPPCLK;
|
||||
DWC2_WRITE_4(hsotg, PCGCTL, pcgcctl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
|
||||
* used in both device and host modes
|
||||
@ -88,8 +446,10 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
|
||||
|
||||
if (hsotg->core_params->dma_enable <= 0)
|
||||
intmsk |= GINTSTS_RXFLVL;
|
||||
if (hsotg->core_params->external_id_pin_ctl <= 0)
|
||||
intmsk |= GINTSTS_CONIDSTSCHNG;
|
||||
|
||||
intmsk |= GINTSTS_CONIDSTSCHNG | GINTSTS_WKUPINT | GINTSTS_USBSUSP |
|
||||
intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP |
|
||||
GINTSTS_SESSREQINT;
|
||||
|
||||
DWC2_WRITE_4(hsotg, GINTMSK, intmsk);
|
||||
@ -129,6 +489,7 @@ static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 greset;
|
||||
int count = 0;
|
||||
u32 gusbcfg;
|
||||
|
||||
dev_vdbg(hsotg->dev, "%s()\n", __func__);
|
||||
|
||||
@ -159,6 +520,23 @@ static int dwc2_core_reset(struct dwc2_hsotg *hsotg)
|
||||
}
|
||||
} while (greset & GRSTCTL_CSFTRST);
|
||||
|
||||
if (hsotg->dr_mode == USB_DR_MODE_HOST) {
|
||||
gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
|
||||
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
|
||||
gusbcfg |= GUSBCFG_FORCEHOSTMODE;
|
||||
DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
|
||||
} else if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) {
|
||||
gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
|
||||
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
|
||||
gusbcfg |= GUSBCFG_FORCEDEVMODE;
|
||||
DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
|
||||
} else if (hsotg->dr_mode == USB_DR_MODE_OTG) {
|
||||
gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
|
||||
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
|
||||
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
|
||||
DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: This long sleep is _very_ important, otherwise the core will
|
||||
* not stay in host mode after a connector ID change!
|
||||
@ -312,13 +690,8 @@ static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
|
||||
|
||||
switch (hsotg->hw_params.arch) {
|
||||
case GHWCFG2_EXT_DMA_ARCH:
|
||||
dev_dbg(hsotg->dev, "External DMA Mode\n");
|
||||
if (hsotg->core_params->ahbcfg != -1) {
|
||||
ahbcfg &= GAHBCFG_CTRL_MASK;
|
||||
ahbcfg |= hsotg->core_params->ahbcfg &
|
||||
~GAHBCFG_CTRL_MASK;
|
||||
}
|
||||
break;
|
||||
dev_err(hsotg->dev, "External DMA Mode not supported\n");
|
||||
return -EINVAL;
|
||||
|
||||
case GHWCFG2_INT_DMA_ARCH:
|
||||
dev_dbg(hsotg->dev, "Internal DMA Mode\n");
|
||||
@ -460,7 +833,7 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy)
|
||||
dwc2_enable_common_interrupts(hsotg);
|
||||
|
||||
/*
|
||||
* Do device or host intialization based on mode during PCD and
|
||||
* Do device or host initialization based on mode during PCD and
|
||||
* HCD initialization
|
||||
*/
|
||||
if (dwc2_is_host_mode(hsotg)) {
|
||||
@ -513,6 +886,72 @@ void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
|
||||
DWC2_WRITE_4(hsotg, GINTMSK, intmsk);
|
||||
}
|
||||
|
||||
/*
|
||||
* dwc2_calculate_dynamic_fifo() - Calculates the default fifo size
|
||||
* For system that have a total fifo depth that is smaller than the default
|
||||
* RX + TX fifo size.
|
||||
*
|
||||
* @hsotg: Programming view of DWC_otg controller
|
||||
*/
|
||||
static void dwc2_calculate_dynamic_fifo(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *params = hsotg->core_params;
|
||||
struct dwc2_hw_params *hw = &hsotg->hw_params;
|
||||
u32 rxfsiz, nptxfsiz, ptxfsiz, total_fifo_size;
|
||||
|
||||
total_fifo_size = hw->total_fifo_size;
|
||||
rxfsiz = params->host_rx_fifo_size;
|
||||
nptxfsiz = params->host_nperio_tx_fifo_size;
|
||||
ptxfsiz = params->host_perio_tx_fifo_size;
|
||||
|
||||
/*
|
||||
* Will use Method 2 defined in the DWC2 spec: minimum FIFO depth
|
||||
* allocation with support for high bandwidth endpoints. Synopsys
|
||||
* defines MPS(Max Packet size) for a periodic EP=1024, and for
|
||||
* non-periodic as 512.
|
||||
*/
|
||||
if (total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)) {
|
||||
/*
|
||||
* For Buffer DMA mode/Scatter Gather DMA mode
|
||||
* 2 * ((Largest Packet size / 4) + 1 + 1) + n
|
||||
* with n = number of host channel.
|
||||
* 2 * ((1024/4) + 2) = 516
|
||||
*/
|
||||
rxfsiz = 516 + hw->host_channels;
|
||||
|
||||
/*
|
||||
* min non-periodic tx fifo depth
|
||||
* 2 * (largest non-periodic USB packet used / 4)
|
||||
* 2 * (512/4) = 256
|
||||
*/
|
||||
nptxfsiz = 256;
|
||||
|
||||
/*
|
||||
* min periodic tx fifo depth
|
||||
* (largest packet size*MC)/4
|
||||
* (1024 * 3)/4 = 768
|
||||
*/
|
||||
ptxfsiz = 768;
|
||||
|
||||
params->host_rx_fifo_size = rxfsiz;
|
||||
params->host_nperio_tx_fifo_size = nptxfsiz;
|
||||
params->host_perio_tx_fifo_size = ptxfsiz;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the summation of RX, NPTX and PTX fifo sizes is still
|
||||
* bigger than the total_fifo_size, then we have a problem.
|
||||
*
|
||||
* We won't be able to allocate as many endpoints. Right now,
|
||||
* we're just printing an error message, but ideally this FIFO
|
||||
* allocation algorithm would be improved in the future.
|
||||
*
|
||||
* FIXME improve this FIFO allocation algorithm.
|
||||
*/
|
||||
if (unlikely(total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)))
|
||||
dev_err(hsotg->dev, "invalid fifo sizes\n");
|
||||
}
|
||||
|
||||
static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_core_params *params = hsotg->core_params;
|
||||
@ -521,6 +960,8 @@ static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
|
||||
if (!params->enable_dynamic_fifo)
|
||||
return;
|
||||
|
||||
dwc2_calculate_dynamic_fifo(hsotg);
|
||||
|
||||
/* Rx FIFO */
|
||||
grxfsiz = DWC2_READ_4(hsotg, GRXFSIZ);
|
||||
dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
|
||||
@ -1401,18 +1842,10 @@ void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
|
||||
} else {
|
||||
dma_addr = chan->xfer_dma;
|
||||
}
|
||||
if (hsotg->hsotg_sc->sc_set_dma_addr == NULL) {
|
||||
DWC2_WRITE_4(hsotg, HCDMA(chan->hc_num),
|
||||
(u32)dma_addr);
|
||||
if (dbg_hc(chan))
|
||||
dev_vdbg(hsotg->dev,
|
||||
"Wrote %08lx to HCDMA(%d)\n",
|
||||
(unsigned long)dma_addr,
|
||||
chan->hc_num);
|
||||
} else {
|
||||
(void)(*hsotg->hsotg_sc->sc_set_dma_addr)(
|
||||
hsotg->dev, dma_addr, chan->hc_num);
|
||||
}
|
||||
DWC2_WRITE_4(hsotg, HCDMA(chan->hc_num), (u32)dma_addr);
|
||||
if (dbg_hc(chan))
|
||||
dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n",
|
||||
(unsigned long)dma_addr, chan->hc_num);
|
||||
}
|
||||
|
||||
/* Start the split */
|
||||
@ -2539,6 +2972,40 @@ static void dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val)
|
||||
hsotg->core_params->uframe_sched = val;
|
||||
}
|
||||
|
||||
static void dwc2_set_param_external_id_pin_ctl(struct dwc2_hsotg *hsotg,
|
||||
int val)
|
||||
{
|
||||
if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
|
||||
if (val >= 0) {
|
||||
dev_err(hsotg->dev,
|
||||
"'%d' invalid for parameter external_id_pin_ctl\n",
|
||||
val);
|
||||
dev_err(hsotg->dev, "external_id_pin_ctl must be 0 or 1\n");
|
||||
}
|
||||
val = 0;
|
||||
dev_dbg(hsotg->dev, "Setting external_id_pin_ctl to %d\n", val);
|
||||
}
|
||||
|
||||
hsotg->core_params->external_id_pin_ctl = val;
|
||||
}
|
||||
|
||||
static void dwc2_set_param_hibernation(struct dwc2_hsotg *hsotg,
|
||||
int val)
|
||||
{
|
||||
if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) {
|
||||
if (val >= 0) {
|
||||
dev_err(hsotg->dev,
|
||||
"'%d' invalid for parameter hibernation\n",
|
||||
val);
|
||||
dev_err(hsotg->dev, "hibernation must be 0 or 1\n");
|
||||
}
|
||||
val = 0;
|
||||
dev_dbg(hsotg->dev, "Setting hibernation to %d\n", val);
|
||||
}
|
||||
|
||||
hsotg->core_params->hibernation = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called during module intialization to pass module parameters
|
||||
* for the DWC_otg core.
|
||||
@ -2583,6 +3050,8 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
|
||||
dwc2_set_param_ahbcfg(hsotg, params->ahbcfg);
|
||||
dwc2_set_param_otg_ver(hsotg, params->otg_ver);
|
||||
dwc2_set_param_uframe_sched(hsotg, params->uframe_sched);
|
||||
dwc2_set_param_external_id_pin_ctl(hsotg, params->external_id_pin_ctl);
|
||||
dwc2_set_param_hibernation(hsotg, params->hibernation);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2618,23 +3087,23 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
|
||||
hwcfg2 = DWC2_READ_4(hsotg, GHWCFG2);
|
||||
hwcfg3 = DWC2_READ_4(hsotg, GHWCFG3);
|
||||
hwcfg4 = DWC2_READ_4(hsotg, GHWCFG4);
|
||||
gnptxfsiz = DWC2_READ_4(hsotg, GNPTXFSIZ);
|
||||
grxfsiz = DWC2_READ_4(hsotg, GRXFSIZ);
|
||||
|
||||
dev_dbg(hsotg->dev, "hwcfg1=%08x\n", DWC2_READ_4(hsotg, GHWCFG1));
|
||||
dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2);
|
||||
dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3);
|
||||
dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4);
|
||||
dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
|
||||
dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz);
|
||||
|
||||
/* Force host mode to get HPTXFSIZ exact power on value */
|
||||
/* Force host mode to get HPTXFSIZ / GNPTXFSIZ exact power on value */
|
||||
gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
|
||||
gusbcfg |= GUSBCFG_FORCEHOSTMODE;
|
||||
DWC2_WRITE_4(hsotg, GUSBCFG, gusbcfg);
|
||||
usleep_range(100000, 150000);
|
||||
|
||||
gnptxfsiz = DWC2_READ_4(hsotg, GNPTXFSIZ);
|
||||
hptxfsiz = DWC2_READ_4(hsotg, HPTXFSIZ);
|
||||
dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
|
||||
dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
|
||||
gusbcfg = DWC2_READ_4(hsotg, GUSBCFG);
|
||||
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
|
||||
@ -2669,6 +3138,13 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
|
||||
width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
|
||||
GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
|
||||
hw->max_transfer_size = (1 << (width + 11)) - 1;
|
||||
/*
|
||||
* Clip max_transfer_size to 65535. dwc2_hc_setup_align_buf() allocates
|
||||
* coherent buffers with this size, and if it's too large we can
|
||||
* exhaust the coherent DMA pool.
|
||||
*/
|
||||
if (hw->max_transfer_size > 65535)
|
||||
hw->max_transfer_size = 65535;
|
||||
width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
|
||||
GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
|
||||
hw->max_packet_count = (1 << (width + 4)) - 1;
|
||||
@ -2743,6 +3219,22 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets all parameters to the given value.
|
||||
*
|
||||
* Assumes that the dwc2_core_params struct contains only integers.
|
||||
*/
|
||||
void dwc2_set_all_params(struct dwc2_core_params *params, int value)
|
||||
{
|
||||
int *p = (int *)params;
|
||||
size_t size = sizeof(*params) / sizeof(*p);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
p[i] = value;
|
||||
}
|
||||
|
||||
|
||||
u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
return hsotg->core_params->otg_ver == 1 ? 0x0200 : 0x0103;
|
||||
|
411
sys/external/bsd/dwc2/dist/dwc2_core.h
vendored
411
sys/external/bsd/dwc2/dist/dwc2_core.h
vendored
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dwc2_core.h,v 1.5 2014/04/03 06:34:58 skrll Exp $ */
|
||||
/* $NetBSD: dwc2_core.h,v 1.6 2015/08/30 12:59:59 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* core.h - DesignWare HS OTG Controller common declarations
|
||||
@ -53,6 +53,129 @@
|
||||
/* Maximum number of Endpoints/HostChannels */
|
||||
#define MAX_EPS_CHANNELS 16
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
|
||||
/* s3c-hsotg declarations */
|
||||
static const char * const s3c_hsotg_supply_names[] = {
|
||||
"vusb_d", /* digital USB supply, 1.2V */
|
||||
"vusb_a", /* analog USB supply, 1.1V */
|
||||
};
|
||||
|
||||
/*
|
||||
* EP0_MPS_LIMIT
|
||||
*
|
||||
* Unfortunately there seems to be a limit of the amount of data that can
|
||||
* be transferred by IN transactions on EP0. This is either 127 bytes or 3
|
||||
* packets (which practically means 1 packet and 63 bytes of data) when the
|
||||
* MPS is set to 64.
|
||||
*
|
||||
* This means if we are wanting to move >127 bytes of data, we need to
|
||||
* split the transactions up, but just doing one packet at a time does
|
||||
* not work (this may be an implicit DATA0 PID on first packet of the
|
||||
* transaction) and doing 2 packets is outside the controller's limits.
|
||||
*
|
||||
* If we try to lower the MPS size for EP0, then no transfers work properly
|
||||
* for EP0, and the system will fail basic enumeration. As no cause for this
|
||||
* has currently been found, we cannot support any large IN transfers for
|
||||
* EP0.
|
||||
*/
|
||||
#define EP0_MPS_LIMIT 64
|
||||
|
||||
struct dwc2_hsotg;
|
||||
struct s3c_hsotg_req;
|
||||
|
||||
/**
|
||||
* struct s3c_hsotg_ep - driver endpoint definition.
|
||||
* @ep: The gadget layer representation of the endpoint.
|
||||
* @name: The driver generated name for the endpoint.
|
||||
* @queue: Queue of requests for this endpoint.
|
||||
* @parent: Reference back to the parent device structure.
|
||||
* @req: The current request that the endpoint is processing. This is
|
||||
* used to indicate an request has been loaded onto the endpoint
|
||||
* and has yet to be completed (maybe due to data move, or simply
|
||||
* awaiting an ack from the core all the data has been completed).
|
||||
* @debugfs: File entry for debugfs file for this endpoint.
|
||||
* @lock: State lock to protect contents of endpoint.
|
||||
* @dir_in: Set to true if this endpoint is of the IN direction, which
|
||||
* means that it is sending data to the Host.
|
||||
* @index: The index for the endpoint registers.
|
||||
* @mc: Multi Count - number of transactions per microframe
|
||||
* @interval - Interval for periodic endpoints
|
||||
* @name: The name array passed to the USB core.
|
||||
* @halted: Set if the endpoint has been halted.
|
||||
* @periodic: Set if this is a periodic ep, such as Interrupt
|
||||
* @isochronous: Set if this is a isochronous ep
|
||||
* @send_zlp: Set if we need to send a zero-length packet.
|
||||
* @total_data: The total number of data bytes done.
|
||||
* @fifo_size: The size of the FIFO (for periodic IN endpoints)
|
||||
* @fifo_load: The amount of data loaded into the FIFO (periodic IN)
|
||||
* @last_load: The offset of data for the last start of request.
|
||||
* @size_loaded: The last loaded size for DxEPTSIZE for periodic IN
|
||||
*
|
||||
* This is the driver's state for each registered enpoint, allowing it
|
||||
* to keep track of transactions that need doing. Each endpoint has a
|
||||
* lock to protect the state, to try and avoid using an overall lock
|
||||
* for the host controller as much as possible.
|
||||
*
|
||||
* For periodic IN endpoints, we have fifo_size and fifo_load to try
|
||||
* and keep track of the amount of data in the periodic FIFO for each
|
||||
* of these as we don't have a status register that tells us how much
|
||||
* is in each of them. (note, this may actually be useless information
|
||||
* as in shared-fifo mode periodic in acts like a single-frame packet
|
||||
* buffer than a fifo)
|
||||
*/
|
||||
struct s3c_hsotg_ep {
|
||||
struct usb_ep ep;
|
||||
struct list_head queue;
|
||||
struct dwc2_hsotg *parent;
|
||||
struct s3c_hsotg_req *req;
|
||||
struct dentry *debugfs;
|
||||
|
||||
unsigned long total_data;
|
||||
unsigned int size_loaded;
|
||||
unsigned int last_load;
|
||||
unsigned int fifo_load;
|
||||
unsigned short fifo_size;
|
||||
unsigned short fifo_index;
|
||||
|
||||
unsigned char dir_in;
|
||||
unsigned char index;
|
||||
unsigned char mc;
|
||||
unsigned char interval;
|
||||
|
||||
unsigned int halted:1;
|
||||
unsigned int periodic:1;
|
||||
unsigned int isochronous:1;
|
||||
unsigned int send_zlp:1;
|
||||
|
||||
char name[10];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s3c_hsotg_req - data transfer request
|
||||
* @req: The USB gadget request
|
||||
* @queue: The list of requests for the endpoint this is queued for.
|
||||
* @saved_req_buf: variable to save req.buf when bounce buffers are used.
|
||||
*/
|
||||
struct s3c_hsotg_req {
|
||||
struct usb_request req;
|
||||
struct list_head queue;
|
||||
void *saved_req_buf;
|
||||
};
|
||||
|
||||
#define call_gadget(_hs, _entry) \
|
||||
do { \
|
||||
if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \
|
||||
(_hs)->driver && (_hs)->driver->_entry) { \
|
||||
spin_unlock(&_hs->lock); \
|
||||
(_hs)->driver->_entry(&(_hs)->gadget); \
|
||||
spin_lock(&_hs->lock); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define call_gadget(_hs, _entry) do {} while (0)
|
||||
#endif
|
||||
|
||||
struct dwc2_hsotg;
|
||||
struct dwc2_host_chan;
|
||||
|
||||
@ -64,6 +187,22 @@ enum dwc2_lx_state {
|
||||
DWC2_L3, /* Off state */
|
||||
};
|
||||
|
||||
/*
|
||||
* Gadget periodic tx fifo sizes as used by legacy driver
|
||||
* EP0 is not included
|
||||
*/
|
||||
#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
|
||||
768, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
/* Gadget ep0 states */
|
||||
enum dwc2_ep0_state {
|
||||
DWC2_EP0_SETUP,
|
||||
DWC2_EP0_DATA_IN,
|
||||
DWC2_EP0_DATA_OUT,
|
||||
DWC2_EP0_STATUS_IN,
|
||||
DWC2_EP0_STATUS_OUT,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc2_core_params - Parameters for configuring the core
|
||||
*
|
||||
@ -188,6 +327,17 @@ enum dwc2_lx_state {
|
||||
* by the driver and are ignored in this
|
||||
* configuration value.
|
||||
* @uframe_sched: True to enable the microframe scheduler
|
||||
* @external_id_pin_ctl: Specifies whether ID pin is handled externally.
|
||||
* Disable CONIDSTSCHNG controller interrupt in such
|
||||
* case.
|
||||
* 0 - No (default)
|
||||
* 1 - Yes
|
||||
* @hibernation: Specifies whether the controller support hibernation.
|
||||
* If hibernation is enabled, the controller will enter
|
||||
* hibernation in both peripheral and host mode when
|
||||
* needed.
|
||||
* 0 - No (default)
|
||||
* 1 - Yes
|
||||
*
|
||||
* The following parameters may be specified when starting the module. These
|
||||
* parameters define how the DWC_otg controller should be configured. A
|
||||
@ -225,6 +375,8 @@ struct dwc2_core_params {
|
||||
int reload_ctl;
|
||||
int ahbcfg;
|
||||
int uframe_sched;
|
||||
int external_id_pin_ctl;
|
||||
int hibernation;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -252,7 +404,7 @@ struct dwc2_core_params {
|
||||
* @power_optimized Are power optimizations enabled?
|
||||
* @num_dev_ep Number of device endpoints available
|
||||
* @num_dev_perio_in_ep Number of device periodic IN endpoints
|
||||
* avaialable
|
||||
* available
|
||||
* @dev_token_q_depth Device Mode IN Token Sequence Learning Queue
|
||||
* Depth
|
||||
* 0 to 30
|
||||
@ -305,19 +457,109 @@ struct dwc2_hw_params {
|
||||
u32 snpsid;
|
||||
};
|
||||
|
||||
/* Size of control and EP0 buffers */
|
||||
#define DWC2_CTRL_BUFF_SIZE 8
|
||||
|
||||
/**
|
||||
* struct dwc2_gregs_backup - Holds global registers state before entering partial
|
||||
* power down
|
||||
* @gotgctl: Backup of GOTGCTL register
|
||||
* @gintmsk: Backup of GINTMSK register
|
||||
* @gahbcfg: Backup of GAHBCFG register
|
||||
* @gusbcfg: Backup of GUSBCFG register
|
||||
* @grxfsiz: Backup of GRXFSIZ register
|
||||
* @gnptxfsiz: Backup of GNPTXFSIZ register
|
||||
* @gi2cctl: Backup of GI2CCTL register
|
||||
* @hptxfsiz: Backup of HPTXFSIZ register
|
||||
* @gdfifocfg: Backup of GDFIFOCFG register
|
||||
* @dtxfsiz: Backup of DTXFSIZ registers for each endpoint
|
||||
* @gpwrdn: Backup of GPWRDN register
|
||||
*/
|
||||
struct dwc2_gregs_backup {
|
||||
u32 gotgctl;
|
||||
u32 gintmsk;
|
||||
u32 gahbcfg;
|
||||
u32 gusbcfg;
|
||||
u32 grxfsiz;
|
||||
u32 gnptxfsiz;
|
||||
u32 gi2cctl;
|
||||
u32 hptxfsiz;
|
||||
u32 pcgcctl;
|
||||
u32 gdfifocfg;
|
||||
u32 dtxfsiz[MAX_EPS_CHANNELS];
|
||||
u32 gpwrdn;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc2_dregs_backup - Holds device registers state before entering partial
|
||||
* power down
|
||||
* @dcfg: Backup of DCFG register
|
||||
* @dctl: Backup of DCTL register
|
||||
* @daintmsk: Backup of DAINTMSK register
|
||||
* @diepmsk: Backup of DIEPMSK register
|
||||
* @doepmsk: Backup of DOEPMSK register
|
||||
* @diepctl: Backup of DIEPCTL register
|
||||
* @dieptsiz: Backup of DIEPTSIZ register
|
||||
* @diepdma: Backup of DIEPDMA register
|
||||
* @doepctl: Backup of DOEPCTL register
|
||||
* @doeptsiz: Backup of DOEPTSIZ register
|
||||
* @doepdma: Backup of DOEPDMA register
|
||||
*/
|
||||
struct dwc2_dregs_backup {
|
||||
u32 dcfg;
|
||||
u32 dctl;
|
||||
u32 daintmsk;
|
||||
u32 diepmsk;
|
||||
u32 doepmsk;
|
||||
u32 diepctl[MAX_EPS_CHANNELS];
|
||||
u32 dieptsiz[MAX_EPS_CHANNELS];
|
||||
u32 diepdma[MAX_EPS_CHANNELS];
|
||||
u32 doepctl[MAX_EPS_CHANNELS];
|
||||
u32 doeptsiz[MAX_EPS_CHANNELS];
|
||||
u32 doepdma[MAX_EPS_CHANNELS];
|
||||
bool valid;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc2_hregs_backup - Holds host registers state before entering partial
|
||||
* power down
|
||||
* @hcfg: Backup of HCFG register
|
||||
* @haintmsk: Backup of HAINTMSK register
|
||||
* @hcintmsk: Backup of HCINTMSK register
|
||||
* @hptr0: Backup of HPTR0 register
|
||||
* @hfir: Backup of HFIR register
|
||||
*/
|
||||
struct dwc2_hregs_backup {
|
||||
u32 hcfg;
|
||||
u32 haintmsk;
|
||||
u32 hcintmsk[MAX_EPS_CHANNELS];
|
||||
u32 hprt0;
|
||||
u32 hfir;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
|
||||
* and periodic schedules
|
||||
*
|
||||
* These are common for both host and peripheral modes:
|
||||
*
|
||||
* @dev: The struct device pointer
|
||||
* @regs: Pointer to controller regs
|
||||
* @core_params: Parameters that define how the core should be configured
|
||||
* @hw_params: Parameters that were autodetected from the
|
||||
* hardware registers
|
||||
* @core_params: Parameters that define how the core should be configured
|
||||
* @op_state: The operational State, during transitions (a_host=>
|
||||
* a_peripheral and b_device=>b_host) this may not match
|
||||
* the core, but allows the software to determine
|
||||
* transitions
|
||||
* @dr_mode: Requested mode of operation, one of following:
|
||||
* - USB_DR_MODE_PERIPHERAL
|
||||
* - USB_DR_MODE_HOST
|
||||
* - USB_DR_MODE_OTG
|
||||
* @lock: Spinlock that protects all the driver data structures
|
||||
* @priv: Stores a pointer to the struct usb_hcd
|
||||
* @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
|
||||
* transfer are in process of being queued
|
||||
* @srp_success: Stores status of SRP request in the case of a FS PHY
|
||||
@ -327,6 +569,12 @@ struct dwc2_hw_params {
|
||||
* interrupt
|
||||
* @wkp_timer: Timer object for handling Wakeup Detected interrupt
|
||||
* @lx_state: Lx state of connected device
|
||||
* @gregs_backup: Backup of global registers during suspend
|
||||
* @dregs_backup: Backup of device registers during suspend
|
||||
* @hregs_backup: Backup of host registers during suspend
|
||||
*
|
||||
* These are for host mode:
|
||||
*
|
||||
* @flags: Flags for handling root port state changes
|
||||
* @non_periodic_sched_inactive: Inactive QHs in the non-periodic schedule.
|
||||
* Transfers associated with these QHs are not currently
|
||||
@ -395,11 +643,37 @@ struct dwc2_hw_params {
|
||||
* @status_buf_dma: DMA address for status_buf
|
||||
* @start_work: Delayed work for handling host A-cable connection
|
||||
* @reset_work: Delayed work for handling a port reset
|
||||
* @lock: Spinlock that protects all the driver data structures
|
||||
* @priv: Stores a pointer to the struct usb_hcd
|
||||
* @otg_port: OTG port number
|
||||
* @frame_list: Frame list
|
||||
* @frame_list_dma: Frame list DMA address
|
||||
*
|
||||
* These are for peripheral mode:
|
||||
*
|
||||
* @driver: USB gadget driver
|
||||
* @phy: The otg phy transceiver structure for phy control.
|
||||
* @uphy: The otg phy transceiver structure for old USB phy control.
|
||||
* @plat: The platform specific configuration data. This can be removed once
|
||||
* all SoCs support usb transceiver.
|
||||
* @supplies: Definition of USB power supplies
|
||||
* @phyif: PHY interface width
|
||||
* @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
|
||||
* @num_of_eps: Number of available EPs (excluding EP0)
|
||||
* @debug_root: Root directrory for debugfs.
|
||||
* @debug_file: Main status file for debugfs.
|
||||
* @debug_testmode: Testmode status file for debugfs.
|
||||
* @debug_fifo: FIFO status file for debugfs.
|
||||
* @ep0_reply: Request used for ep0 reply.
|
||||
* @ep0_buff: Buffer for EP0 reply data, if needed.
|
||||
* @ctrl_buff: Buffer for EP0 control requests.
|
||||
* @ctrl_req: Request for EP0 control packets.
|
||||
* @ep0_state: EP0 control transfers state
|
||||
* @test_mode: USB test mode requested by the host
|
||||
* @last_rst: Time of last reset
|
||||
* @eps: The endpoints being supplied to the gadget framework
|
||||
* @g_using_dma: Indicate if dma usage is enabled
|
||||
* @g_rx_fifo_sz: Contains rx fifo size value
|
||||
* @g_np_g_tx_fifo_sz: Contains Non-Periodic tx fifo size value
|
||||
* @g_tx_fifo_sz: Contains tx fifo size value per endpoints
|
||||
*/
|
||||
struct dwc2_hsotg {
|
||||
device_t dev;
|
||||
@ -409,6 +683,21 @@ struct dwc2_hsotg {
|
||||
/** Params to actually use */
|
||||
struct dwc2_core_params *core_params;
|
||||
enum usb_otg_state op_state;
|
||||
enum usb_dr_mode dr_mode;
|
||||
unsigned int hcd_enabled:1;
|
||||
unsigned int gadget_enabled:1;
|
||||
|
||||
spinlock_t lock;
|
||||
void *priv;
|
||||
struct usb_phy *uphy;
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
struct phy *phy;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
|
||||
|
||||
struct mutex init_mutex;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
|
||||
|
||||
unsigned int queuing_high_bandwidth:1;
|
||||
unsigned int srp_success:1;
|
||||
@ -417,7 +706,21 @@ struct dwc2_hsotg {
|
||||
struct work wf_otg;
|
||||
struct callout wkp_timer;
|
||||
enum dwc2_lx_state lx_state;
|
||||
struct dwc2_gregs_backup gr_backup;
|
||||
struct dwc2_dregs_backup dr_backup;
|
||||
struct dwc2_hregs_backup hr_backup;
|
||||
|
||||
struct dentry *debug_root;
|
||||
struct debugfs_regset32 *regset;
|
||||
|
||||
/* DWC OTG HW Release versions */
|
||||
#define DWC2_CORE_REV_2_71a 0x4f54271a
|
||||
#define DWC2_CORE_REV_2_90a 0x4f54290a
|
||||
#define DWC2_CORE_REV_2_92a 0x4f54292a
|
||||
#define DWC2_CORE_REV_2_94a 0x4f54294a
|
||||
#define DWC2_CORE_REV_3_00a 0x4f54300a
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
union dwc2_hcd_internal_flags {
|
||||
u32 d32;
|
||||
struct {
|
||||
@ -428,7 +731,7 @@ struct dwc2_hsotg {
|
||||
unsigned port_suspend_change:1;
|
||||
unsigned port_over_current_change:1;
|
||||
unsigned port_l1_change:1;
|
||||
unsigned reserved:26;
|
||||
unsigned reserved:25;
|
||||
} b;
|
||||
} flags;
|
||||
|
||||
@ -465,20 +768,11 @@ struct dwc2_hsotg {
|
||||
|
||||
struct delayed_work start_work;
|
||||
struct delayed_work reset_work;
|
||||
spinlock_t lock;
|
||||
void *priv;
|
||||
u8 otg_port;
|
||||
usb_dma_t frame_list_usbdma;
|
||||
u32 *frame_list;
|
||||
dma_addr_t frame_list_dma;
|
||||
|
||||
/* DWC OTG HW Release versions */
|
||||
#define DWC2_CORE_REV_2_71a 0x4f54271a
|
||||
#define DWC2_CORE_REV_2_90a 0x4f54290a
|
||||
#define DWC2_CORE_REV_2_92a 0x4f54292a
|
||||
#define DWC2_CORE_REV_2_94a 0x4f54294a
|
||||
#define DWC2_CORE_REV_3_00a 0x4f54300a
|
||||
|
||||
#ifdef DEBUG
|
||||
u32 frrem_samples;
|
||||
u64 frrem_accum;
|
||||
@ -497,6 +791,37 @@ struct dwc2_hsotg {
|
||||
u32 hfnum_other_samples_b;
|
||||
u64 hfnum_other_frrem_accum_b;
|
||||
#endif
|
||||
#endif /* CONFIG_USB_DWC2_HOST || CONFIG_USB_DWC2_DUAL_ROLE */
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
/* Gadget structures */
|
||||
struct usb_gadget_driver *driver;
|
||||
struct s3c_hsotg_plat *plat;
|
||||
|
||||
u32 phyif;
|
||||
int fifo_mem;
|
||||
unsigned int dedicated_fifos:1;
|
||||
unsigned char num_of_eps;
|
||||
u32 fifo_map;
|
||||
|
||||
struct usb_request *ep0_reply;
|
||||
struct usb_request *ctrl_req;
|
||||
void *ep0_buff;
|
||||
void *ctrl_buff;
|
||||
enum dwc2_ep0_state ep0_state;
|
||||
u8 test_mode;
|
||||
|
||||
struct usb_gadget gadget;
|
||||
unsigned int enabled:1;
|
||||
unsigned int connected:1;
|
||||
unsigned long last_rst;
|
||||
struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
|
||||
struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
|
||||
u32 g_using_dma;
|
||||
u32 g_rx_fifo_sz;
|
||||
u32 g_np_g_tx_fifo_sz;
|
||||
u32 g_tx_fifo_sz[MAX_EPS_CHANNELS];
|
||||
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
|
||||
};
|
||||
|
||||
/* Reasons for halting a host channel */
|
||||
@ -522,6 +847,8 @@ enum dwc2_halt_status {
|
||||
* and the DWC_otg controller
|
||||
*/
|
||||
extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
|
||||
extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
|
||||
extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
|
||||
|
||||
/*
|
||||
* Host core Functions.
|
||||
@ -754,6 +1081,15 @@ extern void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
|
||||
|
||||
extern void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
|
||||
|
||||
extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
|
||||
const struct dwc2_core_params *params);
|
||||
|
||||
extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
|
||||
|
||||
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Dump core registers and SPRAM
|
||||
*/
|
||||
@ -766,4 +1102,49 @@ extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg);
|
||||
*/
|
||||
extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/* Gadget defines */
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
|
||||
extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
|
||||
extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
|
||||
extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
|
||||
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
|
||||
bool reset);
|
||||
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
|
||||
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
|
||||
extern int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
|
||||
#define dwc2_is_device_connected(hsotg) (hsotg->connected)
|
||||
#else
|
||||
static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
|
||||
{ return 0; }
|
||||
static inline int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2)
|
||||
{ return 0; }
|
||||
static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
|
||||
{ return 0; }
|
||||
static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
|
||||
{ return 0; }
|
||||
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
|
||||
bool reset) {}
|
||||
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
|
||||
static inline int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
|
||||
int testmode)
|
||||
{ return 0; }
|
||||
#define dwc2_is_device_connected(hsotg) (0)
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
|
||||
extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
|
||||
#else
|
||||
static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
|
||||
static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
|
||||
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
#endif /* __DWC2_CORE_H__ */
|
||||
|
75
sys/external/bsd/dwc2/dist/dwc2_coreintr.c
vendored
75
sys/external/bsd/dwc2/dist/dwc2_coreintr.c
vendored
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dwc2_coreintr.c,v 1.8 2014/04/04 05:40:57 skrll Exp $ */
|
||||
/* $NetBSD: dwc2_coreintr.c,v 1.9 2015/08/30 12:59:59 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* core_intr.c - DesignWare HS OTG Controller common interrupt handling
|
||||
@ -41,7 +41,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_coreintr.c,v 1.8 2014/04/04 05:40:57 skrll Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_coreintr.c,v 1.9 2015/08/30 12:59:59 skrll Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -57,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: dwc2_coreintr.c,v 1.8 2014/04/04 05:40:57 skrll Exp
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <dwc2/dwc2.h>
|
||||
#include <dwc2/dwc2var.h>
|
||||
@ -141,6 +142,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
||||
dwc2_op_state_str(hsotg));
|
||||
gotgctl = DWC2_READ_4(hsotg, GOTGCTL);
|
||||
|
||||
if (dwc2_is_device_mode(hsotg))
|
||||
s3c_hsotg_disconnect(hsotg);
|
||||
|
||||
if (hsotg->op_state == OTG_STATE_B_HOST) {
|
||||
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
|
||||
} else {
|
||||
@ -300,9 +304,11 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
|
||||
* Release lock before scheduling workq as it holds spinlock during
|
||||
* scheduling.
|
||||
*/
|
||||
spin_unlock(&hsotg->lock);
|
||||
workqueue_enqueue(hsotg->wq_otg, &hsotg->wf_otg, NULL);
|
||||
spin_lock(&hsotg->lock);
|
||||
if (hsotg->wq_otg) {
|
||||
spin_unlock(&hsotg->lock);
|
||||
workqueue_enqueue(hsotg->wq_otg, &hsotg->wf_otg, NULL);
|
||||
spin_lock(&hsotg->lock);
|
||||
}
|
||||
|
||||
/* Clear interrupt */
|
||||
DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_CONIDSTSCHNG);
|
||||
@ -325,6 +331,12 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
|
||||
|
||||
/* Clear interrupt */
|
||||
DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_SESSREQINT);
|
||||
|
||||
/*
|
||||
* Report disconnect if there is any previous session established
|
||||
*/
|
||||
if (dwc2_is_device_mode(hsotg))
|
||||
s3c_hsotg_disconnect(hsotg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -336,6 +348,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
|
||||
*/
|
||||
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
int ret;
|
||||
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
|
||||
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
|
||||
|
||||
@ -347,6 +360,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
||||
/* Clear Remote Wakeup Signaling */
|
||||
dctl &= ~DCTL_RMTWKUPSIG;
|
||||
DWC2_WRITE_4(hsotg, DCTL, dctl);
|
||||
ret = dwc2_exit_hibernation(hsotg, true);
|
||||
if (ret && (ret != -ENOTSUPP))
|
||||
dev_err(hsotg->dev, "exit hibernation failed\n");
|
||||
|
||||
call_gadget(hsotg, resume);
|
||||
}
|
||||
/* Change to L0 state */
|
||||
hsotg->lx_state = DWC2_L0;
|
||||
@ -379,6 +397,9 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
|
||||
dwc2_is_host_mode(hsotg) ? "Host" : "Device",
|
||||
dwc2_op_state_str(hsotg));
|
||||
|
||||
if (hsotg->op_state == OTG_STATE_A_HOST)
|
||||
dwc2_hcd_disconnect(hsotg);
|
||||
|
||||
/* Change to L3 (OFF) state */
|
||||
hsotg->lx_state = DWC2_L3;
|
||||
|
||||
@ -395,12 +416,12 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
|
||||
*/
|
||||
static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
u32 dsts;
|
||||
int ret;
|
||||
|
||||
dev_dbg(hsotg->dev, "USB SUSPEND\n");
|
||||
|
||||
if (dwc2_is_device_mode(hsotg)) {
|
||||
#ifdef DWC2_DEBUG
|
||||
u32 dsts;
|
||||
|
||||
/*
|
||||
* Check the Device status register to determine if the Suspend
|
||||
* state is active
|
||||
@ -411,11 +432,43 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
||||
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
|
||||
!!(dsts & DSTS_SUSPSTS),
|
||||
hsotg->hw_params.power_optimized);
|
||||
#endif
|
||||
if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
|
||||
/* Ignore suspend request before enumeration */
|
||||
if (!dwc2_is_device_connected(hsotg)) {
|
||||
dev_dbg(hsotg->dev,
|
||||
"ignore suspend request before enumeration\n");
|
||||
goto clear_int;
|
||||
}
|
||||
|
||||
ret = dwc2_enter_hibernation(hsotg);
|
||||
if (ret) {
|
||||
if (ret != -ENOTSUPP)
|
||||
dev_err(hsotg->dev,
|
||||
"enter hibernation failed\n");
|
||||
goto skip_power_saving;
|
||||
}
|
||||
|
||||
udelay(100);
|
||||
|
||||
/* Ask phy to be suspended */
|
||||
if (!IS_ERR_OR_NULL(hsotg->uphy))
|
||||
usb_phy_set_suspend(hsotg->uphy, true);
|
||||
skip_power_saving:
|
||||
/*
|
||||
* Change to L2 (suspend) state before releasing
|
||||
* spinlock
|
||||
*/
|
||||
hsotg->lx_state = DWC2_L2;
|
||||
|
||||
/* Call gadget suspend callback */
|
||||
call_gadget(hsotg, suspend);
|
||||
}
|
||||
} else {
|
||||
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
|
||||
dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
|
||||
|
||||
/* Change to L2 (suspend) state */
|
||||
hsotg->lx_state = DWC2_L2;
|
||||
/* Clear the a_peripheral flag, back to a_host */
|
||||
spin_unlock(&hsotg->lock);
|
||||
dwc2_hcd_start(hsotg);
|
||||
@ -424,9 +477,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Change to L2 (suspend) state */
|
||||
hsotg->lx_state = DWC2_L2;
|
||||
|
||||
clear_int:
|
||||
/* Clear interrupt */
|
||||
DWC2_WRITE_4(hsotg, GINTSTS, GINTSTS_USBSUSP);
|
||||
}
|
||||
|
163
sys/external/bsd/dwc2/dist/dwc2_hcd.c
vendored
163
sys/external/bsd/dwc2/dist/dwc2_hcd.c
vendored
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dwc2_hcd.c,v 1.15 2014/11/24 10:14:14 skrll Exp $ */
|
||||
/* $NetBSD: dwc2_hcd.c,v 1.16 2015/08/30 12:59:59 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* hcd.c - DesignWare HS OTG Controller host-mode routines
|
||||
@ -42,7 +42,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.15 2014/11/24 10:14:14 skrll Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.16 2015/08/30 12:59:59 skrll Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/kmem.h>
|
||||
@ -57,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: dwc2_hcd.c,v 1.15 2014/11/24 10:14:14 skrll Exp $");
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <dwc2/dwc2.h>
|
||||
#include <dwc2/dwc2var.h>
|
||||
@ -267,6 +268,14 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
|
||||
*/
|
||||
channel->qh = NULL;
|
||||
}
|
||||
/* All channels have been freed, mark them available */
|
||||
if (hsotg->core_params->uframe_sched > 0) {
|
||||
hsotg->available_host_channels =
|
||||
hsotg->core_params->host_channels;
|
||||
} else {
|
||||
hsotg->non_periodic_channels = 0;
|
||||
hsotg->periodic_channels = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -328,10 +337,12 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
|
||||
*/
|
||||
static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
if (hsotg->lx_state == DWC2_L2)
|
||||
if (hsotg->lx_state == DWC2_L2) {
|
||||
hsotg->flags.b.port_suspend_change = 1;
|
||||
else
|
||||
usb_hcd_resume_root_hub(hsotg->priv);
|
||||
} else {
|
||||
hsotg->flags.b.port_l1_change = 1;
|
||||
}
|
||||
|
||||
dwc2_root_intr(hsotg->hsotg_sc);
|
||||
}
|
||||
@ -361,12 +372,11 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
|
||||
DWC2_WRITE_4(hsotg, HPRT0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, struct dwc2_hcd_urb *urb,
|
||||
void **ep_handle, gfp_t mem_flags)
|
||||
/* Caller must hold driver lock */
|
||||
int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_hcd_urb *urb, struct dwc2_qh *qh,
|
||||
struct dwc2_qtd *qtd)
|
||||
{
|
||||
struct dwc2_softc *sc = hsotg->hsotg_sc;
|
||||
struct dwc2_qtd *qtd;
|
||||
u32 intr_mask;
|
||||
int retval;
|
||||
int dev_speed;
|
||||
@ -379,32 +389,28 @@ dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, struct dwc2_hcd_urb *urb,
|
||||
|
||||
dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
|
||||
|
||||
/* Some core configurations cannot support LS traffic on a FS root port */
|
||||
/* Some configurations cannot support LS traffic on a FS root port */
|
||||
if ((dev_speed == USB_SPEED_LOW) &&
|
||||
(hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) &&
|
||||
(hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI)) {
|
||||
u32 hprt0 = DWC2_READ_4(hsotg, HPRT0);
|
||||
u32 prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
|
||||
|
||||
if (prtspd == HPRT0_SPD_FULL_SPEED) {
|
||||
if (prtspd == HPRT0_SPD_FULL_SPEED)
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
qtd = pool_cache_get(sc->sc_qtdpool, PR_NOWAIT);
|
||||
if (!qtd)
|
||||
return -ENOMEM;
|
||||
return -EINVAL;
|
||||
|
||||
memset(qtd, 0, sizeof(*qtd));
|
||||
|
||||
dwc2_hcd_qtd_init(qtd, urb);
|
||||
retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle,
|
||||
mem_flags);
|
||||
retval = dwc2_hcd_qtd_add(hsotg, qtd, qh);
|
||||
if (retval) {
|
||||
dev_err(hsotg->dev,
|
||||
"DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
|
||||
retval);
|
||||
pool_cache_put(sc->sc_qtdpool, qtd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -665,18 +671,20 @@ static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
|
||||
}
|
||||
|
||||
static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
struct dwc2_host_chan *chan, void *bufptr)
|
||||
struct dwc2_host_chan *chan,
|
||||
struct dwc2_hcd_urb *urb, void *bufptr)
|
||||
{
|
||||
u32 buf_size;
|
||||
|
||||
if (chan->ep_type != USB_ENDPOINT_XFER_ISOC)
|
||||
buf_size = hsotg->core_params->max_transfer_size;
|
||||
else
|
||||
buf_size = 4096;
|
||||
|
||||
if (!qh->dw_align_buf) {
|
||||
int err;
|
||||
|
||||
if (chan->ep_type != USB_ENDPOINT_XFER_ISOC)
|
||||
buf_size = hsotg->core_params->max_transfer_size;
|
||||
else
|
||||
/* 3072 = 3 max-size Isoc packets */
|
||||
buf_size = 3072;
|
||||
|
||||
qh->dw_align_buf = NULL;
|
||||
qh->dw_align_buf_dma = 0;
|
||||
err = usb_allocmem(&hsotg->hsotg_sc->sc_bus, buf_size, buf_size,
|
||||
@ -689,16 +697,26 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
}
|
||||
if (!qh->dw_align_buf)
|
||||
return -ENOMEM;
|
||||
qh->dw_align_buf_size = buf_size;
|
||||
}
|
||||
|
||||
if (!chan->ep_is_in && chan->xfer_len) {
|
||||
usb_syncmem(chan->xfer_usbdma, 0, buf_size,
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
memcpy(qh->dw_align_buf, bufptr, chan->xfer_len);
|
||||
usb_syncmem(chan->xfer_usbdma, 0, buf_size,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
if (chan->xfer_len) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
void *usb_urb = urb->priv;
|
||||
|
||||
if (usb_urb) {
|
||||
if (!chan->ep_is_in) {
|
||||
memcpy(qh->dw_align_buf, bufptr,
|
||||
chan->xfer_len);
|
||||
}
|
||||
} else {
|
||||
dev_warn(hsotg->dev, "no URB in dwc2_urb\n");
|
||||
}
|
||||
}
|
||||
|
||||
usb_syncmem(&qh->dw_align_buf_usbdma, 0, qh->dw_align_buf_size,
|
||||
chan->ep_is_in ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
||||
|
||||
chan->align_buf = qh->dw_align_buf_dma;
|
||||
return 0;
|
||||
}
|
||||
@ -793,8 +811,8 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
||||
|
||||
/* Non DWORD-aligned buffer case */
|
||||
if (bufptr) {
|
||||
dev_vdbg(hsotg->dev, "Non-aligned buffer%p\n", bufptr);
|
||||
if (dwc2_hc_setup_align_buf(hsotg, qh, chan, bufptr)) {
|
||||
dev_vdbg(hsotg->dev, "Non-aligned buffer\n");
|
||||
if (dwc2_hc_setup_align_buf(hsotg, qh, chan, urb, bufptr)) {
|
||||
dev_err(hsotg->dev,
|
||||
"%s: Failed to allocate memory to handle non-dword aligned buffer\n",
|
||||
__func__);
|
||||
@ -1338,6 +1356,8 @@ dwc2_conn_id_status_change(struct work *work)
|
||||
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
|
||||
dwc2_core_init(hsotg, false);
|
||||
dwc2_enable_global_interrupts(hsotg);
|
||||
s3c_hsotg_core_init_disconnected(hsotg, false);
|
||||
s3c_hsotg_core_connect(hsotg);
|
||||
} else {
|
||||
/* A-Device connector (Host Mode) */
|
||||
dev_dbg(hsotg->dev, "connId A\n");
|
||||
@ -1485,7 +1505,7 @@ dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||
hprt0 |= HPRT0_RES;
|
||||
DWC2_WRITE_4(hsotg, HPRT0, hprt0);
|
||||
hprt0 &= ~HPRT0_SUSP;
|
||||
usleep_range(100000, 150000);
|
||||
msleep(USB_RESUME_TIMEOUT);
|
||||
|
||||
hprt0 &= ~HPRT0_RES;
|
||||
DWC2_WRITE_4(hsotg, HPRT0, hprt0);
|
||||
@ -1566,9 +1586,10 @@ dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||
dev_dbg(hsotg->dev, "GetHubDescriptor\n");
|
||||
hub_desc = (usb_hub_descriptor_t *)buf;
|
||||
hub_desc->bDescLength = 9;
|
||||
hub_desc->bDescriptorType = 0x29;
|
||||
hub_desc->bDescriptorType = USB_DT_HUB;
|
||||
hub_desc->bNbrPorts = 1;
|
||||
USETW(hub_desc->wHubCharacteristics, 0x08);
|
||||
USETW(hub_desc->wHubCharacteristics, HUB_CHAR_COMMON_LPSM |
|
||||
HUB_CHAR_INDV_PORT_OCPM);
|
||||
hub_desc->bPwrOn2PwrGood = 1;
|
||||
hub_desc->bHubContrCurrent = 0;
|
||||
hub_desc->DeviceRemovable[0] = 0;
|
||||
@ -1727,6 +1748,15 @@ dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
|
||||
/* Not supported */
|
||||
break;
|
||||
|
||||
case USB_PORT_FEAT_TEST:
|
||||
hprt0 = dwc2_read_hprt0(hsotg);
|
||||
dev_dbg(hsotg->dev,
|
||||
"SetPortFeature - USB_PORT_FEAT_TEST\n");
|
||||
hprt0 &= ~HPRT0_TSTCTL_MASK;
|
||||
hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT;
|
||||
DWC2_WRITE_4(hsotg, HPRT0, hprt0);
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
dev_err(hsotg->dev,
|
||||
@ -2067,7 +2097,6 @@ dwc2_hcd_reset_func(struct work *work)
|
||||
* error code on failure.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Frees secondary storage associated with the dwc2_hsotg structure contained
|
||||
* in the struct usb_hcd field
|
||||
@ -2141,42 +2170,23 @@ static void dwc2_hcd_release(struct dwc2_hsotg *hsotg)
|
||||
dwc2_hcd_free(hsotg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets all parameters to the given value.
|
||||
*
|
||||
* Assumes that the dwc2_core_params struct contains only integers.
|
||||
*/
|
||||
void dwc2_set_all_params(struct dwc2_core_params *params, int value)
|
||||
{
|
||||
int *p = (int *)params;
|
||||
size_t size = sizeof(*params) / sizeof(*p);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
p[i] = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes the HCD. This function allocates memory for and initializes the
|
||||
* static parts of the usb_hcd and dwc2_hsotg structures. It also registers the
|
||||
* USB bus with the core and calls the hc_driver->start() function. It returns
|
||||
* a negative error on failure.
|
||||
*/
|
||||
int dwc2_hcd_init(struct dwc2_hsotg *hsotg,
|
||||
const struct dwc2_core_params *params)
|
||||
int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct dwc2_host_chan *channel;
|
||||
int i, num_channels;
|
||||
int err, retval;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
|
||||
|
||||
/* Detect config values from hardware */
|
||||
retval = dwc2_get_hwparams(hsotg);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = -ENOMEM;
|
||||
|
||||
dev_dbg(hsotg->dev, "hcfg=%08x\n", DWC2_READ_4(hsotg, HCFG));
|
||||
@ -2194,15 +2204,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg,
|
||||
hsotg->last_frame_num = HFNUM_MAX_FRNUM;
|
||||
#endif
|
||||
|
||||
hsotg->core_params = kmem_zalloc(sizeof(*hsotg->core_params), KM_SLEEP);
|
||||
if (!hsotg->core_params)
|
||||
goto error1;
|
||||
|
||||
dwc2_set_all_params(hsotg->core_params, -1);
|
||||
|
||||
/* Validate parameter values */
|
||||
dwc2_set_parameters(hsotg, params);
|
||||
|
||||
spin_lock_init(&hsotg->lock);
|
||||
|
||||
/*
|
||||
@ -2306,7 +2307,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg,
|
||||
error3:
|
||||
dwc2_hcd_release(hsotg);
|
||||
error2:
|
||||
error1:
|
||||
kmem_free(hsotg->core_params, sizeof(*hsotg->core_params));
|
||||
|
||||
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
|
||||
@ -2319,3 +2319,30 @@ error1:
|
||||
dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes the HCD.
|
||||
* Frees memory and resources associated with the HCD and deregisters the bus.
|
||||
*/
|
||||
void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
dev_dbg(hsotg->dev, "DWC OTG HCD REMOVE\n");
|
||||
|
||||
hcd = dwc2_hsotg_to_hcd(hsotg);
|
||||
dev_dbg(hsotg->dev, "hsotg->hcd = %p\n", hcd);
|
||||
|
||||
if (!hcd) {
|
||||
dev_dbg(hsotg->dev, "%s: dwc2_hsotg_to_hcd(hsotg) NULL!\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
hsotg->priv = NULL;
|
||||
dwc2_hcd_release(hsotg);
|
||||
|
||||
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
|
||||
kfree(hsotg->last_frame_num_array);
|
||||
kfree(hsotg->frame_num_array);
|
||||
#endif
|
||||
}
|
||||
|
33
sys/external/bsd/dwc2/dist/dwc2_hcd.h
vendored
33
sys/external/bsd/dwc2/dist/dwc2_hcd.h
vendored
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dwc2_hcd.h,v 1.9 2014/09/03 10:00:08 skrll Exp $ */
|
||||
/* $NetBSD: dwc2_hcd.h,v 1.10 2015/08/30 12:59:59 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* hcd.h - DesignWare HS OTG Controller host-mode declarations
|
||||
@ -249,7 +249,8 @@ enum dwc2_transaction_type {
|
||||
* @ntd: Actual number of transfer descriptors in a list
|
||||
* @dw_align_buf: Used instead of original buffer if its physical address
|
||||
* is not dword-aligned
|
||||
* @dw_align_buf_dma: DMA address for align_buf
|
||||
* @dw_align_buf_size: Size of dw_align_buf
|
||||
* @dw_align_buf_dma: DMA address for dw_align_buf
|
||||
* @qtd_list: List of QTDs for this QH
|
||||
* @channel: Host channel currently processing transfers for this QH
|
||||
* @qh_list_entry: Entry for QH in either the periodic or non-periodic
|
||||
@ -284,6 +285,7 @@ struct dwc2_qh {
|
||||
u16 ntd;
|
||||
usb_dma_t dw_align_buf_usbdma;
|
||||
u8 *dw_align_buf;
|
||||
int dw_align_buf_size;
|
||||
dma_addr_t dw_align_buf_dma;
|
||||
struct list_head qtd_list;
|
||||
struct dwc2_host_chan *channel;
|
||||
@ -459,13 +461,8 @@ static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
|
||||
return !dwc2_hcd_is_pipe_in(pipe);
|
||||
}
|
||||
|
||||
extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg,
|
||||
const struct dwc2_core_params *params);
|
||||
extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
|
||||
const struct dwc2_core_params *params);
|
||||
extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
|
||||
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/* Transaction Execution Functions */
|
||||
extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
|
||||
@ -476,6 +473,9 @@ extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
|
||||
/* Schedule Queue Functions */
|
||||
/* Implemented in hcd_queue.c */
|
||||
extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg);
|
||||
extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_hcd_urb *urb,
|
||||
gfp_t mem_flags);
|
||||
extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
|
||||
extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
|
||||
extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
|
||||
@ -484,7 +484,7 @@ extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
|
||||
extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
|
||||
extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
|
||||
struct dwc2_qh **qh, int mem_flags);
|
||||
struct dwc2_qh *qh);
|
||||
|
||||
/* Removes and frees a QTD */
|
||||
extern void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
|
||||
@ -667,9 +667,6 @@ extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg);
|
||||
*/
|
||||
extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg);
|
||||
|
||||
extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
|
||||
extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/**
|
||||
* dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host,
|
||||
* and 0 otherwise
|
||||
@ -678,13 +675,6 @@ extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
|
||||
*/
|
||||
extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/**
|
||||
* dwc2_hcd_get_frame_number() - Returns current frame number
|
||||
*
|
||||
* @hsotg: The DWC2 HCD
|
||||
*/
|
||||
extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
|
||||
|
||||
/**
|
||||
* dwc2_hcd_dump_state() - Dumps hsotg state
|
||||
*
|
||||
@ -774,8 +764,9 @@ int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *, struct dwc2_hcd_urb *);
|
||||
void dwc2_hcd_reinit(struct dwc2_hsotg *);
|
||||
int dwc2_hcd_hub_control(struct dwc2_hsotg *, u16, u16, u16, char *, u16);
|
||||
struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *);
|
||||
int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *, struct dwc2_hcd_urb *, void **,
|
||||
gfp_t);
|
||||
int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_hcd_urb *urb, struct dwc2_qh *qh,
|
||||
struct dwc2_qtd *qtd);
|
||||
void dwc2_hcd_urb_set_pipeinfo(struct dwc2_hsotg *, struct dwc2_hcd_urb *,
|
||||
u8 ,u8, u8, u8, u16);
|
||||
|
||||
|
107
sys/external/bsd/dwc2/dist/dwc2_hcdintr.c
vendored
107
sys/external/bsd/dwc2/dist/dwc2_hcdintr.c
vendored
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dwc2_hcdintr.c,v 1.11 2014/11/24 10:14:14 skrll Exp $ */
|
||||
/* $NetBSD: dwc2_hcdintr.c,v 1.12 2015/08/30 12:59:59 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling
|
||||
@ -40,7 +40,7 @@
|
||||
* This file contains the interrupt handlers for Host mode
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdintr.c,v 1.11 2014/11/24 10:14:14 skrll Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdintr.c,v 1.12 2015/08/30 12:59:59 skrll Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/pool.h>
|
||||
@ -357,6 +357,9 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
|
||||
dev_vdbg(hsotg->dev,
|
||||
"--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
|
||||
hprt0);
|
||||
if (hsotg->lx_state != DWC2_L0)
|
||||
usb_hcd_resume_root_hub(hsotg->priv);
|
||||
|
||||
hsotg->flags.b.port_connect_status_change = 1;
|
||||
hsotg->flags.b.port_connect_status = 1;
|
||||
hprt0_modify |= HPRT0_CONNDET;
|
||||
@ -474,12 +477,17 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
|
||||
}
|
||||
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && xfer_length && chan->ep_is_in) {
|
||||
if (chan->align_buf && xfer_length) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
usb_syncmem(urb->usbdma, 0, urb->length, BUS_DMASYNC_POSTREAD);
|
||||
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
|
||||
xfer_length);
|
||||
usb_syncmem(urb->usbdma, 0, urb->length, BUS_DMASYNC_PREREAD);
|
||||
usb_syncmem(urb->usbdma, 0, chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
||||
if (chan->ep_is_in)
|
||||
memcpy(urb->buf + urb->actual_length,
|
||||
chan->qh->dw_align_buf, xfer_length);
|
||||
usb_syncmem(urb->usbdma, 0, chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
||||
}
|
||||
|
||||
dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
|
||||
@ -564,17 +572,22 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
|
||||
chan, chnum, qtd, halt_status, NULL);
|
||||
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && frame_desc->actual_length &&
|
||||
chan->ep_is_in) {
|
||||
if (chan->align_buf && frame_desc->actual_length) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
|
||||
__func__);
|
||||
usb_syncmem(urb->usbdma, 0, urb->length,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
memcpy(urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset, chan->qh->dw_align_buf,
|
||||
frame_desc->actual_length);
|
||||
usb_syncmem(urb->usbdma, 0, urb->length,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
usb_dma_t *ud = &chan->qh->dw_align_buf_usbdma;
|
||||
|
||||
usb_syncmem(ud, 0, chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
||||
if (chan->ep_is_in)
|
||||
memcpy(urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset,
|
||||
chan->qh->dw_align_buf,
|
||||
frame_desc->actual_length);
|
||||
usb_syncmem(ud, 0, chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
||||
}
|
||||
break;
|
||||
case DWC2_HC_XFER_FRAME_OVERRUN:
|
||||
@ -597,17 +610,22 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
|
||||
chan, chnum, qtd, halt_status, NULL);
|
||||
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && frame_desc->actual_length &&
|
||||
chan->ep_is_in) {
|
||||
if (chan->align_buf && frame_desc->actual_length) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
|
||||
__func__);
|
||||
usb_syncmem(urb->usbdma, 0, urb->length,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
memcpy(urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset, chan->qh->dw_align_buf,
|
||||
frame_desc->actual_length);
|
||||
usb_syncmem(urb->usbdma, 0, urb->length,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
usb_dma_t *ud = &chan->qh->dw_align_buf_usbdma;
|
||||
|
||||
usb_syncmem(ud, 0, chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
||||
if (chan->ep_is_in)
|
||||
memcpy(urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset,
|
||||
chan->qh->dw_align_buf,
|
||||
frame_desc->actual_length);
|
||||
usb_syncmem(ud, 0, chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
||||
}
|
||||
|
||||
/* Skip whole frame */
|
||||
@ -943,12 +961,12 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
|
||||
|
||||
if (chan->align_buf) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
usb_syncmem(qtd->urb->usbdma, 0, qtd->urb->length,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
usb_syncmem(qtd->urb->usbdma, chan->qh->dw_align_buf_dma,
|
||||
chan->qh->dw_align_buf_size, BUS_DMASYNC_POSTREAD);
|
||||
memcpy(qtd->urb->buf + frame_desc->offset +
|
||||
qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
|
||||
usb_syncmem(qtd->urb->usbdma, 0, qtd->urb->length,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
usb_syncmem(qtd->urb->usbdma, chan->qh->dw_align_buf_dma,
|
||||
chan->qh->dw_align_buf_size, BUS_DMASYNC_PREREAD);
|
||||
}
|
||||
|
||||
qtd->isoc_split_offset += len;
|
||||
@ -1175,10 +1193,19 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
|
||||
/* Non DWORD-aligned buffer case handling */
|
||||
if (chan->align_buf && xfer_length && chan->ep_is_in) {
|
||||
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
|
||||
usb_syncmem(urb->usbdma, 0, urb->length, BUS_DMASYNC_POSTREAD);
|
||||
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
|
||||
xfer_length);
|
||||
usb_syncmem(urb->usbdma, 0, urb->length, BUS_DMASYNC_PREREAD);
|
||||
|
||||
usb_dma_t *ud = &chan->qh->dw_align_buf_usbdma;
|
||||
|
||||
usb_syncmem(ud, 0, chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
||||
if (chan->ep_is_in)
|
||||
memcpy(urb->buf + urb->actual_length,
|
||||
chan->qh->dw_align_buf,
|
||||
xfer_length);
|
||||
usb_syncmem(ud, 0, chan->qh->dw_align_buf_size,
|
||||
chan->ep_is_in ?
|
||||
BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
||||
}
|
||||
|
||||
urb->actual_length += xfer_length;
|
||||
@ -1206,6 +1233,16 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_host_chan *chan, int chnum,
|
||||
struct dwc2_qtd *qtd)
|
||||
{
|
||||
if (!qtd) {
|
||||
dev_dbg(hsotg->dev, "%s: qtd is NULL\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!qtd->urb) {
|
||||
dev_dbg(hsotg->dev, "%s: qtd->urb is NULL\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dbg_hc(chan))
|
||||
dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n",
|
||||
chnum);
|
||||
@ -1910,10 +1947,10 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
|
||||
"NYET/NAK/ACK/other in non-error case, 0x%08x\n",
|
||||
chan->hcint);
|
||||
error:
|
||||
/* use the 3-strikes rule */
|
||||
/* Failthrough: use 3-strikes rule */
|
||||
qtd->error_count++;
|
||||
dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb,
|
||||
qtd, DWC2_HC_XFER_XACT_ERR);
|
||||
qtd, DWC2_HC_XFER_XACT_ERR);
|
||||
dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
|
||||
dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR);
|
||||
}
|
||||
|
68
sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c
vendored
68
sys/external/bsd/dwc2/dist/dwc2_hcdqueue.c
vendored
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dwc2_hcdqueue.c,v 1.11 2014/09/03 10:00:08 skrll Exp $ */
|
||||
/* $NetBSD: dwc2_hcdqueue.c,v 1.12 2015/08/30 12:59:59 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* hcd_queue.c - DesignWare HS OTG Controller host queuing routines
|
||||
@ -42,7 +42,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.11 2014/09/03 10:00:08 skrll Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dwc2_hcdqueue.c,v 1.12 2015/08/30 12:59:59 skrll Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/kmem.h>
|
||||
@ -206,7 +206,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
||||
*
|
||||
* Return: Pointer to the newly allocated QH, or NULL on error
|
||||
*/
|
||||
static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
|
||||
struct dwc2_hcd_urb *urb,
|
||||
gfp_t mem_flags)
|
||||
{
|
||||
@ -251,8 +251,8 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
||||
if (hsotg->core_params->dma_desc_enable > 0) {
|
||||
dwc2_hcd_qh_free_ddma(hsotg, qh);
|
||||
} else if (qh->dw_align_buf) {
|
||||
/* XXXNH */
|
||||
usb_freemem(&hsotg->hsotg_sc->sc_bus, &qh->dw_align_buf_usbdma);
|
||||
usb_freemem(&sc->sc_bus, &qh->dw_align_buf_usbdma);
|
||||
qh->dw_align_buf_dma = (dma_addr_t)0;
|
||||
}
|
||||
|
||||
pool_cache_put(sc->sc_qhpool, qh);
|
||||
@ -609,6 +609,7 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
||||
&hsotg->non_periodic_sched_inactive);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = dwc2_schedule_periodic(hsotg, qh);
|
||||
if (status)
|
||||
return status;
|
||||
@ -646,6 +647,7 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
||||
list_del_init(&qh->qh_list_entry);
|
||||
return;
|
||||
}
|
||||
|
||||
dwc2_deschedule_periodic(hsotg, qh);
|
||||
hsotg->periodic_qh_count--;
|
||||
if (!hsotg->periodic_qh_count) {
|
||||
@ -780,63 +782,39 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
|
||||
|
||||
/**
|
||||
* dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
|
||||
* Caller must hold driver lock.
|
||||
*
|
||||
* @hsotg: The DWC HCD structure
|
||||
* @qtd: The QTD to add
|
||||
* @qh: Out parameter to return queue head
|
||||
* @mem_flags: Flag to do atomic alloc if needed
|
||||
* @hsotg: The DWC HCD structure
|
||||
* @qtd: The QTD to add
|
||||
* @qh: Queue head to add qtd to
|
||||
*
|
||||
* Return: 0 if successful, negative error code otherwise
|
||||
*
|
||||
* Finds the correct QH to place the QTD into. If it does not find a QH, it
|
||||
* will create a new QH. If the QH to which the QTD is added is not currently
|
||||
* scheduled, it is placed into the proper schedule based on its EP type.
|
||||
*
|
||||
* HCD lock must be held and interrupts must be disabled on entry
|
||||
* If the QH to which the QTD is added is not currently scheduled, it is placed
|
||||
* into the proper schedule based on its EP type.
|
||||
*/
|
||||
int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
|
||||
struct dwc2_qh **qh, gfp_t mem_flags)
|
||||
struct dwc2_qh *qh)
|
||||
{
|
||||
struct dwc2_hcd_urb *urb = qtd->urb;
|
||||
int allocated = 0;
|
||||
|
||||
KASSERT(mutex_owned(hsotg->lock));
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* Get the QH which holds the QTD-list to insert to. Create QH if it
|
||||
* doesn't exist.
|
||||
*/
|
||||
if (*qh == NULL) {
|
||||
*qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags);
|
||||
if (*qh == NULL)
|
||||
return -ENOMEM;
|
||||
allocated = 1;
|
||||
if (unlikely(!qh)) {
|
||||
dev_err(hsotg->dev, "%s: Invalid QH\n", __func__);
|
||||
retval = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
retval = dwc2_hcd_qh_add(hsotg, *qh);
|
||||
retval = dwc2_hcd_qh_add(hsotg, qh);
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
qtd->qh = *qh;
|
||||
list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
|
||||
qtd->qh = qh;
|
||||
list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (allocated) {
|
||||
struct dwc2_qtd *qtd2, *qtd2_tmp;
|
||||
struct dwc2_qh *qh_tmp = *qh;
|
||||
|
||||
*qh = NULL;
|
||||
dwc2_hcd_qh_unlink(hsotg, qh_tmp);
|
||||
|
||||
/* Free each QTD in the QH's QTD list */
|
||||
list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list,
|
||||
qtd_list_entry)
|
||||
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
|
||||
|
||||
dwc2_hcd_qh_free(hsotg, qh_tmp);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
16
sys/external/bsd/dwc2/dist/dwc2_hw.h
vendored
16
sys/external/bsd/dwc2/dist/dwc2_hw.h
vendored
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dwc2_hw.h,v 1.2 2013/09/25 06:19:22 skrll Exp $ */
|
||||
/* $NetBSD: dwc2_hw.h,v 1.3 2015/08/30 12:59:59 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* hw.h - DesignWare HS OTG Controller hardware definitions
|
||||
@ -111,6 +111,7 @@
|
||||
#define GUSBCFG_FSINTF (1 << 5)
|
||||
#define GUSBCFG_ULPI_UTMI_SEL (1 << 4)
|
||||
#define GUSBCFG_PHYIF16 (1 << 3)
|
||||
#define GUSBCFG_PHYIF8 (0 << 3)
|
||||
#define GUSBCFG_TOUTCAL_MASK (0x7 << 0)
|
||||
#define GUSBCFG_TOUTCAL_SHIFT 0
|
||||
#define GUSBCFG_TOUTCAL_LIMIT 0x7
|
||||
@ -295,6 +296,7 @@
|
||||
#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
|
||||
#define GHWCFG4_NUM_IN_EPS_SHIFT 26
|
||||
#define GHWCFG4_DED_FIFO_EN (1 << 25)
|
||||
#define GHWCFG4_DED_FIFO_SHIFT 25
|
||||
#define GHWCFG4_SESSION_END_FILT_EN (1 << 24)
|
||||
#define GHWCFG4_B_VALID_FILT_EN (1 << 23)
|
||||
#define GHWCFG4_A_VALID_FILT_EN (1 << 22)
|
||||
@ -405,6 +407,7 @@
|
||||
#define FIFOSIZE_DEPTH_SHIFT 16
|
||||
#define FIFOSIZE_STARTADDR_MASK (0xffff << 0)
|
||||
#define FIFOSIZE_STARTADDR_SHIFT 0
|
||||
#define FIFOSIZE_DEPTH_GET(_x) (((_x) >> 16) & 0xffff)
|
||||
|
||||
/* Device mode registers */
|
||||
|
||||
@ -521,11 +524,11 @@
|
||||
#define DXEPCTL_STALL (1 << 21)
|
||||
#define DXEPCTL_SNP (1 << 20)
|
||||
#define DXEPCTL_EPTYPE_MASK (0x3 << 18)
|
||||
#define DXEPCTL_EPTYPE_SHIFT 18
|
||||
#define DXEPCTL_EPTYPE_CONTROL 0
|
||||
#define DXEPCTL_EPTYPE_ISO 1
|
||||
#define DXEPCTL_EPTYPE_BULK 2
|
||||
#define DXEPCTL_EPTYPE_INTTERUPT 3
|
||||
#define DXEPCTL_EPTYPE_CONTROL (0x0 << 18)
|
||||
#define DXEPCTL_EPTYPE_ISO (0x1 << 18)
|
||||
#define DXEPCTL_EPTYPE_BULK (0x2 << 18)
|
||||
#define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18)
|
||||
|
||||
#define DXEPCTL_NAKSTS (1 << 17)
|
||||
#define DXEPCTL_DPID (1 << 16)
|
||||
#define DXEPCTL_EOFRNUM (1 << 16)
|
||||
@ -541,6 +544,7 @@
|
||||
|
||||
#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
|
||||
#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
|
||||
#define DXEPINT_SETUP_RCVD (1 << 15)
|
||||
#define DXEPINT_INEPNAKEFF (1 << 6)
|
||||
#define DXEPINT_BACK2BACKSETUP (1 << 6)
|
||||
#define DXEPINT_INTKNEPMIS (1 << 5)
|
||||
|
Loading…
Reference in New Issue
Block a user