Commit 96e46dcf authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'usb-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

Felipe writes:

USB: Changes for v5.4 merge window

With only 45 non-merge commits, we have a small merge window from the
Gadget perspective.

The biggest change here is the addition of the Cadence USB3 DRD
Driver. All other changes are small, non-critical fixes or smaller new
features like the improvement to BESL handling in dwc3.
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>

* tag 'usb-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (45 commits)
  usb: gadget: net2280: Add workaround for AB chip Errata 11
  usb: gadget: net2280: Move all "ll" registers in one structure
  usb: dwc3: gadget: Workaround Mirosoft's BESL check
  usb:cdns3 Fix for stuck packets in on-chip OUT buffer.
  usb: cdns3: Add Cadence USB3 DRD Driver
  usb: common: Simplify usb_decode_get_set_descriptor function.
  usb: common: Patch simplify usb_decode_set_clear_feature function.
  usb: common: Separated decoding functions from dwc3 driver.
  dt-bindings: add binding for USBSS-DRD controller.
  usb: gadget: composite: Set recommended BESL values
  usb: dwc3: gadget: Set BESL config parameter
  usb: dwc3: Separate field holding multiple properties
  usb: gadget: Export recommended BESL values
  usb: phy: phy-fsl-usb: Make structure fsl_otg_initdata constant
  usb: udc: lpc32xx: silence fall-through warning
  usb: dwc3: meson-g12a: fix suspend resume regulator unbalanced disables
  usb: udc: lpc32xx: remove set but not used 3 variables
  usb: gadget: udc: core: Fix segfault if udc_bind_to_driver() for pending driver fails
  usb: dwc3: st: Add of_dev_put() in probe function
  usb: dwc3: st: Add of_node_put() before return in probe function
  ...
parents b2fcb285 18a93cd3
Binding for the Cadence USBSS-DRD controller
Required properties:
- reg: Physical base address and size of the controller's register areas.
Controller has 3 different regions:
- HOST registers area
- DEVICE registers area
- OTG/DRD registers area
- reg-names - register memory area names:
"xhci" - for HOST registers space
"dev" - for DEVICE registers space
"otg" - for OTG/DRD registers space
- compatible: Should contain: "cdns,usb3"
- interrupts: Interrupts used by cdns3 controller:
"host" - interrupt used by XHCI driver.
"peripheral" - interrupt used by device driver
"otg" - interrupt used by DRD/OTG part of driver
Optional properties:
- maximum-speed : valid arguments are "super-speed", "high-speed" and
"full-speed"; refer to usb/generic.txt
- dr_mode: Should be one of "host", "peripheral" or "otg".
- phys: reference to the USB PHY
- phy-names: from the *Generic PHY* bindings;
Supported names are:
- cdns3,usb2-phy
- cdns3,usb3-phy
- cdns,on-chip-buff-size : size of memory intended as internal memory for endpoints
buffers expressed in KB
Example:
usb@f3000000 {
compatible = "cdns,usb3";
interrupts = <GIC_USB_IRQ 7 IRQ_TYPE_LEVEL_HIGH>,
<GIC_USB_IRQ 7 IRQ_TYPE_LEVEL_HIGH>,
<GIC_USB_IRQ 8 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "host", "peripheral", "otg";
reg = <0xf3000000 0x10000>, /* memory area for HOST registers */
<0xf3010000 0x10000>, /* memory area for DEVICE registers */
<0xf3020000 0x10000>; /* memory area for OTG/DRD registers */
reg-names = "xhci", "dev", "otg";
phys = <&usb2_phy>, <&usb3_phy>;
phy-names = "cdns3,usb2-phy", "cnds3,usb3-phy";
};
...@@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig" ...@@ -112,6 +112,8 @@ source "drivers/usb/usbip/Kconfig"
endif endif
source "drivers/usb/cdns3/Kconfig"
source "drivers/usb/mtu3/Kconfig" source "drivers/usb/mtu3/Kconfig"
source "drivers/usb/musb/Kconfig" source "drivers/usb/musb/Kconfig"
......
...@@ -13,6 +13,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/ ...@@ -13,6 +13,8 @@ obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_DWC2) += dwc2/ obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_USB_ISP1760) += isp1760/ obj-$(CONFIG_USB_ISP1760) += isp1760/
obj-$(CONFIG_USB_CDNS3) += cdns3/
obj-$(CONFIG_USB_MON) += mon/ obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_USB_MTU3) += mtu3/ obj-$(CONFIG_USB_MTU3) += mtu3/
......
config USB_CDNS3
tristate "Cadence USB3 Dual-Role Controller"
depends on USB_SUPPORT && (USB || USB_GADGET) && HAS_DMA
select USB_XHCI_PLATFORM if USB_XHCI_HCD
select USB_ROLE_SWITCH
help
Say Y here if your system has a Cadence USB3 dual-role controller.
It supports: dual-role switch, Host-only, and Peripheral-only.
If you choose to build this driver is a dynamically linked
as module, the module will be called cdns3.ko.
if USB_CDNS3
config USB_CDNS3_GADGET
bool "Cadence USB3 device controller"
depends on USB_GADGET=y || USB_GADGET=USB_CDNS3
help
Say Y here to enable device controller functionality of the
Cadence USBSS-DEV driver.
This controller supports FF, HS and SS mode. It doesn't support
LS and SSP mode.
config USB_CDNS3_HOST
bool "Cadence USB3 host controller"
depends on USB=y || USB=USB_CDNS3
help
Say Y here to enable host controller functionality of the
Cadence driver.
Host controller is compliant with XHCI so it will use
standard XHCI driver.
config USB_CDNS3_PCI_WRAP
tristate "Cadence USB3 support on PCIe-based platforms"
depends on USB_PCI && ACPI
default USB_CDNS3
help
If you're using the USBSS Core IP with a PCIe, please say
'Y' or 'M' here.
If you choose to build this driver as module it will
be dynamically linked and module will be called cdns3-pci.ko
endif
# SPDX-License-Identifier: GPL-2.0
# define_trace.h needs to know how to find our header
CFLAGS_trace.o := -I$(src)
cdns3-y := core.o drd.o
obj-$(CONFIG_USB_CDNS3) += cdns3.o
cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o ep0.o
ifneq ($(CONFIG_USB_CDNS3_GADGET),)
cdns3-$(CONFIG_TRACING) += trace.o
endif
cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o
obj-$(CONFIG_USB_CDNS3_PCI_WRAP) += cdns3-pci-wrap.o
// SPDX-License-Identifier: GPL-2.0
/*
* Cadence USBSS PCI Glue driver
*
* Copyright (C) 2018-2019 Cadence.
*
* Author: Pawel Laszczak <pawell@cadence.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
struct cdns3_wrap {
struct platform_device *plat_dev;
struct resource dev_res[6];
int devfn;
};
#define RES_IRQ_HOST_ID 0
#define RES_IRQ_PERIPHERAL_ID 1
#define RES_IRQ_OTG_ID 2
#define RES_HOST_ID 3
#define RES_DEV_ID 4
#define RES_DRD_ID 5
#define PCI_BAR_HOST 0
#define PCI_BAR_DEV 2
#define PCI_BAR_OTG 0
#define PCI_DEV_FN_HOST_DEVICE 0
#define PCI_DEV_FN_OTG 1
#define PCI_DRIVER_NAME "cdns3-pci-usbss"
#define PLAT_DRIVER_NAME "cdns-usb3"
#define CDNS_VENDOR_ID 0x17cd
#define CDNS_DEVICE_ID 0x0100
static struct pci_dev *cdns3_get_second_fun(struct pci_dev *pdev)
{
struct pci_dev *func;
/*
* Gets the second function.
* It's little tricky, but this platform has two function.
* The fist keeps resources for Host/Device while the second
* keeps resources for DRD/OTG.
*/
func = pci_get_device(pdev->vendor, pdev->device, NULL);
if (unlikely(!func))
return NULL;
if (func->devfn == pdev->devfn) {
func = pci_get_device(pdev->vendor, pdev->device, func);
if (unlikely(!func))
return NULL;
}
return func;
}
static int cdns3_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct platform_device_info plat_info;
struct cdns3_wrap *wrap;
struct resource *res;
struct pci_dev *func;
int err;
/*
* for GADGET/HOST PCI (devfn) function number is 0,
* for OTG PCI (devfn) function number is 1
*/
if (!id || (pdev->devfn != PCI_DEV_FN_HOST_DEVICE &&
pdev->devfn != PCI_DEV_FN_OTG))
return -EINVAL;
func = cdns3_get_second_fun(pdev);
if (unlikely(!func))
return -EINVAL;
err = pcim_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err);
return err;
}
pci_set_master(pdev);
if (pci_is_enabled(func)) {
wrap = pci_get_drvdata(func);
} else {
wrap = kzalloc(sizeof(*wrap), GFP_KERNEL);
if (!wrap) {
pci_disable_device(pdev);
return -ENOMEM;
}
}
res = wrap->dev_res;
if (pdev->devfn == PCI_DEV_FN_HOST_DEVICE) {
/* function 0: host(BAR_0) + device(BAR_1).*/
dev_dbg(&pdev->dev, "Initialize Device resources\n");
res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV);
res[RES_DEV_ID].end = pci_resource_end(pdev, PCI_BAR_DEV);
res[RES_DEV_ID].name = "dev";
res[RES_DEV_ID].flags = IORESOURCE_MEM;
dev_dbg(&pdev->dev, "USBSS-DEV physical base addr: %pa\n",
&res[RES_DEV_ID].start);
res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST);
res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST);
res[RES_HOST_ID].name = "xhci";
res[RES_HOST_ID].flags = IORESOURCE_MEM;
dev_dbg(&pdev->dev, "USBSS-XHCI physical base addr: %pa\n",
&res[RES_HOST_ID].start);
/* Interrupt for XHCI */
wrap->dev_res[RES_IRQ_HOST_ID].start = pdev->irq;
wrap->dev_res[RES_IRQ_HOST_ID].name = "host";
wrap->dev_res[RES_IRQ_HOST_ID].flags = IORESOURCE_IRQ;
/* Interrupt device. It's the same as for HOST. */
wrap->dev_res[RES_IRQ_PERIPHERAL_ID].start = pdev->irq;
wrap->dev_res[RES_IRQ_PERIPHERAL_ID].name = "peripheral";
wrap->dev_res[RES_IRQ_PERIPHERAL_ID].flags = IORESOURCE_IRQ;
} else {
res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG);
res[RES_DRD_ID].end = pci_resource_end(pdev, PCI_BAR_OTG);
res[RES_DRD_ID].name = "otg";
res[RES_DRD_ID].flags = IORESOURCE_MEM;
dev_dbg(&pdev->dev, "USBSS-DRD physical base addr: %pa\n",
&res[RES_DRD_ID].start);
/* Interrupt for OTG/DRD. */
wrap->dev_res[RES_IRQ_OTG_ID].start = pdev->irq;
wrap->dev_res[RES_IRQ_OTG_ID].name = "otg";
wrap->dev_res[RES_IRQ_OTG_ID].flags = IORESOURCE_IRQ;
}
if (pci_is_enabled(func)) {
/* set up platform device info */
memset(&plat_info, 0, sizeof(plat_info));
plat_info.parent = &pdev->dev;
plat_info.fwnode = pdev->dev.fwnode;
plat_info.name = PLAT_DRIVER_NAME;
plat_info.id = pdev->devfn;
wrap->devfn = pdev->devfn;
plat_info.res = wrap->dev_res;
plat_info.num_res = ARRAY_SIZE(wrap->dev_res);
plat_info.dma_mask = pdev->dma_mask;
/* register platform device */
wrap->plat_dev = platform_device_register_full(&plat_info);
if (IS_ERR(wrap->plat_dev)) {
pci_disable_device(pdev);
kfree(wrap);
return PTR_ERR(wrap->plat_dev);
}
}
pci_set_drvdata(pdev, wrap);
return err;
}
static void cdns3_pci_remove(struct pci_dev *pdev)
{
struct cdns3_wrap *wrap;
struct pci_dev *func;
func = cdns3_get_second_fun(pdev);
wrap = (struct cdns3_wrap *)pci_get_drvdata(pdev);
if (wrap->devfn == pdev->devfn)
platform_device_unregister(wrap->plat_dev);
if (!pci_is_enabled(func))
kfree(wrap);
}
static const struct pci_device_id cdns3_pci_ids[] = {
{ PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), },
{ 0, }
};
static struct pci_driver cdns3_pci_driver = {
.name = PCI_DRIVER_NAME,
.id_table = cdns3_pci_ids,
.probe = cdns3_pci_probe,
.remove = cdns3_pci_remove,
};
module_pci_driver(cdns3_pci_driver);
MODULE_DEVICE_TABLE(pci, cdns3_pci_ids);
MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Cadence USBSS PCI wrapperr");
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Cadence USBSS DRD Header File.
*
* Copyright (C) 2017-2018 NXP
* Copyright (C) 2018-2019 Cadence.
*
* Authors: Peter Chen <peter.chen@nxp.com>
* Pawel Laszczak <pawell@cadence.com>
*/
#include <linux/usb/otg.h>
#include <linux/usb/role.h>
#ifndef __LINUX_CDNS3_CORE_H
#define __LINUX_CDNS3_CORE_H
struct cdns3;
/**
* struct cdns3_role_driver - host/gadget role driver
* @start: start this role
* @stop: stop this role
* @suspend: suspend callback for this role
* @resume: resume callback for this role
* @irq: irq handler for this role
* @name: role name string (host/gadget)
* @state: current state
*/
struct cdns3_role_driver {
int (*start)(struct cdns3 *cdns);
void (*stop)(struct cdns3 *cdns);
int (*suspend)(struct cdns3 *cdns, bool do_wakeup);
int (*resume)(struct cdns3 *cdns, bool hibernated);
const char *name;
#define CDNS3_ROLE_STATE_INACTIVE 0
#define CDNS3_ROLE_STATE_ACTIVE 1
int state;
};
#define CDNS3_XHCI_RESOURCES_NUM 2
/**
* struct cdns3 - Representation of Cadence USB3 DRD controller.
* @dev: pointer to Cadence device struct
* @xhci_regs: pointer to base of xhci registers
* @xhci_res: the resource for xhci
* @dev_regs: pointer to base of dev registers
* @otg_res: the resource for otg
* @otg_v0_regs: pointer to base of v0 otg registers
* @otg_v1_regs: pointer to base of v1 otg registers
* @otg_regs: pointer to base of otg registers
* @otg_irq: irq number for otg controller
* @dev_irq: irq number for device controller
* @roles: array of supported roles for this controller
* @role: current role
* @host_dev: the child host device pointer for cdns3 core
* @gadget_dev: the child gadget device pointer for cdns3 core
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
* @mutex: the mutex for concurrent code at driver
* @dr_mode: supported mode of operation it can be only Host, only Device
* or OTG mode that allow to switch between Device and Host mode.
* This field based on firmware setting, kernel configuration
* and hardware configuration.
* @role_sw: pointer to role switch object.
* @role_override: set 1 if role rely on SW.
*/
struct cdns3 {
struct device *dev;
void __iomem *xhci_regs;
struct resource xhci_res[CDNS3_XHCI_RESOURCES_NUM];
struct cdns3_usb_regs __iomem *dev_regs;
struct resource otg_res;
struct cdns3_otg_legacy_regs *otg_v0_regs;
struct cdns3_otg_regs *otg_v1_regs;
struct cdns3_otg_common_regs *otg_regs;
#define CDNS3_CONTROLLER_V0 0
#define CDNS3_CONTROLLER_V1 1
u32 version;
int otg_irq;
int dev_irq;
struct cdns3_role_driver *roles[USB_ROLE_DEVICE + 1];
enum usb_role role;
struct platform_device *host_dev;
struct cdns3_device *gadget_dev;
struct phy *usb2_phy;
struct phy *usb3_phy;
/* mutext used in workqueue*/
struct mutex mutex;
enum usb_dr_mode dr_mode;
struct usb_role_switch *role_sw;
int role_override;
};
int cdns3_hw_role_switch(struct cdns3 *cdns);
#endif /* __LINUX_CDNS3_CORE_H */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Cadence USBSS DRD Driver.
* Debug header file.
*
* Copyright (C) 2018-2019 Cadence.
*
* Author: Pawel Laszczak <pawell@cadence.com>
*/
#ifndef __LINUX_CDNS3_DEBUG
#define __LINUX_CDNS3_DEBUG
#include "core.h"
static inline char *cdns3_decode_usb_irq(char *str,
enum usb_device_speed speed,
u32 usb_ists)
{
int ret;
ret = sprintf(str, "IRQ %08x = ", usb_ists);
if (usb_ists & (USB_ISTS_CON2I | USB_ISTS_CONI)) {
ret += sprintf(str + ret, "Connection %s\n",
usb_speed_string(speed));
}
if (usb_ists & USB_ISTS_DIS2I || usb_ists & USB_ISTS_DISI)
ret += sprintf(str + ret, "Disconnection ");
if (usb_ists & USB_ISTS_L2ENTI)
ret += sprintf(str + ret, "suspended ");
if (usb_ists & USB_ISTS_L1ENTI)
ret += sprintf(str + ret, "L1 enter ");
if (usb_ists & USB_ISTS_L1EXTI)
ret += sprintf(str + ret, "L1 exit ");
if (usb_ists & USB_ISTS_L2ENTI)
ret += sprintf(str + ret, "L2 enter ");
if (usb_ists & USB_ISTS_L2EXTI)
ret += sprintf(str + ret, "L2 exit ");
if (usb_ists & USB_ISTS_U3EXTI)
ret += sprintf(str + ret, "U3 exit ");
if (usb_ists & USB_ISTS_UWRESI)
ret += sprintf(str + ret, "Warm Reset ");
if (usb_ists & USB_ISTS_UHRESI)
ret += sprintf(str + ret, "Hot Reset ");
if (usb_ists & USB_ISTS_U2RESI)
ret += sprintf(str + ret, "Reset");
return str;
}
static inline char *cdns3_decode_ep_irq(char *str,
u32 ep_sts,
const char *ep_name)
{
int ret;
ret = sprintf(str, "IRQ for %s: %08x ", ep_name, ep_sts);
if (ep_sts & EP_STS_SETUP)
ret += sprintf(str + ret, "SETUP ");
if (ep_sts & EP_STS_IOC)
ret += sprintf(str + ret, "IOC ");
if (ep_sts & EP_STS_ISP)
ret += sprintf(str + ret, "ISP ");
if (ep_sts & EP_STS_DESCMIS)
ret += sprintf(str + ret, "DESCMIS ");
if (ep_sts & EP_STS_STREAMR)
ret += sprintf(str + ret, "STREAMR ");
if (ep_sts & EP_STS_MD_EXIT)
ret += sprintf(str + ret, "MD_EXIT ");
if (ep_sts & EP_STS_TRBERR)
ret += sprintf(str + ret, "TRBERR ");
if (ep_sts & EP_STS_NRDY)
ret += sprintf(str + ret, "NRDY ");
if (ep_sts & EP_STS_PRIME)
ret += sprintf(str + ret, "PRIME ");
if (ep_sts & EP_STS_SIDERR)
ret += sprintf(str + ret, "SIDERRT ");
if (ep_sts & EP_STS_OUTSMM)
ret += sprintf(str + ret, "OUTSMM ");
if (ep_sts & EP_STS_ISOERR)
ret += sprintf(str + ret, "ISOERR ");
if (ep_sts & EP_STS_IOT)
ret += sprintf(str + ret, "IOT ");
return str;
}
static inline char *cdns3_decode_epx_irq(char *str,
char *ep_name,
u32 ep_sts)
{
return cdns3_decode_ep_irq(str, ep_sts, ep_name);
}
static inline char *cdns3_decode_ep0_irq(char *str,
int dir,
u32 ep_sts)
{
return cdns3_decode_ep_irq(str, ep_sts,
dir ? "ep0IN" : "ep0OUT");
}
/**
* Debug a transfer ring.
*
* Prints out all TRBs in the endpoint ring, even those after the Link TRB.
*.
*/
static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep,
struct cdns3_trb *ring, char *str)
{
dma_addr_t addr = priv_ep->trb_pool_dma;
struct cdns3_trb *trb;
int trb_per_sector;
int ret = 0;
int i;
trb_per_sector = GET_TRBS_PER_SEGMENT(priv_ep->type);
trb = &priv_ep->trb_pool[priv_ep->dequeue];
ret += sprintf(str + ret, "\n\t\tRing contents for %s:", priv_ep->name);
ret += sprintf(str + ret,
"\n\t\tRing deq index: %d, trb: %p (virt), 0x%llx (dma)\n",
priv_ep->dequeue, trb,
(unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb));
trb = &priv_ep->trb_pool[priv_ep->enqueue];
ret += sprintf(str + ret,
"\t\tRing enq index: %d, trb: %p (virt), 0x%llx (dma)\n",
priv_ep->enqueue, trb,
(unsigned long long)cdns3_trb_virt_to_dma(priv_ep, trb));
ret += sprintf(str + ret,
"\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs);
if (trb_per_sector > TRBS_PER_SEGMENT)
trb_per_sector = TRBS_PER_SEGMENT;
if (trb_per_sector > TRBS_PER_SEGMENT) {
sprintf(str + ret, "\t\tTo big transfer ring %d\n",
trb_per_sector);
return str;
}
for (i = 0; i < trb_per_sector; ++i) {
trb = &ring[i];
ret += sprintf(str + ret,
"\t\t@%pad %08x %08x %08x\n", &addr,
le32_to_cpu(trb->buffer),
le32_to_cpu(trb->length),
le32_to_cpu(trb->control));
addr += sizeof(*trb);
}
return str;
}
#endif /*__LINUX_CDNS3_DEBUG*/
// SPDX-License-Identifier: GPL-2.0
/*
* Cadence USBSS DRD Driver.
*
* Copyright (C) 2018-2019 Cadence.
* Copyright (C) 2019 Texas Instruments
*
* Author: Pawel Laszczak <pawell@cadence.com>
* Roger Quadros <rogerq@ti.com>
*
*
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/usb/otg.h>
#include "gadget.h"
#include "drd.h"
#include "core.h"
/**
* cdns3_set_mode - change mode of OTG Core
* @cdns: pointer to context structure
* @mode: selected mode from cdns_role
*
* Returns 0 on success otherwise negative errno
*/
int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode)
{
int ret = 0;
u32 reg;
switch (mode) {
case USB_DR_MODE_PERIPHERAL:
break;
case USB_DR_MODE_HOST:
break;
case USB_DR_MODE_OTG:
dev_dbg(cdns->dev, "Set controller to OTG mode\n");
if (cdns->version == CDNS3_CONTROLLER_V1) {
reg = readl(&cdns->otg_v1_regs->override);
reg |= OVERRIDE_IDPULLUP;
writel(reg, &cdns->otg_v1_regs->override);
} else {
reg = readl(&cdns->otg_v0_regs->ctrl1);
reg |= OVERRIDE_IDPULLUP_V0;
writel(reg, &cdns->otg_v0_regs->ctrl1);
}
/*
* Hardware specification says: "ID_VALUE must be valid within
* 50ms after idpullup is set to '1" so driver must wait
* 50ms before reading this pin.
*/
usleep_range(50000, 60000);
break;
default:
dev_err(cdns->dev, "Unsupported mode of operation %d\n", mode);
return -EINVAL;
}
return ret;
}
int cdns3_get_id(struct cdns3 *cdns)
{
int id;
id = readl(&cdns->otg_regs->sts) & OTGSTS_ID_VALUE;
dev_dbg(cdns->dev, "OTG ID: %d", id);
return id;
}
int cdns3_get_vbus(struct cdns3 *cdns)
{
int vbus;
vbus = !!(readl(&cdns->otg_regs->sts) & OTGSTS_VBUS_VALID);
dev_dbg(cdns->dev, "OTG VBUS: %d", vbus);
return vbus;
}
int cdns3_is_host(struct cdns3 *cdns)
{
if (cdns->dr_mode == USB_DR_MODE_HOST)
return 1;
else if (!cdns3_get_id(cdns))
return 1;
return 0;
}
int cdns3_is_device(struct cdns3 *cdns)
{
if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL)
return 1;
else if (cdns->dr_mode == USB_DR_MODE_OTG)
if (cdns3_get_id(cdns))
return 1;
return 0;
}
/**
* cdns3_otg_disable_irq - Disable all OTG interrupts
* @cdns: Pointer to controller context structure
*/
static void cdns3_otg_disable_irq(struct cdns3 *cdns)
{
writel(0, &cdns->otg_regs->ien);
}
/**
* cdns3_otg_enable_irq - enable id and sess_valid interrupts
* @cdns: Pointer to controller context structure
*/
static void cdns3_otg_enable_irq(struct cdns3 *cdns)
{
writel(OTGIEN_ID_CHANGE_INT | OTGIEN_VBUSVALID_RISE_INT |
OTGIEN_VBUSVALID_FALL_INT, &cdns->otg_regs->ien);
}
/**
* cdns3_drd_switch_host - start/stop host
* @cdns: Pointer to controller context structure
* @on: 1 for start, 0 for stop
*
* Returns 0 on success otherwise negative errno
*/
int cdns3_drd_switch_host(struct cdns3 *cdns, int on)
{
int ret, val;
u32 reg = OTGCMD_OTG_DIS;
/* switch OTG core */
if (on) {
writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd);
dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n");
ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
val & OTGSTS_XHCI_READY,
1, 100000);
if (ret) {
dev_err(cdns->dev, "timeout waiting for xhci_ready\n");
return ret;
}
} else {
writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
&cdns->otg_regs->cmd);
/* Waiting till H_IDLE state.*/
readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
!(val & OTGSTATE_HOST_STATE_MASK),
1, 2000000);
}
return 0;
}
/**
* cdns3_drd_switch_gadget - start/stop gadget
* @cdns: Pointer to controller context structure
* @on: 1 for start, 0 for stop
*
* Returns 0 on success otherwise negative errno
*/
int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on)
{
int ret, val;
u32 reg = OTGCMD_OTG_DIS;
/* switch OTG core */
if (on) {
writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd);
dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n");
ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
val & OTGSTS_DEV_READY,
1, 100000);
if (ret) {
dev_err(cdns->dev, "timeout waiting for dev_ready\n");
return ret;
}
} else {
/*
* driver should wait at least 10us after disabling Device
* before turning-off Device (DEV_BUS_DROP)
*/
usleep_range(20, 30);
writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
&cdns->otg_regs->cmd);
/* Waiting till DEV_IDLE state.*/
readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
!(val & OTGSTATE_DEV_STATE_MASK),
1, 2000000);
}
return 0;
}
/**
* cdns3_init_otg_mode - initialize drd controller
* @cdns: Pointer to controller context structure
*
* Returns 0 on success otherwise negative errno
*/
static int cdns3_init_otg_mode(struct cdns3 *cdns)
{
int ret = 0;
cdns3_otg_disable_irq(cdns);
/* clear all interrupts */
writel(~0, &cdns->otg_regs->ivect);
ret = cdns3_set_mode(cdns, USB_DR_MODE_OTG);
if (ret)
return ret;
cdns3_otg_enable_irq(cdns);
return ret;
}
/**
* cdns3_drd_update_mode - initialize mode of operation
* @cdns: Pointer to controller context structure
*
* Returns 0 on success otherwise negative errno
*/
int cdns3_drd_update_mode(struct cdns3 *cdns)
{
int ret = 0;
switch (cdns->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL);
break;
case USB_DR_MODE_HOST:
ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST);
break;
case USB_DR_MODE_OTG:
ret = cdns3_init_otg_mode(cdns);
break;
default:
dev_err(cdns->dev, "Unsupported mode of operation %d\n",
cdns->dr_mode);
return -EINVAL;
}
return ret;
}
static irqreturn_t cdns3_drd_thread_irq(int irq, void *data)
{
struct cdns3 *cdns = data;
cdns3_hw_role_switch(cdns);
return IRQ_HANDLED;
}
/**
* cdns3_drd_irq - interrupt handler for OTG events
*
* @irq: irq number for cdns3 core device
* @data: structure of cdns3
*
* Returns IRQ_HANDLED or IRQ_NONE
*/
static irqreturn_t cdns3_drd_irq(int irq, void *data)
{
irqreturn_t ret = IRQ_NONE;
struct cdns3 *cdns = data;
u32 reg;
if (cdns->dr_mode != USB_DR_MODE_OTG)
return ret;
reg = readl(&cdns->otg_regs->ivect);
if (!reg)
return ret;
if (reg & OTGIEN_ID_CHANGE_INT) {
dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n",
cdns3_get_id(cdns));
ret = IRQ_WAKE_THREAD;
}
if (reg & (OTGIEN_VBUSVALID_RISE_INT | OTGIEN_VBUSVALID_FALL_INT)) {
dev_dbg(cdns->dev, "OTG IRQ: new VBUS: %d\n",
cdns3_get_vbus(cdns));
ret = IRQ_WAKE_THREAD;
}
writel(~0, &cdns->otg_regs->ivect);
return ret;
}
int cdns3_drd_init(struct cdns3 *cdns)
{
void __iomem *regs;
int ret = 0;
u32 state;
regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res);
if (IS_ERR(regs))
return PTR_ERR(regs);
/* Detection of DRD version. Controller has been released
* in two versions. Both are similar, but they have same changes
* in register maps.
* The first register in old version is command register and it's read
* only, so driver should read 0 from it. On the other hand, in v1
* the first register contains device ID number which is not set to 0.
* Driver uses this fact to detect the proper version of
* controller.
*/
cdns->otg_v0_regs = regs;
if (!readl(&cdns->otg_v0_regs->cmd)) {
cdns->version = CDNS3_CONTROLLER_V0;
cdns->otg_v1_regs = NULL;
cdns->otg_regs = regs;
writel(1, &cdns->otg_v0_regs->simulate);
dev_info(cdns->dev, "DRD version v0 (%08x)\n",
readl(&cdns->otg_v0_regs->version));
} else {
cdns->otg_v0_regs = NULL;
cdns->otg_v1_regs = regs;
cdns->otg_regs = (void *)&cdns->otg_v1_regs->cmd;
cdns->version = CDNS3_CONTROLLER_V1;
writel(1, &cdns->otg_v1_regs->simulate);
dev_info(cdns->dev, "DRD version v1 (ID: %08x, rev: %08x)\n",
readl(&cdns->otg_v1_regs->did),
readl(&cdns->otg_v1_regs->rid));
}
state = OTGSTS_STRAP(readl(&cdns->otg_regs->sts));
/* Update dr_mode according to STRAP configuration. */
cdns->dr_mode = USB_DR_MODE_OTG;
if (state == OTGSTS_STRAP_HOST) {
dev_dbg(cdns->dev, "Controller strapped to HOST\n");
cdns->dr_mode = USB_DR_MODE_HOST;
} else if (state == OTGSTS_STRAP_GADGET) {
dev_dbg(cdns->dev, "Controller strapped to PERIPHERAL\n");
cdns->dr_mode = USB_DR_MODE_PERIPHERAL;
}
ret = devm_request_threaded_irq(cdns->dev, cdns->otg_irq,
cdns3_drd_irq,
cdns3_drd_thread_irq,
IRQF_SHARED,
dev_name(cdns->dev), cdns);
if (ret) {
dev_err(cdns->dev, "couldn't get otg_irq\n");
return ret;
}
state = readl(&cdns->otg_regs->sts);
if (OTGSTS_OTG_NRDY(state) != 0) {
dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n");
return -ENODEV;
}
return ret;
}
int cdns3_drd_exit(struct cdns3 *cdns)
{
cdns3_otg_disable_irq(cdns);
return 0;
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Cadence USB3 DRD header file.
*
* Copyright (C) 2018-2019 Cadence.
*
* Author: Pawel Laszczak <pawell@cadence.com>
*/
#ifndef __LINUX_CDNS3_DRD
#define __LINUX_CDNS3_DRD
#include <linux/usb/otg.h>
#include <linux/phy/phy.h>
#include "core.h"
/* DRD register interface for version v1. */
struct cdns3_otg_regs {
__le32 did;
__le32 rid;
__le32 capabilities;
__le32 reserved1;
__le32 cmd;
__le32 sts;
__le32 state;
__le32 reserved2;
__le32 ien;
__le32 ivect;
__le32 refclk;
__le32 tmr;
__le32 reserved3[4];
__le32 simulate;
__le32 override;
__le32 susp_ctrl;
__le32 reserved4;
__le32 anasts;
__le32 adp_ramp_time;
__le32 ctrl1;
__le32 ctrl2;
};
/* DRD register interface for version v0. */
struct cdns3_otg_legacy_regs {
__le32 cmd;
__le32 sts;
__le32 state;
__le32 refclk;
__le32 ien;
__le32 ivect;
__le32 reserved1[3];
__le32 tmr;
__le32 reserved2[2];
__le32 version;
__le32 capabilities;
__le32 reserved3[2];
__le32 simulate;
__le32 reserved4[5];
__le32 ctrl1;
};
/*
* Common registers interface for both version of DRD.
*/
struct cdns3_otg_common_regs {
__le32 cmd;
__le32 sts;
__le32 state;
__le32 different1;
__le32 ien;
__le32 ivect;
};
/* CDNS_RID - bitmasks */
#define CDNS_RID(p) ((p) & GENMASK(15, 0))
/* CDNS_VID - bitmasks */
#define CDNS_DID(p) ((p) & GENMASK(31, 0))
/* OTGCMD - bitmasks */
/* "Request the bus for Device mode. */
#define OTGCMD_DEV_BUS_REQ BIT(0)
/* Request the bus for Host mode */
#define OTGCMD_HOST_BUS_REQ BIT(1)
/* Enable OTG mode. */
#define OTGCMD_OTG_EN BIT(2)
/* Disable OTG mode */
#define OTGCMD_OTG_DIS BIT(3)
/*"Configure OTG as A-Device. */
#define OTGCMD_A_DEV_EN BIT(4)
/*"Configure OTG as A-Device. */
#define OTGCMD_A_DEV_DIS BIT(5)
/* Drop the bus for Device mod e. */
#define OTGCMD_DEV_BUS_DROP BIT(8)
/* Drop the bus for Host mode*/
#define OTGCMD_HOST_BUS_DROP BIT(9)
/* Power Down USBSS-DEV. */
#define OTGCMD_DEV_POWER_OFF BIT(11)
/* Power Down CDNSXHCI. */
#define OTGCMD_HOST_POWER_OFF BIT(12)
/* OTGIEN - bitmasks */
/* ID change interrupt enable */
#define OTGIEN_ID_CHANGE_INT BIT(0)
/* Vbusvalid fall detected interrupt enable.*/
#define OTGIEN_VBUSVALID_RISE_INT BIT(4)
/* Vbusvalid fall detected interrupt enable */
#define OTGIEN_VBUSVALID_FALL_INT BIT(5)
/* OTGSTS - bitmasks */
/*
* Current value of the ID pin. It is only valid when idpullup in
* OTGCTRL1_TYPE register is set to '1'.
*/
#define OTGSTS_ID_VALUE BIT(0)
/* Current value of the vbus_valid */
#define OTGSTS_VBUS_VALID BIT(1)
/* Current value of the b_sess_vld */
#define OTGSTS_SESSION_VALID BIT(2)
/*Device mode is active*/
#define OTGSTS_DEV_ACTIVE BIT(3)
/* Host mode is active. */
#define OTGSTS_HOST_ACTIVE BIT(4)
/* OTG Controller not ready. */
#define OTGSTS_OTG_NRDY_MASK BIT(11)
#define OTGSTS_OTG_NRDY(p) ((p) & OTGSTS_OTG_NRDY_MASK)
/*
* Value of the strap pins.
* 000 - no default configuration
* 010 - Controller initiall configured as Host
* 100 - Controller initially configured as Device
*/
#define OTGSTS_STRAP(p) (((p) & GENMASK(14, 12)) >> 12)
#define OTGSTS_STRAP_NO_DEFAULT_CFG 0x00
#define OTGSTS_STRAP_HOST_OTG 0x01
#define OTGSTS_STRAP_HOST 0x02
#define OTGSTS_STRAP_GADGET 0x04
/* Host mode is turned on. */
#define OTGSTS_XHCI_READY BIT(26)
/* "Device mode is turned on .*/
#define OTGSTS_DEV_READY BIT(27)
/* OTGSTATE- bitmasks */
#define OTGSTATE_DEV_STATE_MASK GENMASK(2, 0)
#define OTGSTATE_HOST_STATE_MASK GENMASK(5, 3)
#define OTGSTATE_HOST_STATE_IDLE 0x0
#define OTGSTATE_HOST_STATE_VBUS_FALL 0x7
#define OTGSTATE_HOST_STATE(p) (((p) & OTGSTATE_HOST_STATE_MASK) >> 3)
/* OTGREFCLK - bitmasks */
#define OTGREFCLK_STB_CLK_SWITCH_EN BIT(31)
/* OVERRIDE - bitmasks */
#define OVERRIDE_IDPULLUP BIT(0)
/* Only for CDNS3_CONTROLLER_V0 version */
#define OVERRIDE_IDPULLUP_V0 BIT(24)
int cdns3_is_host(struct cdns3 *cdns);
int cdns3_is_device(struct cdns3 *cdns);
int cdns3_get_id(struct cdns3 *cdns);
int cdns3_get_vbus(struct cdns3 *cdns);
int cdns3_drd_init(struct cdns3 *cdns);
int cdns3_drd_exit(struct cdns3 *cdns);
int cdns3_drd_update_mode(struct cdns3 *cdns);
int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on);
int cdns3_drd_switch_host(struct cdns3 *cdns, int on);
int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode);
#endif /* __LINUX_CDNS3_DRD */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Cadence USBSS DRD Driver - Gadget Export APIs.
*
* Copyright (C) 2017 NXP
* Copyright (C) 2017-2018 NXP
*
* Authors: Peter Chen <peter.chen@nxp.com>
*/
#ifndef __LINUX_CDNS3_GADGET_EXPORT
#define __LINUX_CDNS3_GADGET_EXPORT
#ifdef CONFIG_USB_CDNS3_GADGET
int cdns3_gadget_init(struct cdns3 *cdns);
void cdns3_gadget_exit(struct cdns3 *cdns);
#else
static inline int cdns3_gadget_init(struct cdns3 *cdns)
{
return -ENXIO;
}
static inline void cdns3_gadget_exit(struct cdns3 *cdns) { }
#endif
#endif /* __LINUX_CDNS3_GADGET_EXPORT */
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Cadence USBSS DRD Driver - Host Export APIs
*
* Copyright (C) 2017-2018 NXP
*
* Authors: Peter Chen <peter.chen@nxp.com>
*/
#ifndef __LINUX_CDNS3_HOST_EXPORT
#define __LINUX_CDNS3_HOST_EXPORT
#ifdef CONFIG_USB_CDNS3_HOST
int cdns3_host_init(struct cdns3 *cdns);
void cdns3_host_exit(struct cdns3 *cdns);
#else
static inline int cdns3_host_init(struct cdns3 *cdns)
{
return -ENXIO;
}
static inline void cdns3_host_exit(struct cdns3 *cdns) { }
#endif /* CONFIG_USB_CDNS3_HOST */
#endif /* __LINUX_CDNS3_HOST_EXPORT */
// SPDX-License-Identifier: GPL-2.0
/*
* Cadence USBSS DRD Driver - host side
*
* Copyright (C) 2018-2019 Cadence Design Systems.
* Copyright (C) 2017-2018 NXP
*
* Authors: Peter Chen <peter.chen@nxp.com>
* Pawel Laszczak <pawell@cadence.com>
*/
#include <linux/platform_device.h>
#include "core.h"
#include "drd.h"
static int __cdns3_host_init(struct cdns3 *cdns)
{
struct platform_device *xhci;
int ret;
cdns3_drd_switch_host(cdns, 1);
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
if (!xhci) {
dev_err(cdns->dev, "couldn't allocate xHCI device\n");
return -ENOMEM;
}
xhci->dev.parent = cdns->dev;
cdns->host_dev = xhci;
ret = platform_device_add_resources(xhci, cdns->xhci_res,
CDNS3_XHCI_RESOURCES_NUM);
if (ret) {
dev_err(cdns->dev, "couldn't add resources to xHCI device\n");
goto err1;
}
ret = platform_device_add(xhci);
if (ret) {
dev_err(cdns->dev, "failed to register xHCI device\n");
goto err1;
}
return 0;
err1:
platform_device_put(xhci);
return ret;
}
static void cdns3_host_exit(struct cdns3 *cdns)
{
platform_device_unregister(cdns->host_dev);
cdns->host_dev = NULL;
cdns3_drd_switch_host(cdns, 0);
}
int cdns3_host_init(struct cdns3 *cdns)
{
struct cdns3_role_driver *rdrv;
rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
if (!rdrv)
return -ENOMEM;
rdrv->start = __cdns3_host_init;
rdrv->stop = cdns3_host_exit;
rdrv->state = CDNS3_ROLE_STATE_INACTIVE;
rdrv->name = "host";
cdns->roles[USB_ROLE_HOST] = rdrv;
return 0;
}
// SPDX-License-Identifier: GPL-2.0
/*
* USBSS device controller driver Trace Support
*
* Copyright (C) 2018-2019 Cadence.
*
* Author: Pawel Laszczak <pawell@cadence.com>
*/
#define CREATE_TRACE_POINTS
#include "trace.h"
This diff is collapsed.
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
obj-$(CONFIG_USB_COMMON) += usb-common.o obj-$(CONFIG_USB_COMMON) += usb-common.o
usb-common-y += common.o usb-common-y += common.o
usb-common-$(CONFIG_TRACING) += debug.o
usb-common-$(CONFIG_USB_LED_TRIG) += led.o usb-common-$(CONFIG_USB_LED_TRIG) += led.o
obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
......
// SPDX-License-Identifier: GPL-2.0
/**
* Common USB debugging functions
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*/
#include <linux/usb/ch9.h>
static void usb_decode_get_status(__u8 bRequestType, __u16 wIndex,
__u16 wLength, char *str, size_t size)
{
switch (bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
snprintf(str, size, "Get Device Status(Length = %d)", wLength);
break;
case USB_RECIP_INTERFACE:
snprintf(str, size,
"Get Interface Status(Intf = %d, Length = %d)",
wIndex, wLength);
break;
case USB_RECIP_ENDPOINT:
snprintf(str, size, "Get Endpoint Status(ep%d%s)",
wIndex & ~USB_DIR_IN,
wIndex & USB_DIR_IN ? "in" : "out");
break;
}
}
static const char *usb_decode_device_feature(u16 wValue)
{
switch (wValue) {
case USB_DEVICE_SELF_POWERED:
return "Self Powered";
case USB_DEVICE_REMOTE_WAKEUP:
return "Remote Wakeup";
case USB_DEVICE_TEST_MODE:
return "Test Mode";
case USB_DEVICE_U1_ENABLE:
return "U1 Enable";
case USB_DEVICE_U2_ENABLE:
return "U2 Enable";
case USB_DEVICE_LTM_ENABLE:
return "LTM Enable";
default:
return "UNKNOWN";
}
}
static const char *usb_decode_test_mode(u16 wIndex)
{
switch (wIndex) {
case TEST_J:
return ": TEST_J";
case TEST_K:
return ": TEST_K";
case TEST_SE0_NAK:
return ": TEST_SE0_NAK";
case TEST_PACKET:
return ": TEST_PACKET";
case TEST_FORCE_EN:
return ": TEST_FORCE_EN";
default:
return ": UNKNOWN";
}
}
static void usb_decode_set_clear_feature(__u8 bRequestType,
__u8 bRequest, __u16 wValue,
__u16 wIndex, char *str, size_t size)
{
switch (bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
snprintf(str, size, "%s Device Feature(%s%s)",
bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
usb_decode_device_feature(wValue),
wValue == USB_DEVICE_TEST_MODE ?
usb_decode_test_mode(wIndex) : "");
break;
case USB_RECIP_INTERFACE:
snprintf(str, size, "%s Interface Feature(%s)",
bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
wValue == USB_INTRF_FUNC_SUSPEND ?
"Function Suspend" : "UNKNOWN");
break;
case USB_RECIP_ENDPOINT:
snprintf(str, size, "%s Endpoint Feature(%s ep%d%s)",
bRequest == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
wValue == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN",
wIndex & ~USB_DIR_IN,
wIndex & USB_DIR_IN ? "in" : "out");
break;
}
}
static void usb_decode_set_address(__u16 wValue, char *str, size_t size)
{
snprintf(str, size, "Set Address(Addr = %02x)", wValue);
}
static void usb_decode_get_set_descriptor(__u8 bRequestType, __u8 bRequest,
__u16 wValue, __u16 wIndex,
__u16 wLength, char *str, size_t size)
{
char *s;
switch (wValue >> 8) {
case USB_DT_DEVICE:
s = "Device";
break;
case USB_DT_CONFIG:
s = "Configuration";
break;
case USB_DT_STRING:
s = "String";
break;
case USB_DT_INTERFACE:
s = "Interface";
break;
case USB_DT_ENDPOINT:
s = "Endpoint";
break;
case USB_DT_DEVICE_QUALIFIER:
s = "Device Qualifier";
break;
case USB_DT_OTHER_SPEED_CONFIG:
s = "Other Speed Config";
break;
case USB_DT_INTERFACE_POWER:
s = "Interface Power";
break;
case USB_DT_OTG:
s = "OTG";
break;
case USB_DT_DEBUG:
s = "Debug";
break;
case USB_DT_INTERFACE_ASSOCIATION:
s = "Interface Association";
break;
case USB_DT_BOS:
s = "BOS";
break;
case USB_DT_DEVICE_CAPABILITY:
s = "Device Capability";
break;
case USB_DT_PIPE_USAGE:
s = "Pipe Usage";
break;
case USB_DT_SS_ENDPOINT_COMP:
s = "SS Endpoint Companion";
break;
case USB_DT_SSP_ISOC_ENDPOINT_COMP:
s = "SSP Isochronous Endpoint Companion";
break;
default:
s = "UNKNOWN";
break;
}
snprintf(str, size, "%s %s Descriptor(Index = %d, Length = %d)",
bRequest == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set",
s, wValue & 0xff, wLength);
}
static void usb_decode_get_configuration(__u16 wLength, char *str, size_t size)
{
snprintf(str, size, "Get Configuration(Length = %d)", wLength);
}
static void usb_decode_set_configuration(__u8 wValue, char *str, size_t size)
{
snprintf(str, size, "Set Configuration(Config = %d)", wValue);
}
static void usb_decode_get_intf(__u16 wIndex, __u16 wLength, char *str,
size_t size)
{
snprintf(str, size, "Get Interface(Intf = %d, Length = %d)",
wIndex, wLength);
}
static void usb_decode_set_intf(__u8 wValue, __u16 wIndex, char *str,
size_t size)
{
snprintf(str, size, "Set Interface(Intf = %d, Alt.Setting = %d)",
wIndex, wValue);
}
static void usb_decode_synch_frame(__u16 wIndex, __u16 wLength,
char *str, size_t size)
{
snprintf(str, size, "Synch Frame(Endpoint = %d, Length = %d)",
wIndex, wLength);
}
static void usb_decode_set_sel(__u16 wLength, char *str, size_t size)
{
snprintf(str, size, "Set SEL(Length = %d)", wLength);
}
static void usb_decode_set_isoch_delay(__u8 wValue, char *str, size_t size)
{
snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", wValue);
}
/**
* usb_decode_ctrl - returns a string representation of ctrl request
*/
const char *usb_decode_ctrl(char *str, size_t size, __u8 bRequestType,
__u8 bRequest, __u16 wValue, __u16 wIndex,
__u16 wLength)
{
switch (bRequest) {
case USB_REQ_GET_STATUS:
usb_decode_get_status(bRequestType, wIndex, wLength, str, size);
break;
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
usb_decode_set_clear_feature(bRequestType, bRequest, wValue,
wIndex, str, size);
break;
case USB_REQ_SET_ADDRESS:
usb_decode_set_address(wValue, str, size);
break;
case USB_REQ_GET_DESCRIPTOR:
case USB_REQ_SET_DESCRIPTOR:
usb_decode_get_set_descriptor(bRequestType, bRequest, wValue,
wIndex, wLength, str, size);
break;
case USB_REQ_GET_CONFIGURATION:
usb_decode_get_configuration(wLength, str, size);
break;
case USB_REQ_SET_CONFIGURATION:
usb_decode_set_configuration(wValue, str, size);
break;
case USB_REQ_GET_INTERFACE:
usb_decode_get_intf(wIndex, wLength, str, size);
break;
case USB_REQ_SET_INTERFACE:
usb_decode_set_intf(wValue, wIndex, str, size);
break;
case USB_REQ_SYNCH_FRAME:
usb_decode_synch_frame(wIndex, wLength, str, size);
break;
case USB_REQ_SET_SEL:
usb_decode_set_sel(wLength, str, size);
break;
case USB_REQ_SET_ISOCH_DELAY:
usb_decode_set_isoch_delay(wValue, str, size);
break;
default:
snprintf(str, size, "%02x %02x %02x %02x %02x %02x %02x %02x",
bRequestType, bRequest,
(u8)(cpu_to_le16(wValue) & 0xff),
(u8)(cpu_to_le16(wValue) >> 8),
(u8)(cpu_to_le16(wIndex) & 0xff),
(u8)(cpu_to_le16(wIndex) >> 8),
(u8)(cpu_to_le16(wLength) & 0xff),
(u8)(cpu_to_le16(wLength) >> 8));
}
return str;
}
EXPORT_SYMBOL_GPL(usb_decode_ctrl);
...@@ -3224,14 +3224,15 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, ...@@ -3224,14 +3224,15 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg,
struct dwc2_hsotg_ep *ep, struct dwc2_hsotg_ep *ep,
int result) int result)
{ {
struct dwc2_hsotg_req *req, *treq;
unsigned int size; unsigned int size;
ep->req = NULL; ep->req = NULL;
list_for_each_entry_safe(req, treq, &ep->queue, queue) while (!list_empty(&ep->queue)) {
dwc2_hsotg_complete_request(hsotg, ep, req, struct dwc2_hsotg_req *req = get_ep_head(ep);
result);
dwc2_hsotg_complete_request(hsotg, ep, req, result);
}
if (!hsotg->dedicated_fifos) if (!hsotg->dedicated_fifos)
return; return;
......
This diff is collapsed.
...@@ -1137,6 +1137,8 @@ struct dwc3 { ...@@ -1137,6 +1137,8 @@ struct dwc3 {
#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31) #define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31)
#define DWC3_USB31_REVISION_160A (0x3136302a | DWC3_REVISION_IS_DWC31) #define DWC3_USB31_REVISION_160A (0x3136302a | DWC3_REVISION_IS_DWC31)
#define DWC3_USB31_REVISION_170A (0x3137302a | DWC3_REVISION_IS_DWC31) #define DWC3_USB31_REVISION_170A (0x3137302a | DWC3_REVISION_IS_DWC31)
#define DWC3_USB31_REVISION_180A (0x3138302a | DWC3_REVISION_IS_DWC31)
#define DWC3_USB31_REVISION_190A (0x3139302a | DWC3_REVISION_IS_DWC31)
u32 version_type; u32 version_type;
......
This diff is collapsed.
...@@ -81,7 +81,6 @@ static int kdwc3_probe(struct platform_device *pdev) ...@@ -81,7 +81,6 @@ static int kdwc3_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct dwc3_keystone *kdwc; struct dwc3_keystone *kdwc;
struct resource *res;
int error, irq; int error, irq;
kdwc = devm_kzalloc(dev, sizeof(*kdwc), GFP_KERNEL); kdwc = devm_kzalloc(dev, sizeof(*kdwc), GFP_KERNEL);
...@@ -92,8 +91,7 @@ static int kdwc3_probe(struct platform_device *pdev) ...@@ -92,8 +91,7 @@ static int kdwc3_probe(struct platform_device *pdev)
kdwc->dev = dev; kdwc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); kdwc->usbss = devm_platform_ioremap_resource(pdev, 0);
kdwc->usbss = devm_ioremap_resource(dev, res);
if (IS_ERR(kdwc->usbss)) if (IS_ERR(kdwc->usbss))
return PTR_ERR(kdwc->usbss); return PTR_ERR(kdwc->usbss);
......
...@@ -562,7 +562,13 @@ static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev) ...@@ -562,7 +562,13 @@ static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev)
static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev)
{ {
struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
int i; int i, ret;
if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
ret = regulator_disable(priv->vbus);
if (ret)
return ret;
}
for (i = 0 ; i < PHY_COUNT ; ++i) { for (i = 0 ; i < PHY_COUNT ; ++i) {
phy_power_off(priv->phys[i]); phy_power_off(priv->phys[i]);
...@@ -597,6 +603,12 @@ static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev) ...@@ -597,6 +603,12 @@ static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
return ret; return ret;
} }
if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
ret = regulator_enable(priv->vbus);
if (ret)
return ret;
}
return 0; return 0;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -86,7 +86,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, ...@@ -86,7 +86,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
__entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength); __entry->wLength = le16_to_cpu(ctrl->wLength);
), ),
TP_printk("%s", dwc3_decode_ctrl(__get_str(str), DWC3_MSG_MAX, TP_printk("%s", usb_decode_ctrl(__get_str(str), DWC3_MSG_MAX,
__entry->bRequestType, __entry->bRequestType,
__entry->bRequest, __entry->wValue, __entry->bRequest, __entry->wValue,
__entry->wIndex, __entry->wLength) __entry->wIndex, __entry->wLength)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment