USB update for 4.8-rc1

Here's the big USB driver update for 4.8-rc1.  Lots of the normal stuff
 in here, musb, gadget, xhci, and other updates and fixes.  All of the
 details are in the shortlog.
 
 All of these have been in linux-next for a while with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iFYEABECABYFAleVPioPHGdyZWdAa3JvYWguY29tAAoJEDFH1A3bLfspB5AAnj7a
 VJ2t2kcWzFUNQ6dyJrJCGGRAAKDZmb5CnOGeqJmdVpDzN1CGLYjfiw==
 =47iA
 -----END PGP SIGNATURE-----

Merge tag 'usb-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB updates from Greg KH:
 "Here's the big USB driver update for 4.8-rc1.  Lots of the normal
  stuff in here, musb, gadget, xhci, and other updates and fixes.  All
  of the details are in the shortlog.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'usb-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (169 commits)
  cdc-acm: beautify probe()
  cdc-wdm: use the common CDC parser
  cdc-acm: cleanup error handling
  cdc-acm: use the common parser
  usbnet: move the CDC parser into USB core
  usb: musb: sunxi: Simplify dr_mode handling
  usb: musb: sunxi: make unexported symbols static
  usb: musb: cppi41: add dma channel tracepoints
  usb: musb: cppi41: move struct cppi41_dma_channel to header
  usb: musb: cleanup cppi_dma header
  usb: musb: gadget: add usb-request tracepoints
  usb: musb: host: add urb tracepoints
  usb: musb: add tracepoints to dump interrupt events
  usb: musb: add tracepoints for register access
  usb: musb: dsps: use musb register read/write wrappers instead
  usb: musb: switch dev_dbg to tracepoints
  usb: musb: add tracepoints support for debugging
  usb: quirks: Add no-lpm quirk for Elan
  phy: rcar-gen3-usb2: fix mutex_lock calling in interrupt
  phy: rockhip-usb: use devm_add_action_or_reset()
  ...
This commit is contained in:
Linus Torvalds 2016-07-24 17:22:18 -07:00
commit b7545b79a1
109 changed files with 5817 additions and 3786 deletions

View file

@ -0,0 +1,40 @@
TI DA8xx/OMAP-L1xx/AM18xx USB PHY
Required properties:
- compatible: must be "ti,da830-usb-phy".
- #phy-cells: must be 1.
This device controls the PHY for both the USB 1.1 OHCI and USB 2.0 OTG
controllers on DA8xx SoCs. Consumers of this device should use index 0 for
the USB 2.0 phy device and index 1 for the USB 1.1 phy device.
It also requires a "syscon" node with compatible = "ti,da830-cfgchip", "syscon"
to access the CFGCHIP2 register.
Example:
cfgchip: cfgchip@1417c {
compatible = "ti,da830-cfgchip", "syscon";
reg = <0x1417c 0x14>;
};
usb_phy: usb-phy {
compatible = "ti,da830-usb-phy";
#phy-cells = <1>;
};
usb20: usb@200000 {
compatible = "ti,da830-musb";
reg = <0x200000 0x1000>;
interrupts = <58>;
phys = <&usb_phy 0>;
phy-names = "usb-phy";
};
usb11: usb@225000 {
compatible = "ti,da830-ohci";
reg = <0x225000 0x1000>;
interrupts = <59>;
phys = <&usb_phy 1>;
phy-names = "usb-phy";
};

View file

@ -5,11 +5,13 @@ Required properties:
"rockchip,rk3066a-usb-phy"
"rockchip,rk3188-usb-phy"
"rockchip,rk3288-usb-phy"
- rockchip,grf : phandle to the syscon managing the "general
register files"
- #address-cells: should be 1
- #size-cells: should be 0
Deprecated properties:
- rockchip,grf : phandle to the syscon managing the "general
register files" - phy should be a child of the GRF instead
Sub-nodes:
Each PHY should be represented as a sub-node.
@ -28,14 +30,19 @@ Optional Properties:
Example:
usbphy: phy {
compatible = "rockchip,rk3288-usb-phy";
rockchip,grf = <&grf>;
#address-cells = <1>;
#size-cells = <0>;
grf: syscon@ff770000 {
compatible = "rockchip,rk3288-grf", "syscon", "simple-mfd";
usbphy0: usb-phy0 {
#phy-cells = <0>;
reg = <0x320>;
...
usbphy: phy {
compatible = "rockchip,rk3288-usb-phy";
#address-cells = <1>;
#size-cells = <0>;
usbphy0: usb-phy0 {
#phy-cells = <0>;
reg = <0x320>;
};
};
};

View file

@ -93,7 +93,7 @@ Example:
phys = <&usb_phy0>;
phy-names = "usb-phy";
vbus-supply = <&reg_usb0_vbus>;
gadget-itc-setting = <0x4>; /* 4 micro-frames */
itc-setting = <0x4>; /* 4 micro-frames */
/* Incremental burst of unspecified length */
ahb-burst-config = <0x0>;
tx-burst-size-dword = <0x10>; /* 64 bytes */

View file

@ -14,7 +14,7 @@ Optional properties:
- clocks : a list of phandle + clock specifier pairs
- phys : phandle + phy specifier pair
- phy-names : "usb"
- resets : phandle + reset specifier pair
- resets : a list of phandle + reset specifier pairs
Example:

View file

@ -232,7 +232,7 @@ ep15 {
};
usb1: ohci@00400000 {
compatible = "atmel,at91rm9200-ohci", "usb-ohci";
compatible = "atmel,sama5d2-ohci", "usb-ohci";
reg = <0x00400000 0x100000>;
interrupts = <41 IRQ_TYPE_LEVEL_HIGH 2>;
clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>;

View file

@ -42,7 +42,6 @@
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/pm_runtime.h>
@ -1972,143 +1971,6 @@ static int __usbnet_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
return err;
}
int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
struct usb_interface *intf,
u8 *buffer,
int buflen)
{
/* duplicates are ignored */
struct usb_cdc_union_desc *union_header = NULL;
/* duplicates are not tolerated */
struct usb_cdc_header_desc *header = NULL;
struct usb_cdc_ether_desc *ether = NULL;
struct usb_cdc_mdlm_detail_desc *detail = NULL;
struct usb_cdc_mdlm_desc *desc = NULL;
unsigned int elength;
int cnt = 0;
memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header));
hdr->phonet_magic_present = false;
while (buflen > 0) {
elength = buffer[0];
if (!elength) {
dev_err(&intf->dev, "skipping garbage byte\n");
elength = 1;
goto next_desc;
}
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer[2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
if (elength < sizeof(struct usb_cdc_union_desc))
goto next_desc;
if (union_header) {
dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
goto next_desc;
}
union_header = (struct usb_cdc_union_desc *)buffer;
break;
case USB_CDC_COUNTRY_TYPE:
if (elength < sizeof(struct usb_cdc_country_functional_desc))
goto next_desc;
hdr->usb_cdc_country_functional_desc =
(struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE:
if (elength != sizeof(struct usb_cdc_header_desc))
goto next_desc;
if (header)
return -EINVAL;
header = (struct usb_cdc_header_desc *)buffer;
break;
case USB_CDC_ACM_TYPE:
if (elength < sizeof(struct usb_cdc_acm_descriptor))
goto next_desc;
hdr->usb_cdc_acm_descriptor =
(struct usb_cdc_acm_descriptor *)buffer;
break;
case USB_CDC_ETHERNET_TYPE:
if (elength != sizeof(struct usb_cdc_ether_desc))
goto next_desc;
if (ether)
return -EINVAL;
ether = (struct usb_cdc_ether_desc *)buffer;
break;
case USB_CDC_CALL_MANAGEMENT_TYPE:
if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor))
goto next_desc;
hdr->usb_cdc_call_mgmt_descriptor =
(struct usb_cdc_call_mgmt_descriptor *)buffer;
break;
case USB_CDC_DMM_TYPE:
if (elength < sizeof(struct usb_cdc_dmm_desc))
goto next_desc;
hdr->usb_cdc_dmm_desc =
(struct usb_cdc_dmm_desc *)buffer;
break;
case USB_CDC_MDLM_TYPE:
if (elength < sizeof(struct usb_cdc_mdlm_desc *))
goto next_desc;
if (desc)
return -EINVAL;
desc = (struct usb_cdc_mdlm_desc *)buffer;
break;
case USB_CDC_MDLM_DETAIL_TYPE:
if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *))
goto next_desc;
if (detail)
return -EINVAL;
detail = (struct usb_cdc_mdlm_detail_desc *)buffer;
break;
case USB_CDC_NCM_TYPE:
if (elength < sizeof(struct usb_cdc_ncm_desc))
goto next_desc;
hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer;
break;
case USB_CDC_MBIM_TYPE:
if (elength < sizeof(struct usb_cdc_mbim_desc))
goto next_desc;
hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer;
break;
case USB_CDC_MBIM_EXTENDED_TYPE:
if (elength < sizeof(struct usb_cdc_mbim_extended_desc))
break;
hdr->usb_cdc_mbim_extended_desc =
(struct usb_cdc_mbim_extended_desc *)buffer;
break;
case CDC_PHONET_MAGIC_NUMBER:
hdr->phonet_magic_present = true;
break;
default:
/*
* there are LOTS more CDC descriptors that
* could legitimately be found here.
*/
dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n",
buffer[2], elength);
goto next_desc;
}
cnt++;
next_desc:
buflen -= elength;
buffer += elength;
}
hdr->usb_cdc_union_desc = union_header;
hdr->usb_cdc_header_desc = header;
hdr->usb_cdc_mdlm_detail_desc = detail;
hdr->usb_cdc_mdlm_desc = desc;
hdr->usb_cdc_ether_desc = ether;
return cnt;
}
EXPORT_SYMBOL(cdc_parse_cdc_header);
/*
* The function can't be called inside suspend/resume callback,
* otherwise deadlock will be caused.

View file

@ -44,6 +44,16 @@ config ARMADA375_USBCLUSTER_PHY
depends on OF && HAS_IOMEM
select GENERIC_PHY
config PHY_DA8XX_USB
tristate "TI DA8xx USB PHY Driver"
depends on ARCH_DAVINCI_DA8XX
select GENERIC_PHY
select MFD_SYSCON
help
Enable this to support the USB PHY on DA8xx SoCs.
This driver controls both the USB 1.1 PHY and the USB 2.0 PHY.
config PHY_DM816X_USB
tristate "TI dm816x USB PHY driver"
depends on ARCH_OMAP2PLUS
@ -176,6 +186,7 @@ config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
depends on USB_SUPPORT
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't 'y'
select GENERIC_PHY
select USB_PHY
help

View file

@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o
obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o

View file

@ -342,6 +342,21 @@ int phy_power_off(struct phy *phy)
}
EXPORT_SYMBOL_GPL(phy_power_off);
int phy_set_mode(struct phy *phy, enum phy_mode mode)
{
int ret;
if (!phy || !phy->ops->set_mode)
return 0;
mutex_lock(&phy->mutex);
ret = phy->ops->set_mode(phy, mode);
mutex_unlock(&phy->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(phy_set_mode);
/**
* _of_phy_get() - lookup and obtain a reference to a phy by phandle
* @np: device_node for which to get the phy

245
drivers/phy/phy-da8xx-usb.c Normal file
View file

@ -0,0 +1,245 @@
/*
* phy-da8xx-usb - TI DaVinci DA8xx USB PHY driver
*
* Copyright (C) 2016 David Lechner <david@lechnology.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/mfd/da8xx-cfgchip.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
struct da8xx_usb_phy {
struct phy_provider *phy_provider;
struct phy *usb11_phy;
struct phy *usb20_phy;
struct clk *usb11_clk;
struct clk *usb20_clk;
struct regmap *regmap;
};
static int da8xx_usb11_phy_power_on(struct phy *phy)
{
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
int ret;
ret = clk_prepare_enable(d_phy->usb11_clk);
if (ret)
return ret;
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM,
CFGCHIP2_USB1SUSPENDM);
return 0;
}
static int da8xx_usb11_phy_power_off(struct phy *phy)
{
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 0);
clk_disable_unprepare(d_phy->usb11_clk);
return 0;
}
static const struct phy_ops da8xx_usb11_phy_ops = {
.power_on = da8xx_usb11_phy_power_on,
.power_off = da8xx_usb11_phy_power_off,
.owner = THIS_MODULE,
};
static int da8xx_usb20_phy_power_on(struct phy *phy)
{
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
int ret;
ret = clk_prepare_enable(d_phy->usb20_clk);
if (ret)
return ret;
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN, 0);
return 0;
}
static int da8xx_usb20_phy_power_off(struct phy *phy)
{
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGPWRDN,
CFGCHIP2_OTGPWRDN);
clk_disable_unprepare(d_phy->usb20_clk);
return 0;
}
static int da8xx_usb20_phy_set_mode(struct phy *phy, enum phy_mode mode)
{
struct da8xx_usb_phy *d_phy = phy_get_drvdata(phy);
u32 val;
switch (mode) {
case PHY_MODE_USB_HOST: /* Force VBUS valid, ID = 0 */
val = CFGCHIP2_OTGMODE_FORCE_HOST;
break;
case PHY_MODE_USB_DEVICE: /* Force VBUS valid, ID = 1 */
val = CFGCHIP2_OTGMODE_FORCE_DEVICE;
break;
case PHY_MODE_USB_OTG: /* Don't override the VBUS/ID comparators */
val = CFGCHIP2_OTGMODE_NO_OVERRIDE;
break;
default:
return -EINVAL;
}
regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_OTGMODE_MASK,
val);
return 0;
}
static const struct phy_ops da8xx_usb20_phy_ops = {
.power_on = da8xx_usb20_phy_power_on,
.power_off = da8xx_usb20_phy_power_off,
.set_mode = da8xx_usb20_phy_set_mode,
.owner = THIS_MODULE,
};
static struct phy *da8xx_usb_phy_of_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev);
if (!d_phy)
return ERR_PTR(-ENODEV);
switch (args->args[0]) {
case 0:
return d_phy->usb20_phy;
case 1:
return d_phy->usb11_phy;
default:
return ERR_PTR(-EINVAL);
}
}
static int da8xx_usb_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct da8xx_usb_phy *d_phy;
d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL);
if (!d_phy)
return -ENOMEM;
if (node)
d_phy->regmap = syscon_regmap_lookup_by_compatible(
"ti,da830-cfgchip");
else
d_phy->regmap = syscon_regmap_lookup_by_pdevname("syscon.0");
if (IS_ERR(d_phy->regmap)) {
dev_err(dev, "Failed to get syscon\n");
return PTR_ERR(d_phy->regmap);
}
d_phy->usb11_clk = devm_clk_get(dev, "usb11_phy");
if (IS_ERR(d_phy->usb11_clk)) {
dev_err(dev, "Failed to get usb11_phy clock\n");
return PTR_ERR(d_phy->usb11_clk);
}
d_phy->usb20_clk = devm_clk_get(dev, "usb20_phy");
if (IS_ERR(d_phy->usb20_clk)) {
dev_err(dev, "Failed to get usb20_phy clock\n");
return PTR_ERR(d_phy->usb20_clk);
}
d_phy->usb11_phy = devm_phy_create(dev, node, &da8xx_usb11_phy_ops);
if (IS_ERR(d_phy->usb11_phy)) {
dev_err(dev, "Failed to create usb11 phy\n");
return PTR_ERR(d_phy->usb11_phy);
}
d_phy->usb20_phy = devm_phy_create(dev, node, &da8xx_usb20_phy_ops);
if (IS_ERR(d_phy->usb20_phy)) {
dev_err(dev, "Failed to create usb20 phy\n");
return PTR_ERR(d_phy->usb20_phy);
}
platform_set_drvdata(pdev, d_phy);
phy_set_drvdata(d_phy->usb11_phy, d_phy);
phy_set_drvdata(d_phy->usb20_phy, d_phy);
if (node) {
d_phy->phy_provider = devm_of_phy_provider_register(dev,
da8xx_usb_phy_of_xlate);
if (IS_ERR(d_phy->phy_provider)) {
dev_err(dev, "Failed to create phy provider\n");
return PTR_ERR(d_phy->phy_provider);
}
} else {
int ret;
ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0");
if (ret)
dev_warn(dev, "Failed to create usb11 phy lookup\n");
ret = phy_create_lookup(d_phy->usb20_phy, "usb-phy",
"musb-da8xx");
if (ret)
dev_warn(dev, "Failed to create usb20 phy lookup\n");
}
return 0;
}
static int da8xx_usb_phy_remove(struct platform_device *pdev)
{
struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev);
if (!pdev->dev.of_node) {
phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx");
phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci.0");
}
return 0;
}
static const struct of_device_id da8xx_usb_phy_ids[] = {
{ .compatible = "ti,da830-usb-phy" },
{ }
};
MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids);
static struct platform_driver da8xx_usb_phy_driver = {
.probe = da8xx_usb_phy_probe,
.remove = da8xx_usb_phy_remove,
.driver = {
.name = "da8xx-usb-phy",
.of_match_table = da8xx_usb_phy_ids,
},
};
module_platform_driver(da8xx_usb_phy_driver);
MODULE_ALIAS("platform:da8xx-usb-phy");
MODULE_AUTHOR("David Lechner <david@lechnology.com>");
MODULE_DESCRIPTION("TI DA8xx USB PHY driver");
MODULE_LICENSE("GPL v2");

View file

@ -140,7 +140,6 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
if (!phy) {
dev_err(dev, "%s: failed to allocate phy\n", __func__);
err = -ENOMEM;
goto out;
}

View file

@ -196,7 +196,6 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev)
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
if (!phy) {
dev_err(dev, "%s: failed to allocate phy\n", __func__);
err = -ENOMEM;
goto out;
}

View file

@ -21,6 +21,7 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
/******* USB2.0 Host registers (original offset is +0x200) *******/
#define USB2_INT_ENABLE 0x000
@ -81,9 +82,25 @@ struct rcar_gen3_chan {
struct extcon_dev *extcon;
struct phy *phy;
struct regulator *vbus;
struct work_struct work;
bool extcon_host;
bool has_otg;
};
static void rcar_gen3_phy_usb2_work(struct work_struct *work)
{
struct rcar_gen3_chan *ch = container_of(work, struct rcar_gen3_chan,
work);
if (ch->extcon_host) {
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
} else {
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
}
}
static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host)
{
void __iomem *usb2_base = ch->base;
@ -130,8 +147,8 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch)
rcar_gen3_set_host_mode(ch, 1);
rcar_gen3_enable_vbus_ctrl(ch, 1);
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
ch->extcon_host = true;
schedule_work(&ch->work);
}
static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
@ -140,8 +157,8 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch)
rcar_gen3_set_host_mode(ch, 0);
rcar_gen3_enable_vbus_ctrl(ch, 0);
extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
ch->extcon_host = false;
schedule_work(&ch->work);
}
static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch)
@ -301,6 +318,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (irq >= 0) {
int ret;
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(dev), channel);
if (irq < 0)

View file

@ -236,9 +236,10 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
goto err_clk_prov;
}
err = devm_add_action(base->dev, rockchip_usb_phy_action, rk_phy);
err = devm_add_action_or_reset(base->dev, rockchip_usb_phy_action,
rk_phy);
if (err)
goto err_devm_action;
return err;
rk_phy->phy = devm_phy_create(base->dev, child, &ops);
if (IS_ERR(rk_phy->phy)) {
@ -256,9 +257,6 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
else
return rockchip_usb_phy_power(rk_phy, 1);
err_devm_action:
if (!rk_phy->uart_enabled)
of_clk_del_provider(child);
err_clk_prov:
if (!rk_phy->uart_enabled)
clk_unregister(rk_phy->clk480m);
@ -397,8 +395,13 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
phy_base->pdata = match->data;
phy_base->dev = dev;
phy_base->reg_base = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf");
phy_base->reg_base = ERR_PTR(-ENODEV);
if (dev->parent && dev->parent->of_node)
phy_base->reg_base = syscon_node_to_regmap(
dev->parent->of_node);
if (IS_ERR(phy_base->reg_base))
phy_base->reg_base = syscon_regmap_lookup_by_phandle(
dev->of_node, "rockchip,grf");
if (IS_ERR(phy_base->reg_base)) {
dev_err(&pdev->dev, "Missing rockchip,grf property\n");
return PTR_ERR(phy_base->reg_base);
@ -463,7 +466,11 @@ static int __init rockchip_init_usb_uart(void)
return -ENOTSUPP;
}
grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
grf = ERR_PTR(-ENODEV);
if (np->parent)
grf = syscon_node_to_regmap(np->parent);
if (IS_ERR(grf))
grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(grf)) {
pr_err("%s: Missing rockchip,grf property, %lu\n",
__func__, PTR_ERR(grf));

View file

@ -94,6 +94,7 @@
enum sun4i_usb_phy_type {
sun4i_a10_phy,
sun6i_a31_phy,
sun8i_a33_phy,
sun8i_h3_phy,
};
@ -122,7 +123,6 @@ struct sun4i_usb_phy_data {
/* phy0 / otg related variables */
struct extcon_dev *extcon;
bool phy0_init;
bool phy0_poll;
struct gpio_desc *id_det_gpio;
struct gpio_desc *vbus_det_gpio;
struct power_supply *vbus_power_supply;
@ -343,6 +343,24 @@ static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data)
return data->vbus_det_gpio || data->vbus_power_supply;
}
static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data)
{
if ((data->id_det_gpio && data->id_det_irq <= 0) ||
(data->vbus_det_gpio && data->vbus_det_irq <= 0))
return true;
/*
* The A31 companion pmic (axp221) does not generate vbus change
* interrupts when the board is driving vbus, so we must poll
* when using the pmic for vbus-det _and_ we're driving vbus.
*/
if (data->cfg->type == sun6i_a31_phy &&
data->vbus_power_supply && data->phys[0].regulator_on)
return true;
return false;
}
static int sun4i_usb_phy_power_on(struct phy *_phy)
{
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
@ -364,7 +382,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy)
phy->regulator_on = true;
/* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */
if (phy->index == 0 && data->vbus_det_gpio && data->phy0_poll)
if (phy->index == 0 && sun4i_usb_phy0_poll(data))
mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
return 0;
@ -385,7 +403,7 @@ static int sun4i_usb_phy_power_off(struct phy *_phy)
* phy0 vbus typically slowly discharges, sometimes this causes the
* Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan.
*/
if (phy->index == 0 && data->vbus_det_gpio && !data->phy0_poll)
if (phy->index == 0 && !sun4i_usb_phy0_poll(data))
mod_delayed_work(system_wq, &data->detect, POLL_TIME);
return 0;
@ -468,7 +486,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
if (vbus_notify)
extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
if (data->phy0_poll)
if (sun4i_usb_phy0_poll(data))
queue_delayed_work(system_wq, &data->detect, POLL_TIME);
}
@ -644,11 +662,6 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
}
data->id_det_irq = gpiod_to_irq(data->id_det_gpio);
data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
if ((data->id_det_gpio && data->id_det_irq <= 0) ||
(data->vbus_det_gpio && data->vbus_det_irq <= 0))
data->phy0_poll = true;
if (data->id_det_irq > 0) {
ret = devm_request_irq(dev, data->id_det_irq,
sun4i_usb_phy0_id_vbus_det_irq,
@ -660,6 +673,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
}
}
data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
if (data->vbus_det_irq > 0) {
ret = devm_request_irq(dev, data->vbus_det_irq,
sun4i_usb_phy0_id_vbus_det_irq,
@ -711,7 +725,7 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
.num_phys = 3,
.type = sun4i_a10_phy,
.type = sun6i_a31_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = true,

View file

@ -518,7 +518,7 @@ enum clk_type_t {
CLK_INT_SING = 2, /* Internal single ended */
};
enum phy_mode {
enum xgene_phy_mode {
MODE_SATA = 0, /* List them for simple reference */
MODE_SGMII = 1,
MODE_PCIE = 2,
@ -542,7 +542,7 @@ struct xgene_sata_override_param {
struct xgene_phy_ctx {
struct device *dev;
struct phy *phy;
enum phy_mode mode; /* Mode of operation */
enum xgene_phy_mode mode; /* Mode of operation */
enum clk_type_t clk_type; /* Input clock selection */
void __iomem *sds_base; /* PHY CSR base addr */
struct clk *clk; /* Optional clock */

View file

@ -309,6 +309,7 @@ config BATTERY_RX51
config CHARGER_ISP1704
tristate "ISP1704 USB Charger Detection"
depends on USB_PHY
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
help
Say Y to enable support for USB Charger Detection with
ISP1707/ISP1704 USB transceivers.

View file

@ -4,8 +4,9 @@ config USB_CHIPIDEA
select EXTCON
help
Say Y here if your system has a dual role high speed USB
controller based on ChipIdea silicon IP. Currently, only the
peripheral mode is supported.
controller based on ChipIdea silicon IP. It supports:
Dual-role switch (ID, OTG FSM, sysfs), Host-only, and
Peripheral-only.
When compiled dynamically, the module will be called ci-hdrc.ko.

View file

@ -946,7 +946,7 @@ static int wait_serial_change(struct acm *acm, unsigned long arg)
DECLARE_WAITQUEUE(wait, current);
struct async_icount old, new;
if (arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD ))
if (arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD))
return -EINVAL;
do {
spin_lock_irq(&acm->read_lock);
@ -1146,7 +1146,7 @@ static int acm_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_cdc_union_desc *union_header = NULL;
struct usb_cdc_country_functional_desc *cfd = NULL;
struct usb_cdc_call_mgmt_descriptor *cmgmd = NULL;
unsigned char *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
struct usb_interface *control_interface;
@ -1155,18 +1155,16 @@ static int acm_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *epread = NULL;
struct usb_endpoint_descriptor *epwrite = NULL;
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct usb_cdc_parsed_header h;
struct acm *acm;
int minor;
int ctrlsize, readsize;
u8 *buf;
u8 ac_management_function = 0;
u8 call_management_function = 0;
int call_interface_num = -1;
int data_interface_num = -1;
int call_intf_num = -1;
int data_intf_num = -1;
unsigned long quirks;
int num_rx_buf;
int i;
unsigned int elength = 0;
int combined_interfaces = 0;
struct device *tty_dev;
int rv = -ENOMEM;
@ -1210,70 +1208,22 @@ static int acm_probe(struct usb_interface *intf,
}
}
while (buflen > 0) {
elength = buffer[0];
if (!elength) {
dev_err(&intf->dev, "skipping garbage byte\n");
elength = 1;
goto next_desc;
}
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer[2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
if (elength < sizeof(struct usb_cdc_union_desc))
goto next_desc;
if (union_header) {
dev_err(&intf->dev, "More than one "
"union descriptor, skipping ...\n");
goto next_desc;
}
union_header = (struct usb_cdc_union_desc *)buffer;
break;
case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
if (elength < sizeof(struct usb_cdc_country_functional_desc))
goto next_desc;
cfd = (struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE: /* maybe check version */
break; /* for now we ignore it */
case USB_CDC_ACM_TYPE:
if (elength < 4)
goto next_desc;
ac_management_function = buffer[3];
break;
case USB_CDC_CALL_MANAGEMENT_TYPE:
if (elength < 5)
goto next_desc;
call_management_function = buffer[3];
call_interface_num = buffer[4];
break;
default:
/*
* there are LOTS more CDC descriptors that
* could legitimately be found here.
*/
dev_dbg(&intf->dev, "Ignoring descriptor: "
"type %02x, length %ud\n",
buffer[2], elength);
break;
}
next_desc:
buflen -= elength;
buffer += elength;
}
cdc_parse_cdc_header(&h, intf, buffer, buflen);
union_header = h.usb_cdc_union_desc;
cmgmd = h.usb_cdc_call_mgmt_descriptor;
if (cmgmd)
call_intf_num = cmgmd->bDataInterface;
if (!union_header) {
if (call_interface_num > 0) {
if (call_intf_num > 0) {
dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
/* quirks for Droids MuIn LCD */
if (quirks & NO_DATA_INTERFACE)
if (quirks & NO_DATA_INTERFACE) {
data_interface = usb_ifnum_to_if(usb_dev, 0);
else
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
} else {
data_intf_num = call_intf_num;
data_interface = usb_ifnum_to_if(usb_dev, data_intf_num);
}
control_interface = intf;
} else {
if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
@ -1287,8 +1237,9 @@ static int acm_probe(struct usb_interface *intf,
}
}
} else {
data_intf_num = union_header->bSlaveInterface0;
control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
data_interface = usb_ifnum_to_if(usb_dev, data_intf_num);
}
if (!control_interface || !data_interface) {
@ -1296,7 +1247,7 @@ static int acm_probe(struct usb_interface *intf,
return -ENODEV;
}
if (data_interface_num != call_interface_num)
if (data_intf_num != call_intf_num)
dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
if (control_interface == data_interface) {
@ -1379,11 +1330,8 @@ static int acm_probe(struct usb_interface *intf,
goto alloc_fail;
minor = acm_alloc_minor(acm);
if (minor < 0) {
dev_err(&intf->dev, "no more free acm devices\n");
kfree(acm);
return -ENODEV;
}
if (minor < 0)
goto alloc_fail1;
ctrlsize = usb_endpoint_maxp(epctrl);
readsize = usb_endpoint_maxp(epread) *
@ -1394,7 +1342,8 @@ static int acm_probe(struct usb_interface *intf,
acm->data = data_interface;
acm->minor = minor;
acm->dev = usb_dev;
acm->ctrl_caps = ac_management_function;
if (h.usb_cdc_acm_descriptor)
acm->ctrl_caps = h.usb_cdc_acm_descriptor->bmCapabilities;
if (quirks & NO_CAP_LINE)
acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
acm->ctrlsize = ctrlsize;
@ -1488,7 +1437,10 @@ static int acm_probe(struct usb_interface *intf,
if (i < 0)
goto alloc_fail7;
if (cfd) { /* export the country data */
if (h.usb_cdc_country_functional_desc) { /* export the country data */
struct usb_cdc_country_functional_desc * cfd =
h.usb_cdc_country_functional_desc;
acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);
if (!acm->country_codes)
goto skip_countries;
@ -1572,6 +1524,7 @@ static int acm_probe(struct usb_interface *intf,
usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
alloc_fail2:
acm_release_minor(acm);
alloc_fail1:
kfree(acm);
alloc_fail:
return rv;

View file

@ -875,38 +875,18 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
int rv = -EINVAL;
struct usb_host_interface *iface;
struct usb_endpoint_descriptor *ep;
struct usb_cdc_dmm_desc *dmhd;
struct usb_cdc_parsed_header hdr;
u8 *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
u16 maxcom = WDM_DEFAULT_BUFSIZE;
if (!buffer)
goto err;
while (buflen > 2) {
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer[2]) {
case USB_CDC_HEADER_TYPE:
break;
case USB_CDC_DMM_TYPE:
dmhd = (struct usb_cdc_dmm_desc *)buffer;
maxcom = le16_to_cpu(dmhd->wMaxCommand);
dev_dbg(&intf->dev,
"Finding maximum buffer length: %d", maxcom);
break;
default:
dev_err(&intf->dev,
"Ignoring extra header, type %d, length %d\n",
buffer[2], buffer[0]);
break;
}
next_desc:
buflen -= buffer[0];
buffer += buffer[0];
}
cdc_parse_cdc_header(&hdr, intf, buffer, buflen);
if (hdr.usb_cdc_dmm_desc)
maxcom = le16_to_cpu(hdr.usb_cdc_dmm_desc->wMaxCommand);
iface = intf->cur_altsetting;
if (iface->desc.bNumEndpoints != 1)

View file

@ -131,15 +131,17 @@ EXPORT_SYMBOL_GPL(usb_get_dr_mode);
* of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device
* which is associated with the given phy device_node
* @np: Pointer to the given phy device_node
* @arg0: phandle args[0] for phy's with #phy-cells >= 1, or -1 for
* phys which do not have phy-cells
*
* In dts a usb controller associates with phy devices. The function gets
* the string from property 'dr_mode' of the controller associated with the
* given phy device node, and returns the correspondig enum usb_dr_mode.
*/
enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0)
{
struct device_node *controller = NULL;
struct device_node *phy;
struct of_phandle_args args;
const char *dr_mode;
int index;
int err;
@ -148,12 +150,24 @@ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *phy_np)
controller = of_find_node_with_property(controller, "phys");
index = 0;
do {
phy = of_parse_phandle(controller, "phys", index);
of_node_put(phy);
if (phy == phy_np)
if (arg0 == -1) {
args.np = of_parse_phandle(controller, "phys",
index);
args.args_count = 0;
} else {
err = of_parse_phandle_with_args(controller,
"phys", "#phy-cells",
index, &args);
if (err)
break;
}
of_node_put(args.np);
if (args.np == np && (args.args_count == 0 ||
args.args[0] == arg0))
goto finish;
index++;
} while (phy);
} while (args.np);
} while (controller);
finish:

View file

@ -12,6 +12,7 @@
#include <linux/nls.h>
#include <linux/device.h>
#include <linux/scatterlist.h>
#include <linux/usb/cdc.h>
#include <linux/usb/quirks.h>
#include <linux/usb/hcd.h> /* for usbcore internals */
#include <asm/byteorder.h>
@ -2023,3 +2024,155 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
return 0;
}
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
/**
* cdc_parse_cdc_header - parse the extra headers present in CDC devices
* @hdr: the place to put the results of the parsing
* @intf: the interface for which parsing is requested
* @buffer: pointer to the extra headers to be parsed
* @buflen: length of the extra headers
*
* This evaluates the extra headers present in CDC devices which
* bind the interfaces for data and control and provide details
* about the capabilities of the device.
*
* Return: number of descriptors parsed or -EINVAL
* if the header is contradictory beyond salvage
*/
int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
struct usb_interface *intf,
u8 *buffer,
int buflen)
{
/* duplicates are ignored */
struct usb_cdc_union_desc *union_header = NULL;
/* duplicates are not tolerated */
struct usb_cdc_header_desc *header = NULL;
struct usb_cdc_ether_desc *ether = NULL;
struct usb_cdc_mdlm_detail_desc *detail = NULL;
struct usb_cdc_mdlm_desc *desc = NULL;
unsigned int elength;
int cnt = 0;
memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header));
hdr->phonet_magic_present = false;
while (buflen > 0) {
elength = buffer[0];
if (!elength) {
dev_err(&intf->dev, "skipping garbage byte\n");
elength = 1;
goto next_desc;
}
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer[2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
if (elength < sizeof(struct usb_cdc_union_desc))
goto next_desc;
if (union_header) {
dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
goto next_desc;
}
union_header = (struct usb_cdc_union_desc *)buffer;
break;
case USB_CDC_COUNTRY_TYPE:
if (elength < sizeof(struct usb_cdc_country_functional_desc))
goto next_desc;
hdr->usb_cdc_country_functional_desc =
(struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE:
if (elength != sizeof(struct usb_cdc_header_desc))
goto next_desc;
if (header)
return -EINVAL;
header = (struct usb_cdc_header_desc *)buffer;
break;
case USB_CDC_ACM_TYPE:
if (elength < sizeof(struct usb_cdc_acm_descriptor))
goto next_desc;
hdr->usb_cdc_acm_descriptor =
(struct usb_cdc_acm_descriptor *)buffer;
break;
case USB_CDC_ETHERNET_TYPE:
if (elength != sizeof(struct usb_cdc_ether_desc))
goto next_desc;
if (ether)
return -EINVAL;
ether = (struct usb_cdc_ether_desc *)buffer;
break;
case USB_CDC_CALL_MANAGEMENT_TYPE:
if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor))
goto next_desc;
hdr->usb_cdc_call_mgmt_descriptor =
(struct usb_cdc_call_mgmt_descriptor *)buffer;
break;
case USB_CDC_DMM_TYPE:
if (elength < sizeof(struct usb_cdc_dmm_desc))
goto next_desc;
hdr->usb_cdc_dmm_desc =
(struct usb_cdc_dmm_desc *)buffer;
break;
case USB_CDC_MDLM_TYPE:
if (elength < sizeof(struct usb_cdc_mdlm_desc *))
goto next_desc;
if (desc)
return -EINVAL;
desc = (struct usb_cdc_mdlm_desc *)buffer;
break;
case USB_CDC_MDLM_DETAIL_TYPE:
if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *))
goto next_desc;
if (detail)
return -EINVAL;
detail = (struct usb_cdc_mdlm_detail_desc *)buffer;
break;
case USB_CDC_NCM_TYPE:
if (elength < sizeof(struct usb_cdc_ncm_desc))
goto next_desc;
hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer;
break;
case USB_CDC_MBIM_TYPE:
if (elength < sizeof(struct usb_cdc_mbim_desc))
goto next_desc;
hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer;
break;
case USB_CDC_MBIM_EXTENDED_TYPE:
if (elength < sizeof(struct usb_cdc_mbim_extended_desc))
break;
hdr->usb_cdc_mbim_extended_desc =
(struct usb_cdc_mbim_extended_desc *)buffer;
break;
case CDC_PHONET_MAGIC_NUMBER:
hdr->phonet_magic_present = true;
break;
default:
/*
* there are LOTS more CDC descriptors that
* could legitimately be found here.
*/
dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n",
buffer[2], elength);
goto next_desc;
}
cnt++;
next_desc:
buflen -= elength;
buffer += elength;
}
hdr->usb_cdc_union_desc = union_header;
hdr->usb_cdc_header_desc = header;
hdr->usb_cdc_mdlm_detail_desc = detail;
hdr->usb_cdc_mdlm_desc = desc;
hdr->usb_cdc_ether_desc = ether;
return cnt;
}
EXPORT_SYMBOL(cdc_parse_cdc_header);

View file

@ -128,6 +128,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x04f3, 0x016f), .driver_info =
USB_QUIRK_DEVICE_QUALIFIER },
{ USB_DEVICE(0x04f3, 0x0381), .driver_info =
USB_QUIRK_NO_LPM },
{ USB_DEVICE(0x04f3, 0x21b8), .driver_info =
USB_QUIRK_DEVICE_QUALIFIER },

View file

@ -55,6 +55,7 @@ endchoice
config USB_DWC2_PCI
tristate "DWC2 PCI"
depends on PCI
depends on USB_GADGET || !USB_GADGET
default n
select NOP_USB_XCEIV
help

View file

@ -166,7 +166,7 @@ struct dwc2_hsotg_req;
* 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
* @interval - Interval for periodic endpoints, in frames or microframes.
* @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
@ -177,6 +177,8 @@ struct dwc2_hsotg_req;
* @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
* @target_frame: Targeted frame num to setup next ISOC transfer
* @frame_overrun: Indicates SOF number overrun in DSTS
*
* This is the driver's state for each registered enpoint, allowing it
* to keep track of transactions that need doing. Each endpoint has a
@ -213,7 +215,9 @@ struct dwc2_hsotg_ep {
unsigned int periodic:1;
unsigned int isochronous:1;
unsigned int send_zlp:1;
unsigned int has_correct_parity:1;
unsigned int target_frame;
#define TARGET_FRAME_INITIAL 0xFFFFFFFF
bool frame_overrun;
char name[10];
};

View file

@ -96,6 +96,25 @@ static inline bool using_dma(struct dwc2_hsotg *hsotg)
return hsotg->g_using_dma;
}
/**
* dwc2_gadget_incr_frame_num - Increments the targeted frame number.
* @hs_ep: The endpoint
* @increment: The value to increment by
*
* This function will also check if the frame number overruns DSTS_SOFFN_LIMIT.
* If an overrun occurs it will wrap the value and set the frame_overrun flag.
*/
static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep)
{
hs_ep->target_frame += hs_ep->interval;
if (hs_ep->target_frame > DSTS_SOFFN_LIMIT) {
hs_ep->frame_overrun = 1;
hs_ep->target_frame &= DSTS_SOFFN_LIMIT;
} else {
hs_ep->frame_overrun = 0;
}
}
/**
* dwc2_hsotg_en_gsint - enable one or more of the general interrupt
* @hsotg: The device state
@ -503,6 +522,23 @@ static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep)
return maxsize;
}
/**
* dwc2_hsotg_read_frameno - read current frame number
* @hsotg: The device instance
*
* Return the current frame number
*/
static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg)
{
u32 dsts;
dsts = dwc2_readl(hsotg->regs + DSTS);
dsts &= DSTS_SOFFN_MASK;
dsts >>= DSTS_SOFFN_SHIFT;
return dsts;
}
/**
* dwc2_hsotg_start_req - start a USB request from an endpoint's queue
* @hsotg: The controller state.
@ -631,8 +667,17 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
__func__, &ureq->dma, dma_reg);
}
if (hs_ep->isochronous && hs_ep->interval == 1) {
hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
dwc2_gadget_incr_frame_num(hs_ep);
if (hs_ep->target_frame & 0x1)
ctrl |= DXEPCTL_SETODDFR;
else
ctrl |= DXEPCTL_SETEVENFR;
}
ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */
ctrl |= DXEPCTL_USBACTEP;
dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state);
@ -658,14 +703,6 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
dwc2_hsotg_write_fifo(hsotg, hs_ep, hs_req);
}
/*
* clear the INTknTXFEmpMsk when we start request, more as a aide
* to debugging to see what is going on.
*/
if (dir_in)
dwc2_writel(DIEPMSK_INTKNTXFEMPMSK,
hsotg->regs + DIEPINT(index));
/*
* Note, trying to clear the NAK here causes problems with transmit
* on the S3C6400 ending up with the TXFIFO becoming full.
@ -773,6 +810,30 @@ static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg,
hs_req->saved_req_buf = NULL;
}
/**
* dwc2_gadget_target_frame_elapsed - Checks target frame
* @hs_ep: The driver endpoint to check
*
* Returns 1 if targeted frame elapsed. If returned 1 then we need to drop
* corresponding transfer.
*/
static bool dwc2_gadget_target_frame_elapsed(struct dwc2_hsotg_ep *hs_ep)
{
struct dwc2_hsotg *hsotg = hs_ep->parent;
u32 target_frame = hs_ep->target_frame;
u32 current_frame = dwc2_hsotg_read_frameno(hsotg);
bool frame_overrun = hs_ep->frame_overrun;
if (!frame_overrun && current_frame >= target_frame)
return true;
if (frame_overrun && current_frame >= target_frame &&
((current_frame - target_frame) < DSTS_SOFFN_LIMIT / 2))
return true;
return false;
}
static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t gfp_flags)
{
@ -812,9 +873,18 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
first = list_empty(&hs_ep->queue);
list_add_tail(&hs_req->queue, &hs_ep->queue);
if (first)
dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
if (first) {
if (!hs_ep->isochronous) {
dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
return 0;
}
while (dwc2_gadget_target_frame_elapsed(hs_ep))
dwc2_gadget_incr_frame_num(hs_ep);
if (hs_ep->target_frame != TARGET_FRAME_INITIAL)
dwc2_hsotg_start_req(hs, hs_ep, hs_req, false);
}
return 0;
}
@ -1034,6 +1104,42 @@ static struct dwc2_hsotg_req *get_ep_head(struct dwc2_hsotg_ep *hs_ep)
return list_first_entry(&hs_ep->queue, struct dwc2_hsotg_req, queue);
}
/**
* dwc2_gadget_start_next_request - Starts next request from ep queue
* @hs_ep: Endpoint structure
*
* If queue is empty and EP is ISOC-OUT - unmasks OUTTKNEPDIS which is masked
* in its handler. Hence we need to unmask it here to be able to do
* resynchronization.
*/
static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep)
{
u32 mask;
struct dwc2_hsotg *hsotg = hs_ep->parent;
int dir_in = hs_ep->dir_in;
struct dwc2_hsotg_req *hs_req;
u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK;
if (!list_empty(&hs_ep->queue)) {
hs_req = get_ep_head(hs_ep);
dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false);
return;
}
if (!hs_ep->isochronous)
return;
if (dir_in) {
dev_dbg(hsotg->dev, "%s: No more ISOC-IN requests\n",
__func__);
} else {
dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n",
__func__);
mask = dwc2_readl(hsotg->regs + epmsk_reg);
mask |= DOEPMSK_OUTTKNEPDISMSK;
dwc2_writel(mask, hsotg->regs + epmsk_reg);
}
}
/**
* dwc2_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE
* @hsotg: The device state
@ -1044,7 +1150,6 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
{
struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0];
struct dwc2_hsotg_req *hs_req;
bool restart;
bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
struct dwc2_hsotg_ep *ep;
int ret;
@ -1127,12 +1232,7 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
/* If we have pending request, then start it */
if (!ep->req) {
restart = !list_empty(&ep->queue);
if (restart) {
hs_req = get_ep_head(ep);
dwc2_hsotg_start_req(hsotg, ep,
hs_req, false);
}
dwc2_gadget_start_next_request(ep);
}
}
@ -1373,7 +1473,6 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg,
struct dwc2_hsotg_req *hs_req,
int result)
{
bool restart;
if (!hs_req) {
dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__);
@ -1417,11 +1516,7 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg,
*/
if (!hs_ep->req && result >= 0) {
restart = !list_empty(&hs_ep->queue);
if (restart) {
hs_req = get_ep_head(hs_ep);
dwc2_hsotg_start_req(hsotg, hs_ep, hs_req, false);
}
dwc2_gadget_start_next_request(hs_ep);
}
}
@ -1597,31 +1692,15 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
* adjust the ISOC parity here.
*/
if (!using_dma(hsotg)) {
hs_ep->has_correct_parity = 1;
if (hs_ep->isochronous && hs_ep->interval == 1)
dwc2_hsotg_change_ep_iso_parity(hsotg, DOEPCTL(epnum));
else if (hs_ep->isochronous && hs_ep->interval > 1)
dwc2_gadget_incr_frame_num(hs_ep);
}
dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
}
/**
* dwc2_hsotg_read_frameno - read current frame number
* @hsotg: The device instance
*
* Return the current frame number
*/
static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg)
{
u32 dsts;
dsts = dwc2_readl(hsotg->regs + DSTS);
dsts &= DSTS_SOFFN_MASK;
dsts >>= DSTS_SOFFN_SHIFT;
return dsts;
}
/**
* dwc2_hsotg_handle_rx - RX FIFO has data
* @hsotg: The device instance
@ -1936,6 +2015,190 @@ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg,
dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
}
/**
* dwc2_gadget_read_ep_interrupts - reads interrupts for given ep
* @hsotg: The device state.
* @idx: Index of ep.
* @dir_in: Endpoint direction 1-in 0-out.
*
* Reads for endpoint with given index and direction, by masking
* epint_reg with coresponding mask.
*/
static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg,
unsigned int idx, int dir_in)
{
u32 epmsk_reg = dir_in ? DIEPMSK : DOEPMSK;
u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
u32 ints;
u32 mask;
u32 diepempmsk;
mask = dwc2_readl(hsotg->regs + epmsk_reg);
diepempmsk = dwc2_readl(hsotg->regs + DIEPEMPMSK);
mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0;
mask |= DXEPINT_SETUP_RCVD;
ints = dwc2_readl(hsotg->regs + epint_reg);
ints &= mask;
return ints;
}
/**
* dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD
* @hs_ep: The endpoint on which interrupt is asserted.
*
* This interrupt indicates that the endpoint has been disabled per the
* application's request.
*
* For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK,
* in case of ISOC completes current request.
*
* For ISOC-OUT endpoints completes expired requests. If there is remaining
* request starts it.
*/
static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep)
{
struct dwc2_hsotg *hsotg = hs_ep->parent;
struct dwc2_hsotg_req *hs_req;
unsigned char idx = hs_ep->index;
int dir_in = hs_ep->dir_in;
u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
int dctl = dwc2_readl(hsotg->regs + DCTL);
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
if (dir_in) {
int epctl = dwc2_readl(hsotg->regs + epctl_reg);
dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
if (hs_ep->isochronous) {
dwc2_hsotg_complete_in(hsotg, hs_ep);
return;
}
if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) {
int dctl = dwc2_readl(hsotg->regs + DCTL);
dctl |= DCTL_CGNPINNAK;
dwc2_writel(dctl, hsotg->regs + DCTL);
}
return;
}
if (dctl & DCTL_GOUTNAKSTS) {
dctl |= DCTL_CGOUTNAK;
dwc2_writel(dctl, hsotg->regs + DCTL);
}
if (!hs_ep->isochronous)
return;
if (list_empty(&hs_ep->queue)) {
dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n",
__func__, hs_ep);
return;
}
do {
hs_req = get_ep_head(hs_ep);
if (hs_req)
dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req,
-ENODATA);
dwc2_gadget_incr_frame_num(hs_ep);
} while (dwc2_gadget_target_frame_elapsed(hs_ep));
dwc2_gadget_start_next_request(hs_ep);
}
/**
* dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS
* @hs_ep: The endpoint on which interrupt is asserted.
*
* This is starting point for ISOC-OUT transfer, synchronization done with
* first out token received from host while corresponding EP is disabled.
*
* Device does not know initial frame in which out token will come. For this
* HW generates OUTTKNEPDIS - out token is received while EP is disabled. Upon
* getting this interrupt SW starts calculation for next transfer frame.
*/
static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep)
{
struct dwc2_hsotg *hsotg = ep->parent;
int dir_in = ep->dir_in;
u32 doepmsk;
if (dir_in || !ep->isochronous)
return;
dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), -ENODATA);
if (ep->interval > 1 &&
ep->target_frame == TARGET_FRAME_INITIAL) {
u32 dsts;
u32 ctrl;
dsts = dwc2_readl(hsotg->regs + DSTS);
ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
dwc2_gadget_incr_frame_num(ep);
ctrl = dwc2_readl(hsotg->regs + DOEPCTL(ep->index));
if (ep->target_frame & 0x1)
ctrl |= DXEPCTL_SETODDFR;
else
ctrl |= DXEPCTL_SETEVENFR;
dwc2_writel(ctrl, hsotg->regs + DOEPCTL(ep->index));
}
dwc2_gadget_start_next_request(ep);
doepmsk = dwc2_readl(hsotg->regs + DOEPMSK);
doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK;
dwc2_writel(doepmsk, hsotg->regs + DOEPMSK);
}
/**
* dwc2_gadget_handle_nak - handle NAK interrupt
* @hs_ep: The endpoint on which interrupt is asserted.
*
* This is starting point for ISOC-IN transfer, synchronization done with
* first IN token received from host while corresponding EP is disabled.
*
* Device does not know when first one token will arrive from host. On first
* token arrival HW generates 2 interrupts: 'in token received while FIFO empty'
* and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was
* sent in response to that as there was no data in FIFO. SW is basing on this
* interrupt to obtain frame in which token has come and then based on the
* interval calculates next frame for transfer.
*/
static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
{
struct dwc2_hsotg *hsotg = hs_ep->parent;
int dir_in = hs_ep->dir_in;
if (!dir_in || !hs_ep->isochronous)
return;
if (hs_ep->target_frame == TARGET_FRAME_INITIAL) {
hs_ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
if (hs_ep->interval > 1) {
u32 ctrl = dwc2_readl(hsotg->regs +
DIEPCTL(hs_ep->index));
if (hs_ep->target_frame & 0x1)
ctrl |= DXEPCTL_SETODDFR;
else
ctrl |= DXEPCTL_SETEVENFR;
dwc2_writel(ctrl, hsotg->regs + DIEPCTL(hs_ep->index));
}
dwc2_hsotg_complete_request(hsotg, hs_ep,
get_ep_head(hs_ep), 0);
}
dwc2_gadget_incr_frame_num(hs_ep);
}
/**
* dwc2_hsotg_epint - handle an in/out endpoint interrupt
* @hsotg: The driver state
@ -1954,7 +2217,7 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
u32 ints;
u32 ctrl;
ints = dwc2_readl(hsotg->regs + epint_reg);
ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in);
ctrl = dwc2_readl(hsotg->regs + epctl_reg);
/* Clear endpoint interrupts */
@ -1973,11 +2236,10 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD)))
ints &= ~DXEPINT_XFERCOMPL;
if (ints & DXEPINT_XFERCOMPL) {
hs_ep->has_correct_parity = 1;
if (hs_ep->isochronous && hs_ep->interval == 1)
dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
if (ints & DXEPINT_STSPHSERCVD)
dev_dbg(hsotg->dev, "%s: StsPhseRcvd asserted\n", __func__);
if (ints & DXEPINT_XFERCOMPL) {
dev_dbg(hsotg->dev,
"%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n",
__func__, dwc2_readl(hsotg->regs + epctl_reg),
@ -1988,7 +2250,12 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
* at completing IN requests here
*/
if (dir_in) {
if (hs_ep->isochronous && hs_ep->interval > 1)
dwc2_gadget_incr_frame_num(hs_ep);
dwc2_hsotg_complete_in(hsotg, hs_ep);
if (ints & DXEPINT_NAKINTRPT)
ints &= ~DXEPINT_NAKINTRPT;
if (idx == 0 && !hs_ep->req)
dwc2_hsotg_enqueue_setup(hsotg);
@ -1997,28 +2264,21 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
* We're using DMA, we need to fire an OutDone here
* as we ignore the RXFIFO.
*/
if (hs_ep->isochronous && hs_ep->interval > 1)
dwc2_gadget_incr_frame_num(hs_ep);
dwc2_hsotg_handle_outdone(hsotg, idx);
}
}
if (ints & DXEPINT_EPDISBLD) {
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
if (ints & DXEPINT_EPDISBLD)
dwc2_gadget_handle_ep_disabled(hs_ep);
if (dir_in) {
int epctl = dwc2_readl(hsotg->regs + epctl_reg);
if (ints & DXEPINT_OUTTKNEPDIS)
dwc2_gadget_handle_out_token_ep_disabled(hs_ep);
dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
if ((epctl & DXEPCTL_STALL) &&
(epctl & DXEPCTL_EPTYPE_BULK)) {
int dctl = dwc2_readl(hsotg->regs + DCTL);
dctl |= DCTL_CGNPINNAK;
dwc2_writel(dctl, hsotg->regs + DCTL);
}
}
}
if (ints & DXEPINT_NAKINTRPT)
dwc2_gadget_handle_nak(hs_ep);
if (ints & DXEPINT_AHBERR)
dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
@ -2046,20 +2306,20 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
if (dir_in && !hs_ep->isochronous) {
/* not sure if this is important, but we'll clear it anyway */
if (ints & DIEPMSK_INTKNTXFEMPMSK) {
if (ints & DXEPINT_INTKNTXFEMP) {
dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
__func__, idx);
}
/* this probably means something bad is happening */
if (ints & DIEPMSK_INTKNEPMISMSK) {
if (ints & DXEPINT_INTKNEPMIS) {
dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
__func__, idx);
}
/* FIFO has space or is empty (see GAHBCFG) */
if (hsotg->dedicated_fifos &&
ints & DIEPMSK_TXFIFOEMPTY) {
ints & DXEPINT_TXFEMP) {
dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
__func__, idx);
if (!using_dma(hsotg))
@ -2322,18 +2582,16 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) |
DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
DIEPMSK_INTKNEPMISMSK,
DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK,
hsotg->regs + DIEPMSK);
/*
* don't need XferCompl, we get that from RXFIFO in slave mode. In
* DMA mode we may need this.
*/
dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK |
DIEPMSK_TIMEOUTMSK) : 0) |
dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK) : 0) |
DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK |
DOEPMSK_SETUPMSK,
DOEPMSK_SETUPMSK | DOEPMSK_STSPHSERCVDMSK,
hsotg->regs + DOEPMSK);
dwc2_writel(0, hsotg->regs + DAINTMSK);
@ -2413,6 +2671,85 @@ void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg)
__bic32(hsotg->regs + DCTL, DCTL_SFTDISCON);
}
/**
* dwc2_gadget_handle_incomplete_isoc_in - handle incomplete ISO IN Interrupt.
* @hsotg: The device state:
*
* This interrupt indicates one of the following conditions occurred while
* transmitting an ISOC transaction.
* - Corrupted IN Token for ISOC EP.
* - Packet not complete in FIFO.
*
* The following actions will be taken:
* - Determine the EP
* - Disable EP; when 'Endpoint Disabled' interrupt is received Flush FIFO
*/
static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg)
{
struct dwc2_hsotg_ep *hs_ep;
u32 epctrl;
u32 idx;
dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n");
for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_in[idx];
epctrl = dwc2_readl(hsotg->regs + DIEPCTL(idx));
if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous &&
dwc2_gadget_target_frame_elapsed(hs_ep)) {
epctrl |= DXEPCTL_SNAK;
epctrl |= DXEPCTL_EPDIS;
dwc2_writel(epctrl, hsotg->regs + DIEPCTL(idx));
}
}
/* Clear interrupt */
dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS);
}
/**
* dwc2_gadget_handle_incomplete_isoc_out - handle incomplete ISO OUT Interrupt
* @hsotg: The device state:
*
* This interrupt indicates one of the following conditions occurred while
* transmitting an ISOC transaction.
* - Corrupted OUT Token for ISOC EP.
* - Packet not complete in FIFO.
*
* The following actions will be taken:
* - Determine the EP
* - Set DCTL_SGOUTNAK and unmask GOUTNAKEFF if target frame elapsed.
*/
static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg)
{
u32 gintsts;
u32 gintmsk;
u32 epctrl;
struct dwc2_hsotg_ep *hs_ep;
int idx;
dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__);
for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_out[idx];
epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));
if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous &&
dwc2_gadget_target_frame_elapsed(hs_ep)) {
/* Unmask GOUTNAKEFF interrupt */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk |= GINTSTS_GOUTNAKEFF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
if (!(gintsts & GINTSTS_GOUTNAKEFF))
__orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
}
}
/* Clear interrupt */
dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS);
}
/**
* dwc2_hsotg_irq - handle device interrupt
* @irq: The IRQ number triggered
@ -2545,11 +2882,29 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
*/
if (gintsts & GINTSTS_GOUTNAKEFF) {
dev_info(hsotg->dev, "GOUTNakEff triggered\n");
u8 idx;
u32 epctrl;
u32 gintmsk;
struct dwc2_hsotg_ep *hs_ep;
__orr32(hsotg->regs + DCTL, DCTL_CGOUTNAK);
/* Mask this interrupt */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
gintmsk &= ~GINTSTS_GOUTNAKEFF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
dwc2_hsotg_dump(hsotg);
dev_dbg(hsotg->dev, "GOUTNakEff triggered\n");
for (idx = 1; idx <= hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_out[idx];
epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));
if ((epctrl & DXEPCTL_EPENA) && hs_ep->isochronous) {
epctrl |= DXEPCTL_SNAK;
epctrl |= DXEPCTL_EPDIS;
dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx));
}
}
/* This interrupt bit is cleared in DXEPINT_EPDISBLD handler */
}
if (gintsts & GINTSTS_GINNAKEFF) {
@ -2560,39 +2915,11 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
dwc2_hsotg_dump(hsotg);
}
if (gintsts & GINTSTS_INCOMPL_SOIN) {
u32 idx, epctl_reg;
struct dwc2_hsotg_ep *hs_ep;
if (gintsts & GINTSTS_INCOMPL_SOIN)
dwc2_gadget_handle_incomplete_isoc_in(hsotg);
dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOIN\n", __func__);
for (idx = 1; idx < hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_in[idx];
if (!hs_ep->isochronous || hs_ep->has_correct_parity)
continue;
epctl_reg = DIEPCTL(idx);
dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
}
dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS);
}
if (gintsts & GINTSTS_INCOMPL_SOOUT) {
u32 idx, epctl_reg;
struct dwc2_hsotg_ep *hs_ep;
dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__);
for (idx = 1; idx < hsotg->num_of_eps; idx++) {
hs_ep = hsotg->eps_out[idx];
if (!hs_ep->isochronous || hs_ep->has_correct_parity)
continue;
epctl_reg = DOEPCTL(idx);
dwc2_hsotg_change_ep_iso_parity(hsotg, epctl_reg);
}
dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS);
}
if (gintsts & GINTSTS_INCOMPL_SOOUT)
dwc2_gadget_handle_incomplete_isoc_out(hsotg);
/*
* if we've had fifo events, we should try and go around the
@ -2624,6 +2951,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
u32 epctrl_reg;
u32 epctrl;
u32 mps;
u32 mask;
unsigned int dir_in;
unsigned int i, val, size;
int ret = 0;
@ -2666,15 +2994,6 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
*/
epctrl |= DXEPCTL_USBACTEP;
/*
* set the NAK status on the endpoint, otherwise we might try and
* do something with data that we've yet got a request to process
* since the RXFIFO will take data for an endpoint even if the
* size register hasn't been set.
*/
epctrl |= DXEPCTL_SNAK;
/* update the endpoint state */
dwc2_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in);
@ -2683,18 +3002,24 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
hs_ep->periodic = 0;
hs_ep->halted = 0;
hs_ep->interval = desc->bInterval;
hs_ep->has_correct_parity = 0;
if (hs_ep->interval > 1 && hs_ep->mc > 1)
dev_err(hsotg->dev, "MC > 1 when interval is not 1\n");
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_ISOC:
epctrl |= DXEPCTL_EPTYPE_ISO;
epctrl |= DXEPCTL_SETEVENFR;
hs_ep->isochronous = 1;
if (dir_in)
hs_ep->interval = 1 << (desc->bInterval - 1);
hs_ep->target_frame = TARGET_FRAME_INITIAL;
if (dir_in) {
hs_ep->periodic = 1;
mask = dwc2_readl(hsotg->regs + DIEPMSK);
mask |= DIEPMSK_NAKMSK;
dwc2_writel(mask, hsotg->regs + DIEPMSK);
} else {
mask = dwc2_readl(hsotg->regs + DOEPMSK);
mask |= DOEPMSK_OUTTKNEPDISMSK;
dwc2_writel(mask, hsotg->regs + DOEPMSK);
}
break;
case USB_ENDPOINT_XFER_BULK:
@ -2705,6 +3030,9 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
if (dir_in)
hs_ep->periodic = 1;
if (hsotg->gadget.speed == USB_SPEED_HIGH)
hs_ep->interval = 1 << (desc->bInterval - 1);
epctrl |= DXEPCTL_EPTYPE_INTERRUPT;
break;
@ -2758,7 +3086,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
}
/* for non control endpoints, set PID to D0 */
if (index)
if (index && !hs_ep->isochronous)
epctrl |= DXEPCTL_SETD0PID;
dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
@ -2875,10 +3203,8 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
dev_warn(hsotg->dev,
"%s: timeout DIEPINT.NAKEFF\n", __func__);
} else {
/* Clear any pending nak effect interrupt */
dwc2_writel(GINTSTS_GOUTNAKEFF, hsotg->regs + GINTSTS);
__orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF))
__orr32(hsotg->regs + DCTL, DCTL_SGOUTNAK);
/* Wait for global nak to take effect */
if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,

View file

@ -367,7 +367,8 @@ static void pmap_unschedule(unsigned long *map, int bits_per_period,
* @fmt: The format for printf.
* @...: The args for printf.
*/
static void cat_printf(char **buf, size_t *size, const char *fmt, ...)
static __printf(3, 4)
void cat_printf(char **buf, size_t *size, const char *fmt, ...)
{
va_list args;
int i;

View file

@ -459,6 +459,9 @@
#define DSTS_SUSPSTS (1 << 0)
#define DIEPMSK HSOTG_REG(0x810)
#define DIEPMSK_NAKMSK (1 << 13)
#define DIEPMSK_BNAININTRMSK (1 << 9)
#define DIEPMSK_TXFIFOUNDRNMSK (1 << 8)
#define DIEPMSK_TXFIFOEMPTY (1 << 7)
#define DIEPMSK_INEPNAKEFFMSK (1 << 6)
#define DIEPMSK_INTKNEPMISMSK (1 << 5)
@ -470,6 +473,7 @@
#define DOEPMSK HSOTG_REG(0x814)
#define DOEPMSK_BACK2BACKSETUP (1 << 6)
#define DOEPMSK_STSPHSERCVDMSK (1 << 5)
#define DOEPMSK_OUTTKNEPDISMSK (1 << 4)
#define DOEPMSK_SETUPMSK (1 << 3)
#define DOEPMSK_AHBERRMSK (1 << 2)
@ -486,6 +490,7 @@
#define DTKNQR2 HSOTG_REG(0x824)
#define DTKNQR3 HSOTG_REG(0x830)
#define DTKNQR4 HSOTG_REG(0x834)
#define DIEPEMPMSK HSOTG_REG(0x834)
#define DVBUSDIS HSOTG_REG(0x828)
#define DVBUSPULSE HSOTG_REG(0x82C)
@ -544,9 +549,18 @@
#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
#define DXEPINT_SETUP_RCVD (1 << 15)
#define DXEPINT_NYETINTRPT (1 << 14)
#define DXEPINT_NAKINTRPT (1 << 13)
#define DXEPINT_BBLEERRINTRPT (1 << 12)
#define DXEPINT_PKTDRPSTS (1 << 11)
#define DXEPINT_BNAINTR (1 << 9)
#define DXEPINT_TXFIFOUNDRN (1 << 8)
#define DXEPINT_OUTPKTERR (1 << 8)
#define DXEPINT_TXFEMP (1 << 7)
#define DXEPINT_INEPNAKEFF (1 << 6)
#define DXEPINT_BACK2BACKSETUP (1 << 6)
#define DXEPINT_INTKNEPMIS (1 << 5)
#define DXEPINT_STSPHSERCVD (1 << 5)
#define DXEPINT_INTKNTXFEMP (1 << 4)
#define DXEPINT_OUTTKNEPDIS (1 << 4)
#define DXEPINT_TIMEOUT (1 << 3)

View file

@ -41,14 +41,13 @@
#include <linux/usb/of.h>
#include <linux/usb/otg.h>
#include "platform_data.h"
#include "core.h"
#include "gadget.h"
#include "io.h"
#include "debug.h"
/* -------------------------------------------------------------------------- */
#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
@ -149,9 +148,8 @@ static int dwc3_soft_reset(struct dwc3 *dwc)
/*
* dwc3_frame_length_adjustment - Adjusts frame length if required
* @dwc3: Pointer to our controller context structure
* @fladj: Value of GFLADJ_30MHZ to adjust frame length
*/
static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
{
u32 reg;
u32 dft;
@ -159,15 +157,15 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj)
if (dwc->revision < DWC3_REVISION_250A)
return;
if (fladj == 0)
if (dwc->fladj == 0)
return;
reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
dft = reg & DWC3_GFLADJ_30MHZ_MASK;
if (!dev_WARN_ONCE(dwc->dev, dft == fladj,
if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj,
"request value same as default, ignoring\n")) {
reg &= ~DWC3_GFLADJ_30MHZ_MASK;
reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj;
reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
}
}
@ -507,6 +505,21 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
return 0;
}
static void dwc3_core_exit(struct dwc3 *dwc)
{
dwc3_event_buffers_cleanup(dwc);
usb_phy_shutdown(dwc->usb2_phy);
usb_phy_shutdown(dwc->usb3_phy);
phy_exit(dwc->usb2_generic_phy);
phy_exit(dwc->usb3_generic_phy);
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
phy_power_off(dwc->usb2_generic_phy);
phy_power_off(dwc->usb3_generic_phy);
}
/**
* dwc3_core_init - Low-level initialization of DWC3 Core
* @dwc: Pointer to our controller context structure
@ -556,6 +569,10 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (ret)
goto err0;
ret = dwc3_phy_setup(dwc);
if (ret)
goto err0;
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
@ -622,22 +639,45 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN;
dwc3_core_num_eps(dwc);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err1;
dwc3_core_num_eps(dwc);
ret = dwc3_setup_scratch_buffers(dwc);
if (ret)
goto err1;
/* Adjust Frame Length */
dwc3_frame_length_adjustment(dwc);
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
ret = phy_power_on(dwc->usb2_generic_phy);
if (ret < 0)
goto err2;
ret = phy_power_on(dwc->usb3_generic_phy);
if (ret < 0)
goto err3;
ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
goto err4;
}
return 0;
err4:
phy_power_off(dwc->usb2_generic_phy);
err3:
phy_power_off(dwc->usb3_generic_phy);
err2:
dwc3_free_scratch_buffers(dwc);
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
dwc3_core_exit(dwc);
err1:
usb_phy_shutdown(dwc->usb2_phy);
@ -649,15 +689,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
return ret;
}
static void dwc3_core_exit(struct dwc3 *dwc)
{
dwc3_free_scratch_buffers(dwc);
usb_phy_shutdown(dwc->usb2_phy);
usb_phy_shutdown(dwc->usb3_phy);
phy_exit(dwc->usb2_generic_phy);
phy_exit(dwc->usb3_generic_phy);
}
static int dwc3_core_get_phy(struct dwc3 *dwc)
{
struct device *dev = dwc->dev;
@ -735,7 +766,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize gadget\n");
return ret;
}
break;
@ -743,7 +775,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize host\n");
return ret;
}
break;
@ -751,13 +784,15 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize host\n");
return ret;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize gadget\n");
return ret;
}
break;
@ -793,13 +828,11 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dwc3_platform_data *pdata = dev_get_platdata(dev);
struct resource *res;
struct dwc3 *dwc;
u8 lpm_nyet_threshold;
u8 tx_de_emphasis;
u8 hird_threshold;
u32 fladj = 0;
int ret;
@ -814,16 +847,6 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->mem = mem;
dwc->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
dwc->xhci_resources[1].start = res->start;
dwc->xhci_resources[1].end = res->end;
dwc->xhci_resources[1].flags = res->flags;
dwc->xhci_resources[1].name = res->name;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory resource\n");
@ -909,40 +932,7 @@ static int dwc3_probe(struct platform_device *pdev)
device_property_read_string(dev, "snps,hsphy_interface",
&dwc->hsphy_interface);
device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
&fladj);
if (pdata) {
dwc->maximum_speed = pdata->maximum_speed;
dwc->has_lpm_erratum = pdata->has_lpm_erratum;
if (pdata->lpm_nyet_threshold)
lpm_nyet_threshold = pdata->lpm_nyet_threshold;
dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend;
if (pdata->hird_threshold)
hird_threshold = pdata->hird_threshold;
dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
dwc->dr_mode = pdata->dr_mode;
dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk;
dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk;
dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk;
dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk;
dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk;
dwc->lfps_filter_quirk = pdata->lfps_filter_quirk;
dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk;
dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
if (pdata->tx_de_emphasis)
tx_de_emphasis = pdata->tx_de_emphasis;
dwc->hsphy_interface = pdata->hsphy_interface;
fladj = pdata->fladj_value;
}
&dwc->fladj);
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
dwc->tx_de_emphasis = tx_de_emphasis;
@ -953,10 +943,6 @@ static int dwc3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dwc);
dwc3_cache_hwparams(dwc);
ret = dwc3_phy_setup(dwc);
if (ret)
goto err0;
ret = dwc3_core_get_phy(dwc);
if (ret)
goto err0;
@ -969,29 +955,43 @@ static int dwc3_probe(struct platform_device *pdev)
dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
}
pm_runtime_set_active(dev);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err1;
pm_runtime_forbid(dev);
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
ret = -ENOMEM;
goto err1;
goto err2;
}
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
if (IS_ENABLED(CONFIG_USB_DWC3_HOST) &&
(dwc->dr_mode == USB_DR_MODE_OTG ||
dwc->dr_mode == USB_DR_MODE_UNKNOWN))
dwc->dr_mode = USB_DR_MODE_HOST;
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) &&
(dwc->dr_mode == USB_DR_MODE_OTG ||
dwc->dr_mode == USB_DR_MODE_UNKNOWN))
dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
dwc->dr_mode = USB_DR_MODE_OTG;
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err3;
ret = dwc3_core_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize core\n");
goto err1;
goto err4;
}
/* Check the maximum_speed parameter */
@ -1021,31 +1021,12 @@ static int dwc3_probe(struct platform_device *pdev)
break;
}
/* Adjust Frame Length */
dwc3_frame_length_adjustment(dwc, fladj);
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
ret = phy_power_on(dwc->usb2_generic_phy);
if (ret < 0)
goto err2;
ret = phy_power_on(dwc->usb3_generic_phy);
if (ret < 0)
goto err3;
ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
goto err4;
}
ret = dwc3_core_init_mode(dwc);
if (ret)
goto err5;
dwc3_debugfs_init(dwc);
pm_runtime_allow(dev);
pm_runtime_put(dev);
return 0;
@ -1053,20 +1034,19 @@ static int dwc3_probe(struct platform_device *pdev)
dwc3_event_buffers_cleanup(dwc);
err4:
phy_power_off(dwc->usb3_generic_phy);
dwc3_free_scratch_buffers(dwc);
err3:
phy_power_off(dwc->usb2_generic_phy);
err2:
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
dwc3_core_exit(dwc);
err1:
dwc3_free_event_buffers(dwc);
dwc3_ulpi_exit(dwc);
err2:
pm_runtime_allow(&pdev->dev);
err1:
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
err0:
/*
* restore res->start back to its original value so that, in case the
@ -1083,6 +1063,7 @@ static int dwc3_remove(struct platform_device *pdev)
struct dwc3 *dwc = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pm_runtime_get_sync(&pdev->dev);
/*
* restore res->start back to its original value so that, in case the
* probe is deferred, we don't end up getting error in request the
@ -1092,54 +1073,161 @@ static int dwc3_remove(struct platform_device *pdev)
dwc3_debugfs_exit(dwc);
dwc3_core_exit_mode(dwc);
dwc3_event_buffers_cleanup(dwc);
dwc3_free_event_buffers(dwc);
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
phy_power_off(dwc->usb2_generic_phy);
phy_power_off(dwc->usb3_generic_phy);
dwc3_core_exit(dwc);
dwc3_ulpi_exit(dwc);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_allow(&pdev->dev);
pm_runtime_disable(&pdev->dev);
dwc3_free_event_buffers(dwc);
dwc3_free_scratch_buffers(dwc);
return 0;
}
#ifdef CONFIG_PM
static int dwc3_suspend_common(struct dwc3 *dwc)
{
unsigned long flags;
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
break;
case USB_DR_MODE_HOST:
default:
/* do nothing */
break;
}
dwc3_core_exit(dwc);
return 0;
}
static int dwc3_resume_common(struct dwc3 *dwc)
{
unsigned long flags;
int ret;
ret = dwc3_core_init(dwc);
if (ret)
return ret;
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
/* FALLTHROUGH */
case USB_DR_MODE_HOST:
default:
/* do nothing */
break;
}
return 0;
}
static int dwc3_runtime_checks(struct dwc3 *dwc)
{
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
if (dwc->connected)
return -EBUSY;
break;
case USB_DR_MODE_HOST:
default:
/* do nothing */
break;
}
return 0;
}
static int dwc3_runtime_suspend(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
if (dwc3_runtime_checks(dwc))
return -EBUSY;
ret = dwc3_suspend_common(dwc);
if (ret)
return ret;
device_init_wakeup(dev, true);
return 0;
}
static int dwc3_runtime_resume(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
int ret;
device_init_wakeup(dev, false);
ret = dwc3_resume_common(dwc);
if (ret)
return ret;
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
dwc3_gadget_process_pending_events(dwc);
break;
case USB_DR_MODE_HOST:
default:
/* do nothing */
break;
}
pm_runtime_mark_last_busy(dev);
return 0;
}
static int dwc3_runtime_idle(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
if (dwc3_runtime_checks(dwc))
return -EBUSY;
break;
case USB_DR_MODE_HOST:
default:
/* do nothing */
break;
}
pm_runtime_mark_last_busy(dev);
pm_runtime_autosuspend(dev);
return 0;
}
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
static int dwc3_suspend(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
unsigned long flags;
int ret;
spin_lock_irqsave(&dwc->lock, flags);
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
dwc3_gadget_suspend(dwc);
/* FALLTHROUGH */
case USB_DR_MODE_HOST:
default:
dwc3_event_buffers_cleanup(dwc);
break;
}
dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
spin_unlock_irqrestore(&dwc->lock, flags);
usb_phy_shutdown(dwc->usb3_phy);
usb_phy_shutdown(dwc->usb2_phy);
phy_exit(dwc->usb2_generic_phy);
phy_exit(dwc->usb3_generic_phy);
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
WARN_ON(phy_power_off(dwc->usb2_generic_phy) < 0);
WARN_ON(phy_power_off(dwc->usb3_generic_phy) < 0);
ret = dwc3_suspend_common(dwc);
if (ret)
return ret;
pinctrl_pm_select_sleep_state(dev);
@ -1149,76 +1237,28 @@ static int dwc3_suspend(struct device *dev)
static int dwc3_resume(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
unsigned long flags;
int ret;
pinctrl_pm_select_default_state(dev);
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
ret = phy_power_on(dwc->usb2_generic_phy);
if (ret < 0)
ret = dwc3_resume_common(dwc);
if (ret)
return ret;
ret = phy_power_on(dwc->usb3_generic_phy);
if (ret < 0)
goto err_usb2phy_power;
usb_phy_init(dwc->usb3_phy);
usb_phy_init(dwc->usb2_phy);
ret = phy_init(dwc->usb2_generic_phy);
if (ret < 0)
goto err_usb3phy_power;
ret = phy_init(dwc->usb3_generic_phy);
if (ret < 0)
goto err_usb2phy_init;
spin_lock_irqsave(&dwc->lock, flags);
dwc3_event_buffers_setup(dwc);
dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
dwc3_gadget_resume(dwc);
/* FALLTHROUGH */
case USB_DR_MODE_HOST:
default:
/* do nothing */
break;
}
spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
err_usb2phy_init:
phy_exit(dwc->usb2_generic_phy);
err_usb3phy_power:
phy_power_off(dwc->usb3_generic_phy);
err_usb2phy_power:
phy_power_off(dwc->usb2_generic_phy);
return ret;
}
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops dwc3_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
dwc3_runtime_idle)
};
#define DWC3_PM_OPS &(dwc3_dev_pm_ops)
#else
#define DWC3_PM_OPS NULL
#endif
#ifdef CONFIG_OF
static const struct of_device_id of_dwc3_match[] = {
{
@ -1250,7 +1290,7 @@ static struct platform_driver dwc3_driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
.acpi_match_table = ACPI_PTR(dwc3_acpi_match),
.pm = DWC3_PM_OPS,
.pm = &dwc3_dev_pm_ops,
},
};

View file

@ -86,6 +86,7 @@
#define DWC3_GCTL 0xc110
#define DWC3_GEVTEN 0xc114
#define DWC3_GSTS 0xc118
#define DWC3_GUCTL1 0xc11c
#define DWC3_GSNPSID 0xc120
#define DWC3_GGPIO 0xc124
#define DWC3_GUID 0xc128
@ -138,10 +139,12 @@
#define DWC3_DGCMDPAR 0xc710
#define DWC3_DGCMD 0xc714
#define DWC3_DALEPENA 0xc720
#define DWC3_DEPCMDPAR2(n) (0xc800 + (n * 0x10))
#define DWC3_DEPCMDPAR1(n) (0xc804 + (n * 0x10))
#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10))
#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10))
#define DWC3_DEP_BASE(n) (0xc800 + (n * 0x10))
#define DWC3_DEPCMDPAR2 0x00
#define DWC3_DEPCMDPAR1 0x04
#define DWC3_DEPCMDPAR0 0x08
#define DWC3_DEPCMD 0x0c
/* OTG Registers */
#define DWC3_OCFG 0xcc00
@ -231,6 +234,14 @@
#define DWC3_GEVNTSIZ_INTMASK (1 << 31)
#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff)
/* Global HWPARAMS0 Register */
#define DWC3_GHWPARAMS0_USB3_MODE(n) ((n) & 0x3)
#define DWC3_GHWPARAMS0_MBUS_TYPE(n) (((n) >> 3) & 0x7)
#define DWC3_GHWPARAMS0_SBUS_TYPE(n) (((n) >> 6) & 0x3)
#define DWC3_GHWPARAMS0_MDWIDTH(n) (((n) >> 8) & 0xff)
#define DWC3_GHWPARAMS0_SDWIDTH(n) (((n) >> 16) & 0xff)
#define DWC3_GHWPARAMS0_AWIDTH(n) (((n) >> 24) & 0xff)
/* Global HWPARAMS1 Register */
#define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24)
#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
@ -260,6 +271,10 @@
/* Global HWPARAMS6 Register */
#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7)
/* Global HWPARAMS7 Register */
#define DWC3_GHWPARAMS7_RAM1_DEPTH(n) ((n) & 0xffff)
#define DWC3_GHWPARAMS7_RAM2_DEPTH(n) (((n) >> 16) & 0xffff)
/* Global Frame Length Adjustment Register */
#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
#define DWC3_GFLADJ_30MHZ_MASK 0x3f
@ -468,6 +483,8 @@ struct dwc3_event_buffer {
* @endpoint: usb endpoint
* @pending_list: list of pending requests for this endpoint
* @started_list: list of started requests on this endpoint
* @lock: spinlock for endpoint request queue traversal
* @regs: pointer to first endpoint register
* @trb_pool: array of transaction buffers
* @trb_pool_dma: dma address of @trb_pool
* @trb_enqueue: enqueue 'pointer' into TRB array
@ -480,6 +497,8 @@ struct dwc3_event_buffer {
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
* @resource_index: Resource transfer index
* @interval: the interval on which the ISOC transfer is started
* @allocated_requests: number of requests allocated
* @queued_requests: number of requests queued for transfer
* @name: a human readable name e.g. ep1out-bulk
* @direction: true for TX, false for RX
* @stream_capable: true when streams are enabled
@ -489,6 +508,9 @@ struct dwc3_ep {
struct list_head pending_list;
struct list_head started_list;
spinlock_t lock;
void __iomem *regs;
struct dwc3_trb *trb_pool;
dma_addr_t trb_pool_dma;
const struct usb_ss_ep_comp_descriptor *comp_desc;
@ -521,6 +543,8 @@ struct dwc3_ep {
u8 number;
u8 type;
u8 resource_index;
u32 allocated_requests;
u32 queued_requests;
u32 interval;
char name[20];
@ -712,6 +736,8 @@ struct dwc3_scratchpad_array {
* @gadget_driver: pointer to the gadget driver
* @regs: base address for our registers
* @regs_size: address space size
* @fladj: frame length adjustment
* @irq_gadget: peripheral controller's IRQ number
* @nr_scratch: number of scratch buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
@ -744,6 +770,7 @@ struct dwc3_scratchpad_array {
* @lpm_nyet_threshold: LPM NYET response threshold
* @hird_threshold: HIRD threshold
* @hsphy_interface: "utmi" or "ulpi"
* @connected: true when we're connected to a host, false otherwise
* @delayed_status: true when gadget driver asks for delayed status
* @ep0_bounced: true when we used bounce buffer
* @ep0_expect_in: true when we expect a DATA IN transfer
@ -754,6 +781,7 @@ struct dwc3_scratchpad_array {
* 0 - utmi_sleep_n
* 1 - utmi_l1_suspend_n
* @is_fpga: true when we are using the FPGA board
* @pending_events: true when we have pending IRQs to be handled
* @pullups_connected: true when Run/Stop bit is set
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @start_config_issued: true when StartConfig command has been issued
@ -818,10 +846,8 @@ struct dwc3 {
enum usb_dr_mode dr_mode;
/* used for suspend/resume */
u32 dcfg;
u32 gctl;
u32 fladj;
u32 irq_gadget;
u32 nr_scratch;
u32 u1u2;
u32 maximum_speed;
@ -860,7 +886,7 @@ struct dwc3 {
* just so dwc31 revisions are always larger than dwc3.
*/
#define DWC3_REVISION_IS_DWC31 0x80000000
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31)
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31)
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@ -890,6 +916,7 @@ struct dwc3 {
const char *hsphy_interface;
unsigned connected:1;
unsigned delayed_status:1;
unsigned ep0_bounced:1;
unsigned ep0_expect_in:1;
@ -897,6 +924,7 @@ struct dwc3 {
unsigned has_lpm_erratum:1;
unsigned is_utmi_l1_suspend:1;
unsigned is_fpga:1;
unsigned pending_events:1;
unsigned pullups_connected:1;
unsigned setup_packet_pending:1;
unsigned three_stage_setup:1;
@ -1094,8 +1122,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc);
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
int dwc3_gadget_get_link_state(struct dwc3 *dwc);
int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
struct dwc3_gadget_ep_cmd_params *params);
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param);
#else
static inline int dwc3_gadget_init(struct dwc3 *dwc)
@ -1110,8 +1138,8 @@ static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc,
enum dwc3_link_state state)
{ return 0; }
static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
struct dwc3_gadget_ep_cmd_params *params)
{ return 0; }
static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
int cmd, u32 param)
@ -1122,6 +1150,7 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
int dwc3_gadget_suspend(struct dwc3 *dwc);
int dwc3_gadget_resume(struct dwc3 *dwc);
void dwc3_gadget_process_pending_events(struct dwc3 *dwc);
#else
static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
{
@ -1132,6 +1161,10 @@ static inline int dwc3_gadget_resume(struct dwc3 *dwc)
{
return 0;
}
static inline void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
{
}
#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
#if IS_ENABLED(CONFIG_USB_DWC3_ULPI)

View file

@ -128,56 +128,112 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
* dwc3_gadget_event_string - returns event name
* @event: the event code
*/
static inline const char *dwc3_gadget_event_string(u8 event)
static inline const char *
dwc3_gadget_event_string(const struct dwc3_event_devt *event)
{
switch (event) {
static char str[256];
enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK;
switch (event->type) {
case DWC3_DEVICE_EVENT_DISCONNECT:
return "Disconnect";
sprintf(str, "Disconnect: [%s]",
dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_RESET:
return "Reset";
sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_CONNECT_DONE:
return "Connection Done";
sprintf(str, "Connection Done [%s]",
dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
return "Link Status Change";
sprintf(str, "Link Change [%s]",
dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_WAKEUP:
return "WakeUp";
sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_EOPF:
return "End-Of-Frame";
sprintf(str, "End-Of-Frame [%s]",
dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_SOF:
return "Start-Of-Frame";
sprintf(str, "Start-Of-Frame [%s]",
dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
return "Erratic Error";
sprintf(str, "Erratic Error [%s]",
dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
return "Command Complete";
sprintf(str, "Command Complete [%s]",
dwc3_gadget_link_string(state));
break;
case DWC3_DEVICE_EVENT_OVERFLOW:
return "Overflow";
sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state));
break;
default:
sprintf(str, "UNKNOWN");
}
return "UNKNOWN";
return str;
}
/**
* dwc3_ep_event_string - returns event name
* @event: then event code
*/
static inline const char *dwc3_ep_event_string(u8 event)
static inline const char *
dwc3_ep_event_string(const struct dwc3_event_depevt *event)
{
switch (event) {
u8 epnum = event->endpoint_number;
static char str[256];
int status;
int ret;
ret = sprintf(str, "ep%d%s: ", epnum >> 1,
(epnum & 1) ? "in" : "in");
if (ret < 0)
return "UNKNOWN";
switch (event->endpoint_event) {
case DWC3_DEPEVT_XFERCOMPLETE:
return "Transfer Complete";
strcat(str, "Transfer Complete");
break;
case DWC3_DEPEVT_XFERINPROGRESS:
return "Transfer In-Progress";
strcat(str, "Transfer In-Progress");
break;
case DWC3_DEPEVT_XFERNOTREADY:
return "Transfer Not Ready";
strcat(str, "Transfer Not Ready");
status = event->status & DEPEVT_STATUS_TRANSFER_ACTIVE;
strcat(str, status ? " (Active)" : " (Not Active)");
break;
case DWC3_DEPEVT_RXTXFIFOEVT:
return "FIFO";
strcat(str, "FIFO");
break;
case DWC3_DEPEVT_STREAMEVT:
return "Stream";
status = event->status;
switch (status) {
case DEPEVT_STREAMEVT_FOUND:
sprintf(str + ret, " Stream %d Found",
event->parameters);
break;
case DEPEVT_STREAMEVT_NOTFOUND:
default:
strcat(str, " Stream Not Found");
break;
}
break;
case DWC3_DEPEVT_EPCMDCMPLT:
return "Endpoint Command Complete";
strcat(str, "Endpoint Command Complete");
break;
default:
sprintf(str, "UNKNOWN");
}
return "UNKNOWN";
return str;
}
/**
@ -214,6 +270,46 @@ static inline const char *dwc3_gadget_event_type_string(u8 event)
}
}
static inline const char *dwc3_decode_event(u32 event)
{
const union dwc3_event evt = (union dwc3_event) event;
if (evt.type.is_devspec)
return dwc3_gadget_event_string(&evt.devt);
else
return dwc3_ep_event_string(&evt.depevt);
}
static inline const char *dwc3_ep_cmd_status_string(int status)
{
switch (status) {
case -ETIMEDOUT:
return "Timed Out";
case 0:
return "Successful";
case DEPEVT_TRANSFER_NO_RESOURCE:
return "No Resource";
case DEPEVT_TRANSFER_BUS_EXPIRY:
return "Bus Expiry";
default:
return "UNKNOWN";
}
}
static inline const char *dwc3_gadget_generic_cmd_status_string(int status)
{
switch (status) {
case -ETIMEDOUT:
return "Timed Out";
case 0:
return "Successful";
case 1:
return "Error";
default:
return "UNKNOWN";
}
}
void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);
#ifdef CONFIG_DEBUG_FS

View file

@ -36,9 +36,32 @@
#define dump_register(nm) \
{ \
.name = __stringify(nm), \
.offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
.offset = DWC3_ ##nm, \
}
#define dump_ep_register_set(n) \
{ \
.name = "DEPCMDPAR2("__stringify(n)")", \
.offset = DWC3_DEP_BASE(n) + \
DWC3_DEPCMDPAR2, \
}, \
{ \
.name = "DEPCMDPAR1("__stringify(n)")", \
.offset = DWC3_DEP_BASE(n) + \
DWC3_DEPCMDPAR1, \
}, \
{ \
.name = "DEPCMDPAR0("__stringify(n)")", \
.offset = DWC3_DEP_BASE(n) + \
DWC3_DEPCMDPAR0, \
}, \
{ \
.name = "DEPCMD("__stringify(n)")", \
.offset = DWC3_DEP_BASE(n) + \
DWC3_DEPCMD, \
}
static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GSBUSCFG0),
dump_register(GSBUSCFG1),
@ -47,6 +70,7 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GCTL),
dump_register(GEVTEN),
dump_register(GSTS),
dump_register(GUCTL1),
dump_register(GSNPSID),
dump_register(GGPIO),
dump_register(GUID),
@ -218,137 +242,38 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(DGCMD),
dump_register(DALEPENA),
dump_register(DEPCMDPAR2(0)),
dump_register(DEPCMDPAR2(1)),
dump_register(DEPCMDPAR2(2)),
dump_register(DEPCMDPAR2(3)),
dump_register(DEPCMDPAR2(4)),
dump_register(DEPCMDPAR2(5)),
dump_register(DEPCMDPAR2(6)),
dump_register(DEPCMDPAR2(7)),
dump_register(DEPCMDPAR2(8)),
dump_register(DEPCMDPAR2(9)),
dump_register(DEPCMDPAR2(10)),
dump_register(DEPCMDPAR2(11)),
dump_register(DEPCMDPAR2(12)),
dump_register(DEPCMDPAR2(13)),
dump_register(DEPCMDPAR2(14)),
dump_register(DEPCMDPAR2(15)),
dump_register(DEPCMDPAR2(16)),
dump_register(DEPCMDPAR2(17)),
dump_register(DEPCMDPAR2(18)),
dump_register(DEPCMDPAR2(19)),
dump_register(DEPCMDPAR2(20)),
dump_register(DEPCMDPAR2(21)),
dump_register(DEPCMDPAR2(22)),
dump_register(DEPCMDPAR2(23)),
dump_register(DEPCMDPAR2(24)),
dump_register(DEPCMDPAR2(25)),
dump_register(DEPCMDPAR2(26)),
dump_register(DEPCMDPAR2(27)),
dump_register(DEPCMDPAR2(28)),
dump_register(DEPCMDPAR2(29)),
dump_register(DEPCMDPAR2(30)),
dump_register(DEPCMDPAR2(31)),
dump_register(DEPCMDPAR1(0)),
dump_register(DEPCMDPAR1(1)),
dump_register(DEPCMDPAR1(2)),
dump_register(DEPCMDPAR1(3)),
dump_register(DEPCMDPAR1(4)),
dump_register(DEPCMDPAR1(5)),
dump_register(DEPCMDPAR1(6)),
dump_register(DEPCMDPAR1(7)),
dump_register(DEPCMDPAR1(8)),
dump_register(DEPCMDPAR1(9)),
dump_register(DEPCMDPAR1(10)),
dump_register(DEPCMDPAR1(11)),
dump_register(DEPCMDPAR1(12)),
dump_register(DEPCMDPAR1(13)),
dump_register(DEPCMDPAR1(14)),
dump_register(DEPCMDPAR1(15)),
dump_register(DEPCMDPAR1(16)),
dump_register(DEPCMDPAR1(17)),
dump_register(DEPCMDPAR1(18)),
dump_register(DEPCMDPAR1(19)),
dump_register(DEPCMDPAR1(20)),
dump_register(DEPCMDPAR1(21)),
dump_register(DEPCMDPAR1(22)),
dump_register(DEPCMDPAR1(23)),
dump_register(DEPCMDPAR1(24)),
dump_register(DEPCMDPAR1(25)),
dump_register(DEPCMDPAR1(26)),
dump_register(DEPCMDPAR1(27)),
dump_register(DEPCMDPAR1(28)),
dump_register(DEPCMDPAR1(29)),
dump_register(DEPCMDPAR1(30)),
dump_register(DEPCMDPAR1(31)),
dump_register(DEPCMDPAR0(0)),
dump_register(DEPCMDPAR0(1)),
dump_register(DEPCMDPAR0(2)),
dump_register(DEPCMDPAR0(3)),
dump_register(DEPCMDPAR0(4)),
dump_register(DEPCMDPAR0(5)),
dump_register(DEPCMDPAR0(6)),
dump_register(DEPCMDPAR0(7)),
dump_register(DEPCMDPAR0(8)),
dump_register(DEPCMDPAR0(9)),
dump_register(DEPCMDPAR0(10)),
dump_register(DEPCMDPAR0(11)),
dump_register(DEPCMDPAR0(12)),
dump_register(DEPCMDPAR0(13)),
dump_register(DEPCMDPAR0(14)),
dump_register(DEPCMDPAR0(15)),
dump_register(DEPCMDPAR0(16)),
dump_register(DEPCMDPAR0(17)),
dump_register(DEPCMDPAR0(18)),
dump_register(DEPCMDPAR0(19)),
dump_register(DEPCMDPAR0(20)),
dump_register(DEPCMDPAR0(21)),
dump_register(DEPCMDPAR0(22)),
dump_register(DEPCMDPAR0(23)),
dump_register(DEPCMDPAR0(24)),
dump_register(DEPCMDPAR0(25)),
dump_register(DEPCMDPAR0(26)),
dump_register(DEPCMDPAR0(27)),
dump_register(DEPCMDPAR0(28)),
dump_register(DEPCMDPAR0(29)),
dump_register(DEPCMDPAR0(30)),
dump_register(DEPCMDPAR0(31)),
dump_register(DEPCMD(0)),
dump_register(DEPCMD(1)),
dump_register(DEPCMD(2)),
dump_register(DEPCMD(3)),
dump_register(DEPCMD(4)),
dump_register(DEPCMD(5)),
dump_register(DEPCMD(6)),
dump_register(DEPCMD(7)),
dump_register(DEPCMD(8)),
dump_register(DEPCMD(9)),
dump_register(DEPCMD(10)),
dump_register(DEPCMD(11)),
dump_register(DEPCMD(12)),
dump_register(DEPCMD(13)),
dump_register(DEPCMD(14)),
dump_register(DEPCMD(15)),
dump_register(DEPCMD(16)),
dump_register(DEPCMD(17)),
dump_register(DEPCMD(18)),
dump_register(DEPCMD(19)),
dump_register(DEPCMD(20)),
dump_register(DEPCMD(21)),
dump_register(DEPCMD(22)),
dump_register(DEPCMD(23)),
dump_register(DEPCMD(24)),
dump_register(DEPCMD(25)),
dump_register(DEPCMD(26)),
dump_register(DEPCMD(27)),
dump_register(DEPCMD(28)),
dump_register(DEPCMD(29)),
dump_register(DEPCMD(30)),
dump_register(DEPCMD(31)),
dump_ep_register_set(0),
dump_ep_register_set(1),
dump_ep_register_set(2),
dump_ep_register_set(3),
dump_ep_register_set(4),
dump_ep_register_set(5),
dump_ep_register_set(6),
dump_ep_register_set(7),
dump_ep_register_set(8),
dump_ep_register_set(9),
dump_ep_register_set(10),
dump_ep_register_set(11),
dump_ep_register_set(12),
dump_ep_register_set(13),
dump_ep_register_set(14),
dump_ep_register_set(15),
dump_ep_register_set(16),
dump_ep_register_set(17),
dump_ep_register_set(18),
dump_ep_register_set(19),
dump_ep_register_set(20),
dump_ep_register_set(21),
dump_ep_register_set(22),
dump_ep_register_set(23),
dump_ep_register_set(24),
dump_ep_register_set(25),
dump_ep_register_set(26),
dump_ep_register_set(27),
dump_ep_register_set(28),
dump_ep_register_set(29),
dump_ep_register_set(30),
dump_ep_register_set(31),
dump_register(OCFG),
dump_register(OCTL),
@ -939,7 +864,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
dwc->regset->regs = dwc3_regs;
dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
dwc->regset->base = dwc->regs;
dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
if (!file)

View file

@ -165,7 +165,7 @@ static void dwc3_omap_write_utmi_ctrl(struct dwc3_omap *omap, u32 value)
static u32 dwc3_omap_read_irq0_status(struct dwc3_omap *omap)
{
return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0 -
return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_RAW_0 -
omap->irq0_offset);
}
@ -178,7 +178,7 @@ static void dwc3_omap_write_irq0_status(struct dwc3_omap *omap, u32 value)
static u32 dwc3_omap_read_irqmisc_status(struct dwc3_omap *omap)
{
return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_MISC +
return dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_RAW_MISC +
omap->irqmisc_offset);
}
@ -231,35 +231,30 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
}
val = dwc3_omap_read_utmi_ctrl(omap);
val &= ~(USBOTGSS_UTMI_OTG_CTRL_IDDIG
| USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
| USBOTGSS_UTMI_OTG_CTRL_SESSEND);
val |= USBOTGSS_UTMI_OTG_CTRL_SESSVALID
| USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT;
val &= ~USBOTGSS_UTMI_OTG_CTRL_IDDIG;
dwc3_omap_write_utmi_ctrl(omap, val);
break;
case OMAP_DWC3_VBUS_VALID:
val = dwc3_omap_read_utmi_ctrl(omap);
val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND;
val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG
| USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
| USBOTGSS_UTMI_OTG_CTRL_SESSVALID
| USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT;
val |= USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
| USBOTGSS_UTMI_OTG_CTRL_SESSVALID;
dwc3_omap_write_utmi_ctrl(omap, val);
break;
case OMAP_DWC3_ID_FLOAT:
if (omap->vbus_reg)
regulator_disable(omap->vbus_reg);
val = dwc3_omap_read_utmi_ctrl(omap);
val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG;
dwc3_omap_write_utmi_ctrl(omap, val);
case OMAP_DWC3_VBUS_OFF:
val = dwc3_omap_read_utmi_ctrl(omap);
val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID
| USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
| USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT);
val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND
| USBOTGSS_UTMI_OTG_CTRL_IDDIG;
| USBOTGSS_UTMI_OTG_CTRL_VBUSVALID);
val |= USBOTGSS_UTMI_OTG_CTRL_SESSEND;
dwc3_omap_write_utmi_ctrl(omap, val);
break;
@ -268,19 +263,38 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
}
}
static void dwc3_omap_enable_irqs(struct dwc3_omap *omap);
static void dwc3_omap_disable_irqs(struct dwc3_omap *omap);
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
struct dwc3_omap *omap = _omap;
if (dwc3_omap_read_irqmisc_status(omap) ||
dwc3_omap_read_irq0_status(omap)) {
/* mask irqs */
dwc3_omap_disable_irqs(omap);
return IRQ_WAKE_THREAD;
}
return IRQ_NONE;
}
static irqreturn_t dwc3_omap_interrupt_thread(int irq, void *_omap)
{
struct dwc3_omap *omap = _omap;
u32 reg;
/* clear irq status flags */
reg = dwc3_omap_read_irqmisc_status(omap);
dwc3_omap_write_irqmisc_status(omap, reg);
reg = dwc3_omap_read_irq0_status(omap);
dwc3_omap_write_irq0_status(omap, reg);
/* unmask irqs */
dwc3_omap_enable_irqs(omap);
return IRQ_HANDLED;
}
@ -497,8 +511,9 @@ static int dwc3_omap_probe(struct platform_device *pdev)
/* check the DMA Status */
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt,
dwc3_omap_interrupt_thread, IRQF_SHARED,
"dwc3-omap", omap);
if (ret) {
dev_err(dev, "failed to request IRQ #%d --> %d\n",
omap->irq, ret);

View file

@ -20,11 +20,11 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
#include "platform_data.h"
#include <linux/delay.h>
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce
@ -51,62 +51,70 @@ static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
{
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
struct dwc3_platform_data pdata;
struct property_entry properties[] = {
PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
/*
* FIXME these quirks should be removed when AMD NL
* tapes out
*/
PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
{ },
};
memset(&pdata, 0, sizeof(pdata));
pdata.has_lpm_erratum = true;
pdata.lpm_nyet_threshold = 0xf;
pdata.u2exit_lfps_quirk = true;
pdata.u2ss_inp3_quirk = true;
pdata.req_p1p2p3_quirk = true;
pdata.del_p1p2p3_quirk = true;
pdata.del_phy_power_chg_quirk = true;
pdata.lfps_filter_quirk = true;
pdata.rx_detect_poll_quirk = true;
pdata.tx_de_emphasis_quirk = true;
pdata.tx_de_emphasis = 1;
/*
* FIXME these quirks should be removed when AMD NL
* taps out
*/
pdata.disable_scramble_quirk = true;
pdata.dis_u3_susphy_quirk = true;
pdata.dis_u2_susphy_quirk = true;
return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
return platform_device_add_properties(dwc3, properties);
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
struct gpio_desc *gpio;
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
int ret;
acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
acpi_dwc3_byt_gpios);
struct property_entry properties[] = {
PROPERTY_ENTRY_STRING("dr-mode", "peripheral"),
{ }
};
/*
* These GPIOs will turn on the USB2 PHY. Note that we have to
* put the gpio descriptors again here because the phy driver
* might want to grab them, too.
*/
gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
ret = platform_device_add_properties(dwc3, properties);
if (ret < 0)
return ret;
gpiod_set_value_cansleep(gpio, 1);
gpiod_put(gpio);
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
struct gpio_desc *gpio;
gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
acpi_dwc3_byt_gpios);
/*
* These GPIOs will turn on the USB2 PHY. Note that we have to
* put the gpio descriptors again here because the phy driver
* might want to grab them, too.
*/
gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
if (gpio) {
gpiod_set_value_cansleep(gpio, 1);
gpiod_put(gpio);
usleep_range(10000, 11000);
gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
if (gpio) {
gpiod_set_value_cansleep(gpio, 1);
gpiod_put(gpio);
usleep_range(10000, 11000);
}
}
}
@ -114,15 +122,14 @@ static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
(pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {
struct property_entry properties[] = {
PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
{ },
};
struct dwc3_platform_data pdata;
memset(&pdata, 0, sizeof(pdata));
pdata.usb3_lpm_capable = true;
pdata.has_lpm_erratum = true;
pdata.dis_enblslpm_quirk = true;
return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
return platform_device_add_properties(dwc3, properties);
}
return 0;
@ -180,7 +187,11 @@ static int dwc3_pci_probe(struct pci_dev *pci,
goto err;
}
device_init_wakeup(dev, true);
device_set_run_wake(dev, true);
pci_set_drvdata(pci, dwc3);
pm_runtime_put(dev);
return 0;
err:
platform_device_put(dwc3);
@ -189,6 +200,8 @@ static int dwc3_pci_probe(struct pci_dev *pci,
static void dwc3_pci_remove(struct pci_dev *pci)
{
device_init_wakeup(&pci->dev, false);
pm_runtime_get(&pci->dev);
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pci->dev));
platform_device_unregister(pci_get_drvdata(pci));
}
@ -219,11 +232,43 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
#ifdef CONFIG_PM
static int dwc3_pci_runtime_suspend(struct device *dev)
{
if (device_run_wake(dev))
return 0;
return -EBUSY;
}
static int dwc3_pci_pm_dummy(struct device *dev)
{
/*
* There's nothing to do here. No, seriously. Everything is either taken
* care either by PCI subsystem or dwc3/core.c, so we have nothing
* missing here.
*
* So you'd think we didn't need this at all, but PCI subsystem will
* bail out if we don't have a valid callback :-s
*/
return 0;
}
#endif /* CONFIG_PM */
static struct dev_pm_ops dwc3_pci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_pm_dummy, dwc3_pci_pm_dummy)
SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_pm_dummy,
NULL)
};
static struct pci_driver dwc3_pci_driver = {
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = dwc3_pci_remove,
.driver = {
.pm = &dwc3_pci_dev_pm_ops,
}
};
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");

View file

@ -98,8 +98,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
trace_dwc3_prepare_trb(dep, trb);
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
DWC3_DEPCMD_STARTTRANSFER, &params);
ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, &params);
if (ret < 0) {
dwc3_trace(trace_dwc3_ep0, "%s STARTTRANSFER failed",
dep->name);
@ -107,9 +106,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
}
dep->flags |= DWC3_EP_BUSY;
dep->resource_index = dwc3_gadget_ep_get_transfer_index(dwc,
dep->number);
dep->resource_index = dwc3_gadget_ep_get_transfer_index(dep);
dwc->ep0_next_event = DWC3_EP0_COMPLETE;
return 0;
@ -499,7 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
case USB_RECIP_ENDPOINT:
switch (wValue) {
case USB_ENDPOINT_HALT:
dep = dwc3_wIndex_to_dep(dwc, wIndex);
dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
if (!dep)
return -EINVAL;
if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
@ -622,8 +619,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
struct timing {
u8 u1sel;
u8 u1pel;
u16 u2sel;
u16 u2pel;
__le16 u2sel;
__le16 u2pel;
} __packed timing;
int ret;
@ -980,7 +977,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
dep->number);
if (ret) {
dwc3_trace(trace_dwc3_ep0, "failed to map request\n");
dwc3_trace(trace_dwc3_ep0, "failed to map request");
return;
}
@ -1008,7 +1005,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
dep->number);
if (ret) {
dwc3_trace(trace_dwc3_ep0, "failed to map request\n");
dwc3_trace(trace_dwc3_ep0, "failed to map request");
return;
}
@ -1058,7 +1055,7 @@ static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep)
cmd |= DWC3_DEPCMD_CMDIOC;
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
memset(&params, 0, sizeof(params));
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
ret = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
WARN_ON_ONCE(ret);
dep->resource_index = 0;
}
@ -1112,11 +1109,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event)
{
u8 epnum = event->endpoint_number;
dwc3_trace(trace_dwc3_ep0, "%s while ep%d%s in state '%s'",
dwc3_ep_event_string(event->endpoint_event),
epnum >> 1, (epnum & 1) ? "in" : "out",
dwc3_trace(trace_dwc3_ep0, "%s: state '%s'",
dwc3_ep_event_string(event),
dwc3_ep0_state_string(dwc->ep0state));
switch (event->endpoint_event) {

File diff suppressed because it is too large Load diff

View file

@ -95,11 +95,11 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
*
* Caller should take care of locking
*/
static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep)
{
u32 res_id;
res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
res_id = dwc3_readl(dep->regs, DWC3_DEPCMD);
return DWC3_DEPCMD_GET_RSC_IDX(res_id);
}

View file

@ -16,15 +16,55 @@
*/
#include <linux/platform_device.h>
#include <linux/usb/xhci_pdriver.h>
#include "core.h"
int dwc3_host_init(struct dwc3 *dwc)
{
struct property_entry props[2];
struct platform_device *xhci;
struct usb_xhci_pdata pdata;
int ret;
int ret, irq;
struct resource *res;
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
irq = platform_get_irq_byname(dwc3_pdev, "host");
if (irq == -EPROBE_DEFER)
return irq;
if (irq <= 0) {
irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
if (irq == -EPROBE_DEFER)
return irq;
if (irq <= 0) {
irq = platform_get_irq(dwc3_pdev, 0);
if (irq <= 0) {
if (irq != -EPROBE_DEFER) {
dev_err(dwc->dev,
"missing host IRQ\n");
}
if (!irq)
irq = -EINVAL;
return irq;
} else {
res = platform_get_resource(dwc3_pdev,
IORESOURCE_IRQ, 0);
}
} else {
res = platform_get_resource_byname(dwc3_pdev,
IORESOURCE_IRQ,
"dwc_usb3");
}
} else {
res = platform_get_resource_byname(dwc3_pdev, IORESOURCE_IRQ,
"host");
}
dwc->xhci_resources[1].start = irq;
dwc->xhci_resources[1].end = irq;
dwc->xhci_resources[1].flags = res->flags;
dwc->xhci_resources[1].name = res->name;
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
if (!xhci) {
@ -47,14 +87,15 @@ int dwc3_host_init(struct dwc3 *dwc)
goto err1;
}
memset(&pdata, 0, sizeof(pdata));
memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props));
pdata.usb3_lpm_capable = dwc->usb3_lpm_capable;
ret = platform_device_add_data(xhci, &pdata, sizeof(pdata));
if (ret) {
dev_err(dwc->dev, "couldn't add platform data to xHCI device\n");
goto err1;
if (dwc->usb3_lpm_capable) {
props[0].name = "usb3-lpm-capable";
ret = platform_device_add_properties(xhci, props);
if (ret) {
dev_err(dwc->dev, "failed to add properties to xHCI\n");
goto err1;
}
}
phy_create_lookup(dwc->usb2_generic_phy, "usb2-phy",

View file

@ -26,7 +26,6 @@
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
u32 offs = offset - DWC3_GLOBALS_REGS_START;
u32 value;
/*
@ -34,7 +33,7 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset)
* space, see dwc3_probe in core.c.
* However, the offsets are given starting from xHCI address space.
*/
value = readl(base + offs);
value = readl(base + offset - DWC3_GLOBALS_REGS_START);
/*
* When tracing we want to make it easy to find the correct address on
@ -49,14 +48,12 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset)
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
u32 offs = offset - DWC3_GLOBALS_REGS_START;
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
* However, the offsets are given starting from xHCI address space.
*/
writel(value, base + offs);
writel(value, base + offset - DWC3_GLOBALS_REGS_START);
/*
* When tracing we want to make it easy to find the correct address on

View file

@ -1,53 +0,0 @@
/**
* platform_data.h - USB DWC3 Platform Data Support
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
* Author: Felipe Balbi <balbi@ti.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/usb/ch9.h>
#include <linux/usb/otg.h>
struct dwc3_platform_data {
enum usb_device_speed maximum_speed;
enum usb_dr_mode dr_mode;
bool usb3_lpm_capable;
unsigned is_utmi_l1_suspend:1;
u8 hird_threshold;
u8 lpm_nyet_threshold;
unsigned disable_scramble_quirk:1;
unsigned has_lpm_erratum:1;
unsigned u2exit_lfps_quirk:1;
unsigned u2ss_inp3_quirk:1;
unsigned req_p1p2p3_quirk:1;
unsigned del_p1p2p3_quirk:1;
unsigned del_phy_power_chg_quirk:1;
unsigned lfps_filter_quirk:1;
unsigned rx_detect_poll_quirk:1;
unsigned dis_u3_susphy_quirk:1;
unsigned dis_u2_susphy_quirk:1;
unsigned dis_enblslpm_quirk:1;
unsigned dis_rxdet_inp3_quirk:1;
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
u32 fladj_value;
const char *hsphy_interface;
};

View file

@ -71,7 +71,8 @@ DECLARE_EVENT_CLASS(dwc3_log_event,
TP_fast_assign(
__entry->event = event;
),
TP_printk("event %08x", __entry->event)
TP_printk("event (%08x): %s", __entry->event,
dwc3_decode_event(__entry->event))
);
DEFINE_EVENT(dwc3_log_event, dwc3_event,
@ -85,21 +86,21 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
TP_STRUCT__entry(
__field(__u8, bRequestType)
__field(__u8, bRequest)
__field(__le16, wValue)
__field(__le16, wIndex)
__field(__le16, wLength)
__field(__u16, wValue)
__field(__u16, wIndex)
__field(__u16, wLength)
),
TP_fast_assign(
__entry->bRequestType = ctrl->bRequestType;
__entry->bRequest = ctrl->bRequest;
__entry->wValue = ctrl->wValue;
__entry->wIndex = ctrl->wIndex;
__entry->wLength = ctrl->wLength;
__entry->wValue = le16_to_cpu(ctrl->wValue);
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength);
),
TP_printk("bRequestType %02x bRequest %02x wValue %04x wIndex %04x wLength %d",
__entry->bRequestType, __entry->bRequest,
le16_to_cpu(__entry->wValue), le16_to_cpu(__entry->wIndex),
le16_to_cpu(__entry->wLength)
__entry->wValue, __entry->wIndex,
__entry->wLength
)
);
@ -166,37 +167,41 @@ DEFINE_EVENT(dwc3_log_request, dwc3_gadget_giveback,
);
DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
TP_PROTO(unsigned int cmd, u32 param),
TP_ARGS(cmd, param),
TP_PROTO(unsigned int cmd, u32 param, int status),
TP_ARGS(cmd, param, status),
TP_STRUCT__entry(
__field(unsigned int, cmd)
__field(u32, param)
__field(int, status)
),
TP_fast_assign(
__entry->cmd = cmd;
__entry->param = param;
__entry->status = status;
),
TP_printk("cmd '%s' [%d] param %08x",
TP_printk("cmd '%s' [%d] param %08x --> status: %s",
dwc3_gadget_generic_cmd_string(__entry->cmd),
__entry->cmd, __entry->param
__entry->cmd, __entry->param,
dwc3_gadget_generic_cmd_status_string(__entry->status)
)
);
DEFINE_EVENT(dwc3_log_generic_cmd, dwc3_gadget_generic_cmd,
TP_PROTO(unsigned int cmd, u32 param),
TP_ARGS(cmd, param)
TP_PROTO(unsigned int cmd, u32 param, int status),
TP_ARGS(cmd, param, status)
);
DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
TP_PROTO(struct dwc3_ep *dep, unsigned int cmd,
struct dwc3_gadget_ep_cmd_params *params),
TP_ARGS(dep, cmd, params),
struct dwc3_gadget_ep_cmd_params *params, int cmd_status),
TP_ARGS(dep, cmd, params, cmd_status),
TP_STRUCT__entry(
__dynamic_array(char, name, DWC3_MSG_MAX)
__field(unsigned int, cmd)
__field(u32, param0)
__field(u32, param1)
__field(u32, param2)
__field(int, cmd_status)
),
TP_fast_assign(
snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
@ -204,18 +209,20 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
__entry->param0 = params->param0;
__entry->param1 = params->param1;
__entry->param2 = params->param2;
__entry->cmd_status = cmd_status;
),
TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x",
TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x --> status: %s",
__get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
__entry->cmd, __entry->param0,
__entry->param1, __entry->param2
__entry->param1, __entry->param2,
dwc3_ep_cmd_status_string(__entry->cmd_status)
)
);
DEFINE_EVENT(dwc3_log_gadget_ep_cmd, dwc3_gadget_ep_cmd,
TP_PROTO(struct dwc3_ep *dep, unsigned int cmd,
struct dwc3_gadget_ep_cmd_params *params),
TP_ARGS(dep, cmd, params)
struct dwc3_gadget_ep_cmd_params *params, int cmd_status),
TP_ARGS(dep, cmd, params, cmd_status)
);
DECLARE_EVENT_CLASS(dwc3_log_trb,
@ -224,6 +231,8 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
TP_STRUCT__entry(
__dynamic_array(char, name, DWC3_MSG_MAX)
__field(struct dwc3_trb *, trb)
__field(u32, allocated)
__field(u32, queued)
__field(u32, bpl)
__field(u32, bph)
__field(u32, size)
@ -232,14 +241,53 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
TP_fast_assign(
snprintf(__get_str(name), DWC3_MSG_MAX, "%s", dep->name);
__entry->trb = trb;
__entry->allocated = dep->allocated_requests;
__entry->queued = dep->queued_requests;
__entry->bpl = trb->bpl;
__entry->bph = trb->bph;
__entry->size = trb->size;
__entry->ctrl = trb->ctrl;
),
TP_printk("%s: trb %p bph %08x bpl %08x size %08x ctrl %08x",
__get_str(name), __entry->trb, __entry->bph, __entry->bpl,
__entry->size, __entry->ctrl
TP_printk("%s: %d/%d trb %p buf %08x%08x size %d ctrl %08x (%c%c%c%c:%c%c:%s)",
__get_str(name), __entry->queued, __entry->allocated,
__entry->trb, __entry->bph, __entry->bpl,
__entry->size, __entry->ctrl,
__entry->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h',
__entry->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l',
__entry->ctrl & DWC3_TRB_CTRL_CHN ? 'C' : 'c',
__entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
__entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
__entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
({char *s;
switch (__entry->ctrl & 0x3f0) {
case DWC3_TRBCTL_NORMAL:
s = "normal";
break;
case DWC3_TRBCTL_CONTROL_SETUP:
s = "setup";
break;
case DWC3_TRBCTL_CONTROL_STATUS2:
s = "status2";
break;
case DWC3_TRBCTL_CONTROL_STATUS3:
s = "status3";
break;
case DWC3_TRBCTL_CONTROL_DATA:
s = "data";
break;
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
s = "isoc-first";
break;
case DWC3_TRBCTL_ISOCHRONOUS:
s = "isoc";
break;
case DWC3_TRBCTL_LINK_TRB:
s = "link";
break;
default:
s = "UNKNOWN";
break;
} s; })
)
);

View file

@ -13,7 +13,7 @@
#include <linux/console.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci_regs.h>
#include <linux/pci_ids.h>
#include <linux/usb/ch9.h>
@ -1093,5 +1093,5 @@ static int __init kgdbdbgp_start_thread(void)
return 0;
}
module_init(kgdbdbgp_start_thread);
device_initcall(kgdbdbgp_start_thread);
#endif /* CONFIG_KGDB */

View file

@ -114,7 +114,7 @@ config USB_GADGET_VBUS_DRAW
config USB_GADGET_STORAGE_NUM_BUFFERS
int "Number of storage pipeline buffers"
range 2 32
range 2 256
default 2
help
Usually 2 buffers are enough to establish a good buffering

View file

@ -93,7 +93,7 @@ int usb_gadget_config_buf(
*cp = *config;
/* then interface/endpoint/class/vendor/... */
len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf,
length - USB_DT_CONFIG_SIZE, desc);
if (len < 0)
return len;

View file

@ -130,6 +130,12 @@ struct ffs_epfile {
struct dentry *dentry;
/*
* Buffer for holding data from partial reads which may happen since
* were rounding user read requests to a multiple of a max packet size.
*/
struct ffs_buffer *read_buffer; /* P: epfile->mutex */
char name[5];
unsigned char in; /* P: ffs->eps_lock */
@ -138,6 +144,12 @@ struct ffs_epfile {
unsigned char _pad;
};
struct ffs_buffer {
size_t length;
char *data;
char storage[];
};
/* ffs_io_data structure ***************************************************/
struct ffs_io_data {
@ -640,6 +652,49 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
}
}
static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
{
ssize_t ret = copy_to_iter(data, data_len, iter);
if (likely(ret == data_len))
return ret;
if (unlikely(iov_iter_count(iter)))
return -EFAULT;
/*
* Dear user space developer!
*
* TL;DR: To stop getting below error message in your kernel log, change
* user space code using functionfs to align read buffers to a max
* packet size.
*
* Some UDCs (e.g. dwc3) require request sizes to be a multiple of a max
* packet size. When unaligned buffer is passed to functionfs, it
* internally uses a larger, aligned buffer so that such UDCs are happy.
*
* Unfortunately, this means that host may send more data than was
* requested in read(2) system call. f_fs doesnt know what to do with
* that excess data so it simply drops it.
*
* Was the buffer aligned in the first place, no such problem would
* happen.
*
* Data may be dropped only in AIO reads. Synchronous reads are handled
* by splitting a request into multiple parts. This splitting may still
* be a problem though so its likely best to align the buffer
* regardless of it being AIO or not..
*
* This only affects OUT endpoints, i.e. reading data with a read(2),
* aio_read(2) etc. system calls. Writing data to an IN endpoint is not
* affected.
*/
pr_err("functionfs read size %d > requested size %zd, dropping excess data. "
"Align read buffer size to max packet size to avoid the problem.\n",
data_len, ret);
return ret;
}
static void ffs_user_copy_worker(struct work_struct *work)
{
struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
@ -650,9 +705,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
if (io_data->read && ret > 0) {
use_mm(io_data->mm);
ret = copy_to_iter(io_data->buf, ret, &io_data->data);
if (ret != io_data->req->actual && iov_iter_count(&io_data->data))
ret = -EFAULT;
ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data);
unuse_mm(io_data->mm);
}
@ -680,6 +733,58 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep,
schedule_work(&io_data->work);
}
/* Assumes epfile->mutex is held. */
static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile,
struct iov_iter *iter)
{
struct ffs_buffer *buf = epfile->read_buffer;
ssize_t ret;
if (!buf)
return 0;
ret = copy_to_iter(buf->data, buf->length, iter);
if (buf->length == ret) {
kfree(buf);
epfile->read_buffer = NULL;
} else if (unlikely(iov_iter_count(iter))) {
ret = -EFAULT;
} else {
buf->length -= ret;
buf->data += ret;
}
return ret;
}
/* Assumes epfile->mutex is held. */
static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
void *data, int data_len,
struct iov_iter *iter)
{
struct ffs_buffer *buf;
ssize_t ret = copy_to_iter(data, data_len, iter);
if (likely(data_len == ret))
return ret;
if (unlikely(iov_iter_count(iter)))
return -EFAULT;
/* See ffs_copy_to_iter for more context. */
pr_warn("functionfs read size %d > requested size %zd, splitting request into multiple reads.",
data_len, ret);
data_len -= ret;
buf = kmalloc(sizeof(*buf) + data_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
buf->length = data_len;
buf->data = buf->storage;
memcpy(buf->storage, data + ret, data_len);
epfile->read_buffer = buf;
return ret;
}
static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
{
struct ffs_epfile *epfile = file->private_data;
@ -709,21 +814,40 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
if (halt && epfile->isoc)
return -EINVAL;
/* We will be using request and read_buffer */
ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
if (unlikely(ret))
goto error;
/* Allocate & copy */
if (!halt) {
struct usb_gadget *gadget;
/*
* Do we have buffered data from previous partial read? Check
* that for synchronous case only because we do not have
* facility to wake up a pending asynchronous read and push
* buffered data to it which we would need to make things behave
* consistently.
*/
if (!io_data->aio && io_data->read) {
ret = __ffs_epfile_read_buffered(epfile, &io_data->data);
if (ret)
goto error_mutex;
}
/*
* if we _do_ wait above, the epfile->ffs->gadget might be NULL
* before the waiting completes, so do not assign to 'gadget'
* earlier
*/
struct usb_gadget *gadget = epfile->ffs->gadget;
size_t copied;
gadget = epfile->ffs->gadget;
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */
if (epfile->ep != ep) {
spin_unlock_irq(&epfile->ffs->eps_lock);
return -ESHUTDOWN;
ret = -ESHUTDOWN;
goto error_lock;
}
data_len = iov_iter_count(&io_data->data);
/*
@ -735,22 +859,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
spin_unlock_irq(&epfile->ffs->eps_lock);
data = kmalloc(data_len, GFP_KERNEL);
if (unlikely(!data))
return -ENOMEM;
if (!io_data->read) {
copied = copy_from_iter(data, data_len, &io_data->data);
if (copied != data_len) {
ret = -EFAULT;
goto error;
}
if (unlikely(!data)) {
ret = -ENOMEM;
goto error_mutex;
}
if (!io_data->read &&
copy_from_iter(data, data_len, &io_data->data) != data_len) {
ret = -EFAULT;
goto error_mutex;
}
}
/* We will be using request */
ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK);
if (unlikely(ret))
goto error;
spin_lock_irq(&epfile->ffs->eps_lock);
if (epfile->ep != ep) {
@ -803,18 +922,13 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
interrupted = ep->status < 0;
}
/*
* XXX We may end up silently droping data here. Since data_len
* (i.e. req->length) may be bigger than len (after being
* rounded up to maxpacketsize), we may end up with more data
* then user space has space for.
*/
ret = interrupted ? -EINTR : ep->status;
if (io_data->read && ret > 0) {
ret = copy_to_iter(data, ret, &io_data->data);
if (!ret)
ret = -EFAULT;
}
if (interrupted)
ret = -EINTR;
else if (io_data->read && ep->status > 0)
ret = __ffs_epfile_read_data(epfile, data, ep->status,
&io_data->data);
else
ret = ep->status;
goto error_mutex;
} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) {
ret = -ENOMEM;
@ -980,6 +1094,8 @@ ffs_epfile_release(struct inode *inode, struct file *file)
ENTER();
kfree(epfile->read_buffer);
epfile->read_buffer = NULL;
ffs_data_closed(epfile->ffs);
return 0;
@ -1605,19 +1721,24 @@ static void ffs_func_eps_disable(struct ffs_function *func)
unsigned count = func->ffs->eps_count;
unsigned long flags;
spin_lock_irqsave(&func->ffs->eps_lock, flags);
do {
if (epfile)
mutex_lock(&epfile->mutex);
spin_lock_irqsave(&func->ffs->eps_lock, flags);
/* pending requests get nuked */
if (likely(ep->ep))
usb_ep_disable(ep->ep);
++ep;
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
if (epfile) {
epfile->ep = NULL;
kfree(epfile->read_buffer);
epfile->read_buffer = NULL;
mutex_unlock(&epfile->mutex);
++epfile;
}
} while (--count);
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
}
static int ffs_func_eps_enable(struct ffs_function *func)
@ -2227,8 +2348,8 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
{
u32 str_count, needed_count, lang_count;
struct usb_gadget_strings **stringtabs, *t;
struct usb_string *strings, *s;
const char *data = _data;
struct usb_string *s;
ENTER();
@ -2286,7 +2407,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
stringtabs = vla_ptr(vlabuf, d, stringtabs);
t = vla_ptr(vlabuf, d, stringtab);
s = vla_ptr(vlabuf, d, strings);
strings = s;
}
/* For each language */

View file

@ -2655,18 +2655,6 @@ void fsg_common_put(struct fsg_common *common)
}
EXPORT_SYMBOL_GPL(fsg_common_put);
/* check if fsg_num_buffers is within a valid range */
static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers)
{
#define FSG_MAX_NUM_BUFFERS 32
if (fsg_num_buffers >= 2 && fsg_num_buffers <= FSG_MAX_NUM_BUFFERS)
return 0;
pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
fsg_num_buffers, 2, FSG_MAX_NUM_BUFFERS);
return -EINVAL;
}
static struct fsg_common *fsg_common_setup(struct fsg_common *common)
{
if (!common) {
@ -2709,11 +2697,7 @@ static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n)
int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n)
{
struct fsg_buffhd *bh, *buffhds;
int i, rc;
rc = fsg_num_buffers_validate(n);
if (rc != 0)
return rc;
int i;
buffhds = kcalloc(n, sizeof(*buffhds), GFP_KERNEL);
if (!buffhds)
@ -3401,10 +3385,6 @@ static ssize_t fsg_opts_num_buffers_store(struct config_item *item,
if (ret)
goto end;
ret = fsg_num_buffers_validate(num);
if (ret)
goto end;
fsg_common_set_num_buffers(opts->common, num);
ret = len;

View file

@ -907,7 +907,6 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
struct gs_port *port = tty->driver_data;
unsigned long flags;
int status;
pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n",
port->port_num, tty, count);
@ -917,7 +916,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
count = gs_buf_put(&port->port_write_buf, buf, count);
/* treat count == 0 as flush_chars() */
if (port->port_usb)
status = gs_start_tx(port);
gs_start_tx(port);
spin_unlock_irqrestore(&port->port_lock, flags);
return count;

View file

@ -265,7 +265,7 @@ static void *functionfs_acquire_dev(struct ffs_dev *dev)
{
if (!try_module_get(THIS_MODULE))
return ERR_PTR(-ENOENT);
return NULL;
}
@ -275,7 +275,7 @@ static void functionfs_release_dev(struct ffs_dev *dev)
}
/*
* The caller of this function takes ffs_lock
* The caller of this function takes ffs_lock
*/
static int functionfs_ready_callback(struct ffs_data *ffs)
{
@ -294,12 +294,12 @@ static int functionfs_ready_callback(struct ffs_data *ffs)
++missing_funcs;
gfs_registered = false;
}
return ret;
}
/*
* The caller of this function takes ffs_lock
* The caller of this function takes ffs_lock
*/
static void functionfs_closed_callback(struct ffs_data *ffs)
{
@ -347,17 +347,14 @@ static int gfs_bind(struct usb_composite_dev *cdev)
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
{
struct f_rndis_opts *rndis_opts;
fi_rndis = usb_get_function_instance("rndis");
if (IS_ERR(fi_rndis)) {
ret = PTR_ERR(fi_rndis);
goto error;
}
rndis_opts = container_of(fi_rndis, struct f_rndis_opts,
func_inst);
#ifndef CONFIG_USB_FUNCTIONFS_ETH
net = rndis_opts->net;
net = container_of(fi_rndis, struct f_rndis_opts,
func_inst)->net;
#endif
}
#endif

View file

@ -312,7 +312,7 @@ config USB_NET2272_DMA
If unsure, say "N" here. The driver works fine in PIO mode.
config USB_NET2280
tristate "NetChip 228x / PLX USB338x"
tristate "NetChip NET228x / PLX USB3x8x"
depends on PCI
help
NetChip 2280 / 2282 is a PCI based USB peripheral controller which
@ -322,6 +322,8 @@ config USB_NET2280
(for control transfers) and several endpoints with dedicated
functions.
PLX 2380 is a PCIe version of the PLX 2380.
PLX 3380 / 3382 is a PCIe based USB peripheral controller which
supports full, high speed USB 2.0 and super speed USB 3.0
data transfers.

View file

@ -1,3 +1,8 @@
# define_trace.h needs to know how to find our header
CFLAGS_trace.o := -I$(src)
udc-core-y := core.o trace.o
#
# USB peripheral controller drivers
#

View file

@ -2340,7 +2340,6 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
struct udc_ep *ep;
struct udc_request *req;
struct udc_data_dma *td;
unsigned dma_done;
unsigned len;
ep = &dev->ep[ep_ix];
@ -2385,13 +2384,8 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
*/
if (use_dma_ppb_du) {
td = udc_get_last_dma_desc(req);
if (td) {
dma_done =
AMD_GETBITS(td->status,
UDC_DMA_IN_STS_BS);
/* don't care DMA done */
if (td)
req->req.actual = req->req.length;
}
} else {
/* assume all bytes transferred */
req->req.actual = req->req.length;
@ -3417,4 +3411,3 @@ module_pci_driver(udc_pci_driver);
MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
MODULE_AUTHOR("Thomas Dahlmann");
MODULE_LICENSE("GPL");

View file

@ -1920,6 +1920,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
udc->errata = match->data;
udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9g45-pmc");
if (IS_ERR(udc->pmc))
udc->pmc = syscon_regmap_lookup_by_compatible("atmel,at91sam9x5-pmc");
if (udc->errata && IS_ERR(udc->pmc))
return ERR_CAST(udc->pmc);

View file

@ -57,7 +57,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc,
u32 param0, u32 param1, u32 param2)
{
u32 temp, cmd_status;
int reset_bdc = 0;
int ret;
temp = bdc_readl(bdc->regs, BDC_CMDSC);
@ -94,7 +93,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc,
case BDC_CMDS_INTL:
dev_err(bdc->dev, "BDC Internal error\n");
reset_bdc = 1;
ret = -ECONNRESET;
break;
@ -102,7 +100,6 @@ static int bdc_submit_cmd(struct bdc *bdc, u32 cmd_sc,
dev_err(bdc->dev,
"command timedout waited for %dusec\n",
BDC_CMD_TIMEOUT);
reset_bdc = 1;
ret = -ECONNRESET;
break;
default:

View file

@ -81,7 +81,7 @@ static void ep_bd_list_free(struct bdc_ep *ep, u32 num_tabs)
continue;
}
if (!bd_table->start_bd) {
dev_dbg(bdc->dev, "bd dma pool not allocted\n");
dev_dbg(bdc->dev, "bd dma pool not allocated\n");
continue;
}
@ -702,11 +702,9 @@ static int ep0_queue(struct bdc_ep *ep, struct bdc_req *req)
/* Queue data stage */
static int ep0_queue_data_stage(struct bdc *bdc)
{
struct usb_request *ep0_usb_req;
struct bdc_ep *ep;
dev_dbg(bdc->dev, "%s\n", __func__);
ep0_usb_req = &bdc->ep0_req.usb_req;
ep = bdc->bdc_ep_array[1];
bdc->ep0_req.ep = ep;
bdc->ep0_req.usb_req.complete = NULL;
@ -1393,10 +1391,8 @@ static int ep0_set_sel(struct bdc *bdc,
{
struct bdc_ep *ep;
u16 wLength;
u16 wValue;
dev_dbg(bdc->dev, "%s\n", __func__);
wValue = le16_to_cpu(setup_pkt->wValue);
wLength = le16_to_cpu(setup_pkt->wLength);
if (unlikely(wLength != 6)) {
dev_err(bdc->dev, "%s Wrong wLength:%d\n", __func__, wLength);

File diff suppressed because it is too large Load diff

View file

@ -647,12 +647,10 @@ static int dummy_disable(struct usb_ep *_ep)
static struct usb_request *dummy_alloc_request(struct usb_ep *_ep,
gfp_t mem_flags)
{
struct dummy_ep *ep;
struct dummy_request *req;
if (!_ep)
return NULL;
ep = usb_ep_to_dummy_ep(_ep);
req = kzalloc(sizeof(*req), mem_flags);
if (!req)
@ -2444,9 +2442,6 @@ static int dummy_start(struct usb_hcd *hcd)
static void dummy_stop(struct usb_hcd *hcd)
{
struct dummy *dum;
dum = hcd_to_dummy_hcd(hcd)->dum;
device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
}

View file

@ -1199,8 +1199,6 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
struct m66592 *m66592 = _m66592;
u16 intsts0;
u16 intenb0;
u16 brdysts, nrdysts, bempsts;
u16 brdyenb, nrdyenb, bempenb;
u16 savepipe;
u16 mask0;
@ -1224,12 +1222,10 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
mask0 = intsts0 & intenb0;
if (mask0) {
brdysts = m66592_read(m66592, M66592_BRDYSTS);
nrdysts = m66592_read(m66592, M66592_NRDYSTS);
bempsts = m66592_read(m66592, M66592_BEMPSTS);
brdyenb = m66592_read(m66592, M66592_BRDYENB);
nrdyenb = m66592_read(m66592, M66592_NRDYENB);
bempenb = m66592_read(m66592, M66592_BEMPENB);
u16 brdysts = m66592_read(m66592, M66592_BRDYSTS);
u16 bempsts = m66592_read(m66592, M66592_BEMPSTS);
u16 brdyenb = m66592_read(m66592, M66592_BRDYENB);
u16 bempenb = m66592_read(m66592, M66592_BEMPENB);
if (mask0 & M66592_VBINT) {
m66592_write(m66592, 0xffff & ~M66592_VBINT,
@ -1408,28 +1404,20 @@ static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req)
static int m66592_set_halt(struct usb_ep *_ep, int value)
{
struct m66592_ep *ep;
struct m66592_request *req;
struct m66592_ep *ep = container_of(_ep, struct m66592_ep, ep);
unsigned long flags;
int ret = 0;
ep = container_of(_ep, struct m66592_ep, ep);
req = list_entry(ep->queue.next, struct m66592_request, queue);
spin_lock_irqsave(&ep->m66592->lock, flags);
if (!list_empty(&ep->queue)) {
ret = -EAGAIN;
goto out;
}
if (value) {
} else if (value) {
ep->busy = 1;
pipe_stall(ep->m66592, ep->pipenum);
} else {
ep->busy = 0;
pipe_stop(ep->m66592, ep->pipenum);
}
out:
spin_unlock_irqrestore(&ep->m66592->lock, flags);
return ret;
}

View file

@ -119,18 +119,14 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
struct mv_u3d_req *curr_req)
{
struct mv_u3d_trb *curr_trb;
dma_addr_t cur_deq_lo;
struct mv_u3d_ep_context *curr_ep_context;
int trb_complete, actual, remaining_length = 0;
int actual, remaining_length = 0;
int direction, ep_num;
int retval = 0;
u32 tmp, status, length;
curr_ep_context = &u3d->ep_context[index];
direction = index % 2;
ep_num = index / 2;
trb_complete = 0;
actual = curr_req->req.length;
while (!list_empty(&curr_req->trb_list)) {
@ -143,15 +139,10 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
}
curr_trb->trb_hw->ctrl.own = 0;
if (direction == MV_U3D_EP_DIR_OUT) {
if (direction == MV_U3D_EP_DIR_OUT)
tmp = ioread32(&u3d->vuc_regs->rxst[ep_num].statuslo);
cur_deq_lo =
ioread32(&u3d->vuc_regs->rxst[ep_num].curdeqlo);
} else {
else
tmp = ioread32(&u3d->vuc_regs->txst[ep_num].statuslo);
cur_deq_lo =
ioread32(&u3d->vuc_regs->txst[ep_num].curdeqlo);
}
status = tmp >> MV_U3D_XFERSTATUS_COMPLETE_SHIFT;
length = tmp & MV_U3D_XFERSTATUS_TRB_LENGTH_MASK;
@ -527,7 +518,6 @@ static int mv_u3d_ep_enable(struct usb_ep *_ep,
{
struct mv_u3d *u3d;
struct mv_u3d_ep *ep;
struct mv_u3d_ep_context *ep_context;
u16 max = 0;
unsigned maxburst = 0;
u32 epxcr, direction;
@ -548,9 +538,6 @@ static int mv_u3d_ep_enable(struct usb_ep *_ep,
_ep->maxburst = 1;
maxburst = _ep->maxburst;
/* Get the endpoint context address */
ep_context = (struct mv_u3d_ep_context *)ep->ep_context;
/* Set the max burst size */
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_BULK:
@ -633,7 +620,6 @@ static int mv_u3d_ep_disable(struct usb_ep *_ep)
{
struct mv_u3d *u3d;
struct mv_u3d_ep *ep;
struct mv_u3d_ep_context *ep_context;
u32 epxcr, direction;
unsigned long flags;
@ -646,9 +632,6 @@ static int mv_u3d_ep_disable(struct usb_ep *_ep)
u3d = ep->u3d;
/* Get the endpoint context address */
ep_context = ep->ep_context;
direction = mv_u3d_ep_dir(ep);
/* nuke all pending requests (does flush) */

View file

@ -129,7 +129,7 @@ static int process_ep_req(struct mv_udc *udc, int index,
{
struct mv_dtd *curr_dtd;
struct mv_dqh *curr_dqh;
int td_complete, actual, remaining_length;
int actual, remaining_length;
int i, direction;
int retval = 0;
u32 errors;
@ -139,7 +139,6 @@ static int process_ep_req(struct mv_udc *udc, int index,
direction = index % 2;
curr_dtd = curr_req->head;
td_complete = 0;
actual = curr_req->req.length;
for (i = 0; i < curr_req->dtd_count; i++) {
@ -412,11 +411,8 @@ static int req_to_dtd(struct mv_req *req)
unsigned count;
int is_last, is_first = 1;
struct mv_dtd *dtd, *last_dtd = NULL;
struct mv_udc *udc;
dma_addr_t dma;
udc = req->ep->udc;
do {
dtd = build_dtd(req, &count, &dma, &is_last);
if (dtd == NULL)
@ -567,7 +563,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
struct mv_udc *udc;
struct mv_ep *ep;
struct mv_dqh *dqh;
u32 bit_pos, epctrlx, direction;
u32 epctrlx, direction;
unsigned long flags;
ep = container_of(_ep, struct mv_ep, ep);
@ -582,7 +578,6 @@ static int mv_ep_disable(struct usb_ep *_ep)
spin_lock_irqsave(&udc->lock, flags);
direction = ep_dir(ep);
bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
/* Reset the max packet length and the interrupt on Setup */
dqh->max_packet_length = 0;

View file

@ -329,12 +329,10 @@ static int net2272_disable(struct usb_ep *_ep)
static struct usb_request *
net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
{
struct net2272_ep *ep;
struct net2272_request *req;
if (!_ep)
return NULL;
ep = container_of(_ep, struct net2272_ep, ep);
req = kzalloc(sizeof(*req), gfp_flags);
if (!req)
@ -348,10 +346,8 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
static void
net2272_free_request(struct usb_ep *_ep, struct usb_request *_req)
{
struct net2272_ep *ep;
struct net2272_request *req;
ep = container_of(_ep, struct net2272_ep, ep);
if (!_ep || !_req)
return;

View file

@ -211,7 +211,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
goto print_err;
}
if (dev->quirks & PLX_SUPERSPEED) {
if (dev->quirks & PLX_PCIE) {
if ((desc->bEndpointAddress & 0x0f) >= 0x0c) {
ret = -EDOM;
goto print_err;
@ -245,7 +245,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
/* set type, direction, address; reset fifo counters */
writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) {
if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) {
tmp = readl(&ep->cfg->ep_cfg);
/* If USB ep number doesn't match hardware ep number */
if ((tmp & 0xf) != usb_endpoint_num(desc)) {
@ -316,7 +316,7 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
BIT(CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
}
if (dev->quirks & PLX_SUPERSPEED)
if (dev->quirks & PLX_PCIE)
ep_clear_seqnum(ep);
writel(tmp, &ep->cfg->ep_cfg);
@ -527,7 +527,7 @@ static int net2280_disable(struct usb_ep *_ep)
spin_lock_irqsave(&ep->dev->lock, flags);
nuke(ep);
if (ep->dev->quirks & PLX_SUPERSPEED)
if (ep->dev->quirks & PLX_PCIE)
ep_reset_338x(ep->dev->regs, ep);
else
ep_reset_228x(ep->dev->regs, ep);
@ -862,7 +862,7 @@ static void start_queue(struct net2280_ep *ep, u32 dmactl, u32 td_dma)
writel(readl(&dma->dmastat), &dma->dmastat);
writel(td_dma, &dma->dmadesc);
if (ep->dev->quirks & PLX_SUPERSPEED)
if (ep->dev->quirks & PLX_PCIE)
dmactl |= BIT(DMA_REQUEST_OUTSTANDING);
writel(dmactl, &dma->dmactl);
@ -1046,7 +1046,7 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* kickstart this i/o queue? */
if (list_empty(&ep->queue) && !ep->stopped &&
!((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
!((dev->quirks & PLX_PCIE) && ep->dma &&
(readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
/* use DMA if the endpoint supports it, else pio */
@ -1169,7 +1169,7 @@ static void scan_dma_completions(struct net2280_ep *ep)
break;
} else if (!ep->is_in &&
(req->req.length % ep->ep.maxpacket) &&
!(ep->dev->quirks & PLX_SUPERSPEED)) {
!(ep->dev->quirks & PLX_PCIE)) {
tmp = readl(&ep->regs->ep_stat);
/* AVOID TROUBLE HERE by not issuing short reads from
@ -1367,7 +1367,7 @@ net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
ep->wedged = 1;
} else {
clear_halt(ep);
if (ep->dev->quirks & PLX_SUPERSPEED &&
if (ep->dev->quirks & PLX_PCIE &&
!list_empty(&ep->queue) && ep->td_dma)
restart_dma(ep);
ep->wedged = 0;
@ -2394,7 +2394,7 @@ static int net2280_start(struct usb_gadget *_gadget,
*/
net2280_led_active(dev, 1);
if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched)
defect7374_enable_data_eps_zero(dev);
ep0_start(dev);
@ -3063,7 +3063,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
}
ep->stopped = 0;
dev->protocol_stall = 0;
if (!(dev->quirks & PLX_SUPERSPEED)) {
if (!(dev->quirks & PLX_PCIE)) {
if (ep->dev->quirks & PLX_2280)
tmp = BIT(FIFO_OVERFLOW) |
BIT(FIFO_UNDERFLOW);
@ -3090,7 +3090,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
cpu_to_le32s(&u.raw[0]);
cpu_to_le32s(&u.raw[1]);
if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
if ((dev->quirks & PLX_PCIE) && !dev->bug7734_patched)
defect7374_workaround(dev, u.r);
tmp = 0;
@ -3173,7 +3173,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
} else {
ep_vdbg(dev, "%s clear halt\n", e->ep.name);
clear_halt(e);
if ((ep->dev->quirks & PLX_SUPERSPEED) &&
if ((ep->dev->quirks & PLX_PCIE) &&
!list_empty(&e->queue) && e->td_dma)
restart_dma(e);
}
@ -3195,7 +3195,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
if (e->ep.name == ep0name)
goto do_stall;
set_halt(e);
if ((dev->quirks & PLX_SUPERSPEED) && e->dma)
if ((dev->quirks & PLX_PCIE) && e->dma)
abort_dma(e);
allow_status(ep);
ep_vdbg(dev, "%s set halt\n", ep->ep.name);
@ -3234,7 +3234,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
#undef w_length
next_endpoints:
if ((dev->quirks & PLX_SUPERSPEED) && dev->enhanced_mode) {
if ((dev->quirks & PLX_PCIE) && dev->enhanced_mode) {
u32 mask = (BIT(ENDPOINT_0_INTERRUPT) |
USB3380_IRQSTAT0_EP_INTR_MASK_IN |
USB3380_IRQSTAT0_EP_INTR_MASK_OUT);
@ -3399,7 +3399,7 @@ __acquires(dev->lock)
writel(tmp, &dma->dmastat);
/* dma sync*/
if (dev->quirks & PLX_SUPERSPEED) {
if (dev->quirks & PLX_PCIE) {
u32 r_dmacount = readl(&dma->dmacount);
if (!ep->is_in && (r_dmacount & 0x00FFFFFF) &&
(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT)))
@ -3468,7 +3468,7 @@ static irqreturn_t net2280_irq(int irq, void *_dev)
/* control requests and PIO */
handle_stat0_irqs(dev, readl(&dev->regs->irqstat0));
if (dev->quirks & PLX_SUPERSPEED) {
if (dev->quirks & PLX_PCIE) {
/* re-enable interrupt to trigger any possible new interrupt */
u32 pciirqenb1 = readl(&dev->regs->pciirqenb1);
writel(pciirqenb1 & 0x7FFFFFFF, &dev->regs->pciirqenb1);
@ -3513,7 +3513,7 @@ static void net2280_remove(struct pci_dev *pdev)
}
if (dev->got_irq)
free_irq(pdev->irq, dev);
if (dev->quirks & PLX_SUPERSPEED)
if (dev->quirks & PLX_PCIE)
pci_disable_msi(pdev);
if (dev->regs)
iounmap(dev->regs);
@ -3593,7 +3593,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200);
dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300);
if (dev->quirks & PLX_SUPERSPEED) {
if (dev->quirks & PLX_PCIE) {
u32 fsmvalue;
u32 usbstat;
dev->usb_ext = (struct usb338x_usb_ext_regs __iomem *)
@ -3637,7 +3637,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto done;
}
if (dev->quirks & PLX_SUPERSPEED)
if (dev->quirks & PLX_PCIE)
if (pci_enable_msi(pdev))
ep_err(dev, "Failed to enable MSI mode\n");
@ -3755,10 +3755,19 @@ static const struct pci_device_id pci_ids[] = { {
.class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x2380,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = PLX_PCIE,
},
{
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x3380,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = PLX_SUPERSPEED,
.driver_data = PLX_PCIE | PLX_SUPERSPEED,
},
{
.class = PCI_CLASS_SERIAL_USB_DEVICE,
@ -3767,7 +3776,7 @@ static const struct pci_device_id pci_ids[] = { {
.device = 0x3382,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = PLX_SUPERSPEED,
.driver_data = PLX_PCIE | PLX_SUPERSPEED,
},
{ /* end: all zeroes */ }
};

View file

@ -47,6 +47,7 @@ set_idx_reg(struct net2280_regs __iomem *regs, u32 index, u32 value)
#define PLX_LEGACY BIT(0)
#define PLX_2280 BIT(1)
#define PLX_SUPERSPEED BIT(2)
#define PLX_PCIE BIT(3)
#define REG_DIAG 0x0
#define RETRY_COUNTER 16

View file

@ -1477,11 +1477,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
req->dma_mapped = 0;
}
ep->halted = 1;
spin_lock(&dev->lock);
spin_unlock(&dev->lock);
if (!ep->in)
pch_udc_ep_clear_rrdy(ep);
usb_gadget_giveback_request(&ep->ep, &req->req);
spin_unlock(&dev->lock);
spin_lock(&dev->lock);
ep->halted = halted;
}
@ -1984,9 +1984,8 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
if (ep->num == PCH_UDC_EP0)
ep->dev->stall = 1;
pch_udc_ep_set_stall(ep);
pch_udc_enable_ep_interrupts(ep->dev,
PCH_UDC_EPINT(ep->in,
ep->num));
pch_udc_enable_ep_interrupts(
ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
} else {
pch_udc_ep_clear_stall(ep);
}
@ -2451,16 +2450,11 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
*/
static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num)
{
struct pch_udc_ep *ep;
struct pch_udc_request *req;
ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
if (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next, struct pch_udc_request, queue);
pch_udc_enable_ep_interrupts(ep->dev,
PCH_UDC_EPINT(ep->in, ep->num));
pch_udc_ep_clear_nak(ep);
}
struct pch_udc_ep *ep = &dev->ep[UDC_EPIN_IDX(ep_num)];
if (list_empty(&ep->queue))
return;
pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
pch_udc_ep_clear_nak(ep);
}
/**
@ -2573,9 +2567,9 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
empty_req_queue(ep);
}
if (dev->driver) {
spin_lock(&dev->lock);
usb_gadget_udc_reset(&dev->gadget, dev->driver);
spin_unlock(&dev->lock);
usb_gadget_udc_reset(&dev->gadget, dev->driver);
spin_lock(&dev->lock);
}
}
@ -2654,9 +2648,9 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
dev->ep[i].halted = 0;
}
dev->stall = 0;
spin_lock(&dev->lock);
dev->driver->setup(&dev->gadget, &dev->setup_data);
spin_unlock(&dev->lock);
dev->driver->setup(&dev->gadget, &dev->setup_data);
spin_lock(&dev->lock);
}
/**
@ -2691,9 +2685,9 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
dev->stall = 0;
/* call gadget zero with setup data received */
spin_lock(&dev->lock);
dev->driver->setup(&dev->gadget, &dev->setup_data);
spin_unlock(&dev->lock);
dev->driver->setup(&dev->gadget, &dev->setup_data);
spin_lock(&dev->lock);
}
/**

View file

@ -1825,13 +1825,10 @@ static int pxa27x_udc_start(struct usb_gadget *g,
* Disables all udc endpoints (even control endpoint), report disconnect to
* the gadget user.
*/
static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
static void stop_activity(struct pxa_udc *udc)
{
int i;
/* don't disconnect drivers more than once */
if (udc->gadget.speed == USB_SPEED_UNKNOWN)
driver = NULL;
udc->gadget.speed = USB_SPEED_UNKNOWN;
for (i = 0; i < NR_USB_ENDPOINTS; i++)
@ -1848,7 +1845,7 @@ static int pxa27x_udc_stop(struct usb_gadget *g)
{
struct pxa_udc *udc = to_pxa(g);
stop_activity(udc, NULL);
stop_activity(udc);
udc_disable(udc);
udc->driver = NULL;
@ -2296,7 +2293,7 @@ static void irq_udc_reset(struct pxa_udc *udc)
if ((udccr & UDCCR_UDA) == 0) {
dev_dbg(udc->dev, "USB reset start\n");
stop_activity(udc, udc->driver);
stop_activity(udc);
}
udc->gadget.speed = USB_SPEED_FULL;
memset(&udc->stats, 0, sizeof udc->stats);

View file

@ -1464,8 +1464,6 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
struct r8a66597 *r8a66597 = _r8a66597;
u16 intsts0;
u16 intenb0;
u16 brdysts, nrdysts, bempsts;
u16 brdyenb, nrdyenb, bempenb;
u16 savepipe;
u16 mask0;
@ -1481,12 +1479,10 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
mask0 = intsts0 & intenb0;
if (mask0) {
brdysts = r8a66597_read(r8a66597, BRDYSTS);
nrdysts = r8a66597_read(r8a66597, NRDYSTS);
bempsts = r8a66597_read(r8a66597, BEMPSTS);
brdyenb = r8a66597_read(r8a66597, BRDYENB);
nrdyenb = r8a66597_read(r8a66597, NRDYENB);
bempenb = r8a66597_read(r8a66597, BEMPENB);
u16 brdysts = r8a66597_read(r8a66597, BRDYSTS);
u16 bempsts = r8a66597_read(r8a66597, BEMPSTS);
u16 brdyenb = r8a66597_read(r8a66597, BRDYENB);
u16 bempenb = r8a66597_read(r8a66597, BEMPENB);
if (mask0 & VBINT) {
r8a66597_write(r8a66597, 0xffff & ~VBINT,
@ -1658,20 +1654,14 @@ static int r8a66597_dequeue(struct usb_ep *_ep, struct usb_request *_req)
static int r8a66597_set_halt(struct usb_ep *_ep, int value)
{
struct r8a66597_ep *ep;
struct r8a66597_request *req;
struct r8a66597_ep *ep = container_of(_ep, struct r8a66597_ep, ep);
unsigned long flags;
int ret = 0;
ep = container_of(_ep, struct r8a66597_ep, ep);
req = get_request_from_ep(ep);
spin_lock_irqsave(&ep->r8a66597->lock, flags);
if (!list_empty(&ep->queue)) {
ret = -EAGAIN;
goto out;
}
if (value) {
} else if (value) {
ep->busy = 1;
pipe_stall(ep->r8a66597, ep->pipenum);
} else {
@ -1679,8 +1669,6 @@ static int r8a66597_set_halt(struct usb_ep *_ep, int value)
ep->wedge = 0;
pipe_stop(ep->r8a66597, ep->pipenum);
}
out:
spin_unlock_irqrestore(&ep->r8a66597->lock, flags);
return ret;
}

View file

@ -0,0 +1,18 @@
/**
* trace.c - USB Gadget Framework Trace Support
*
* Copyright (C) 2016 Intel Corporation
* Author: Felipe Balbi <felipe.balbi@linux.intel.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define CREATE_TRACE_POINTS
#include "trace.h"

View file

@ -0,0 +1,298 @@
/**
* udc.c - Core UDC Framework
*
* Copyright (C) 2016 Intel Corporation
* Author: Felipe Balbi <felipe.balbi@linux.intel.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM gadget
#if !defined(__UDC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define __UDC_TRACE_H
#include <linux/types.h>
#include <linux/tracepoint.h>
#include <asm/byteorder.h>
#include <linux/usb/gadget.h>
DECLARE_EVENT_CLASS(udc_log_gadget,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret),
TP_STRUCT__entry(
__field(enum usb_device_speed, speed)
__field(enum usb_device_speed, max_speed)
__field(enum usb_device_state, state)
__field(unsigned, mA)
__field(unsigned, sg_supported)
__field(unsigned, is_otg)
__field(unsigned, is_a_peripheral)
__field(unsigned, b_hnp_enable)
__field(unsigned, a_hnp_support)
__field(unsigned, hnp_polling_support)
__field(unsigned, host_request_flag)
__field(unsigned, quirk_ep_out_aligned_size)
__field(unsigned, quirk_altset_not_supp)
__field(unsigned, quirk_stall_not_supp)
__field(unsigned, quirk_zlp_not_supp)
__field(unsigned, is_selfpowered)
__field(unsigned, deactivated)
__field(unsigned, connected)
__field(int, ret)
),
TP_fast_assign(
__entry->speed = g->speed;
__entry->max_speed = g->max_speed;
__entry->state = g->state;
__entry->mA = g->mA;
__entry->sg_supported = g->sg_supported;
__entry->is_otg = g->is_otg;
__entry->is_a_peripheral = g->is_a_peripheral;
__entry->b_hnp_enable = g->b_hnp_enable;
__entry->a_hnp_support = g->a_hnp_support;
__entry->hnp_polling_support = g->hnp_polling_support;
__entry->host_request_flag = g->host_request_flag;
__entry->quirk_ep_out_aligned_size = g->quirk_ep_out_aligned_size;
__entry->quirk_altset_not_supp = g->quirk_altset_not_supp;
__entry->quirk_stall_not_supp = g->quirk_stall_not_supp;
__entry->quirk_zlp_not_supp = g->quirk_zlp_not_supp;
__entry->is_selfpowered = g->is_selfpowered;
__entry->deactivated = g->deactivated;
__entry->connected = g->connected;
__entry->ret = ret;
),
TP_printk("speed %d/%d state %d %dmA [%s%s%s%s%s%s%s%s%s%s%s%s%s%s] --> %d",
__entry->speed, __entry->max_speed, __entry->state, __entry->mA,
__entry->sg_supported ? "sg:" : "",
__entry->is_otg ? "OTG:" : "",
__entry->is_a_peripheral ? "a_peripheral:" : "",
__entry->b_hnp_enable ? "b_hnp:" : "",
__entry->a_hnp_support ? "a_hnp:" : "",
__entry->hnp_polling_support ? "hnp_poll:" : "",
__entry->host_request_flag ? "hostreq:" : "",
__entry->quirk_ep_out_aligned_size ? "out_aligned:" : "",
__entry->quirk_altset_not_supp ? "no_altset:" : "",
__entry->quirk_stall_not_supp ? "no_stall:" : "",
__entry->quirk_zlp_not_supp ? "no_zlp" : "",
__entry->is_selfpowered ? "self-powered:" : "bus-powered:",
__entry->deactivated ? "deactivated:" : "activated:",
__entry->connected ? "connected" : "disconnected",
__entry->ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_frame_number,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_wakeup,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_set_selfpowered,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_clear_selfpowered,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_connect,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_draw,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_vbus_disconnect,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_connect,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_disconnect,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_deactivate,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DEFINE_EVENT(udc_log_gadget, usb_gadget_activate,
TP_PROTO(struct usb_gadget *g, int ret),
TP_ARGS(g, ret)
);
DECLARE_EVENT_CLASS(udc_log_ep,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret),
TP_STRUCT__entry(
__dynamic_array(char, name, UDC_TRACE_STR_MAX)
__field(unsigned, maxpacket)
__field(unsigned, maxpacket_limit)
__field(unsigned, max_streams)
__field(unsigned, mult)
__field(unsigned, maxburst)
__field(u8, address)
__field(bool, claimed)
__field(bool, enabled)
__field(int, ret)
),
TP_fast_assign(
snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name);
__entry->maxpacket = ep->maxpacket;
__entry->maxpacket_limit = ep->maxpacket_limit;
__entry->max_streams = ep->max_streams;
__entry->mult = ep->mult;
__entry->maxburst = ep->maxburst;
__entry->address = ep->address,
__entry->claimed = ep->claimed;
__entry->enabled = ep->enabled;
__entry->ret = ret;
),
TP_printk("%s: mps %d/%d streams %d mult %d burst %d addr %02x %s%s --> %d",
__get_str(name), __entry->maxpacket, __entry->maxpacket_limit,
__entry->max_streams, __entry->mult, __entry->maxburst,
__entry->address, __entry->claimed ? "claimed:" : "released:",
__entry->enabled ? "enabled" : "disabled", ret)
);
DEFINE_EVENT(udc_log_ep, usb_ep_set_maxpacket_limit,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret)
);
DEFINE_EVENT(udc_log_ep, usb_ep_enable,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret)
);
DEFINE_EVENT(udc_log_ep, usb_ep_disable,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret)
);
DEFINE_EVENT(udc_log_ep, usb_ep_set_halt,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret)
);
DEFINE_EVENT(udc_log_ep, usb_ep_clear_halt,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret)
);
DEFINE_EVENT(udc_log_ep, usb_ep_set_wedge,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret)
);
DEFINE_EVENT(udc_log_ep, usb_ep_fifo_status,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret)
);
DEFINE_EVENT(udc_log_ep, usb_ep_fifo_flush,
TP_PROTO(struct usb_ep *ep, int ret),
TP_ARGS(ep, ret)
);
DECLARE_EVENT_CLASS(udc_log_req,
TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
TP_ARGS(ep, req, ret),
TP_STRUCT__entry(
__dynamic_array(char, name, UDC_TRACE_STR_MAX)
__field(unsigned, length)
__field(unsigned, actual)
__field(unsigned, num_sgs)
__field(unsigned, num_mapped_sgs)
__field(unsigned, stream_id)
__field(unsigned, no_interrupt)
__field(unsigned, zero)
__field(unsigned, short_not_ok)
__field(int, status)
__field(int, ret)
),
TP_fast_assign(
snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name);
__entry->length = req->length;
__entry->actual = req->actual;
__entry->num_sgs = req->num_sgs;
__entry->num_mapped_sgs = req->num_mapped_sgs;
__entry->stream_id = req->stream_id;
__entry->no_interrupt = req->no_interrupt;
__entry->zero = req->zero;
__entry->short_not_ok = req->short_not_ok;
__entry->status = req->status;
__entry->ret = ret;
),
TP_printk("%s: length %d/%d sgs %d/%d stream %d %s%s%s status %d --> %d",
__get_str(name), __entry->actual, __entry->length,
__entry->num_mapped_sgs, __entry->num_sgs, __entry->stream_id,
__entry->zero ? "Z" : "z",
__entry->short_not_ok ? "S" : "s",
__entry->no_interrupt ? "i" : "I",
__entry->status, __entry->ret
)
);
DEFINE_EVENT(udc_log_req, usb_ep_alloc_request,
TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
TP_ARGS(ep, req, ret)
);
DEFINE_EVENT(udc_log_req, usb_ep_free_request,
TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
TP_ARGS(ep, req, ret)
);
DEFINE_EVENT(udc_log_req, usb_ep_queue,
TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
TP_ARGS(ep, req, ret)
);
DEFINE_EVENT(udc_log_req, usb_ep_dequeue,
TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
TP_ARGS(ep, req, ret)
);
DEFINE_EVENT(udc_log_req, usb_gadget_giveback_request,
TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret),
TP_ARGS(ep, req, ret)
);
#endif /* __UDC_TRACE_H */
/* this part has to be here */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace
#include <trace/define_trace.h>

View file

@ -1,800 +0,0 @@
/**
* udc.c - Core UDC Framework
*
* Copyright (C) 2010 Texas Instruments
* Author: Felipe Balbi <balbi@ti.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb.h>
/**
* struct usb_udc - describes one usb device controller
* @driver - the gadget driver pointer. For use by the class code
* @dev - the child device to the actual controller
* @gadget - the gadget. For use by the class code
* @list - for use by the udc class driver
* @vbus - for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true
*
* This represents the internal data structure which is used by the UDC-class
* to hold information about udc driver and gadget together.
*/
struct usb_udc {
struct usb_gadget_driver *driver;
struct usb_gadget *gadget;
struct device dev;
struct list_head list;
bool vbus;
};
static struct class *udc_class;
static LIST_HEAD(udc_list);
static LIST_HEAD(gadget_driver_pending_list);
static DEFINE_MUTEX(udc_lock);
static int udc_bind_to_driver(struct usb_udc *udc,
struct usb_gadget_driver *driver);
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_HAS_DMA
int usb_gadget_map_request_by_dev(struct device *dev,
struct usb_request *req, int is_in)
{
if (req->length == 0)
return 0;
if (req->num_sgs) {
int mapped;
mapped = dma_map_sg(dev, req->sg, req->num_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (mapped == 0) {
dev_err(dev, "failed to map SGs\n");
return -EFAULT;
}
req->num_mapped_sgs = mapped;
} else {
req->dma = dma_map_single(dev, req->buf, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (dma_mapping_error(dev, req->dma)) {
dev_err(dev, "failed to map buffer\n");
return -EFAULT;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev);
int usb_gadget_map_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in);
}
EXPORT_SYMBOL_GPL(usb_gadget_map_request);
void usb_gadget_unmap_request_by_dev(struct device *dev,
struct usb_request *req, int is_in)
{
if (req->length == 0)
return;
if (req->num_mapped_sgs) {
dma_unmap_sg(dev, req->sg, req->num_mapped_sgs,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->num_mapped_sgs = 0;
} else {
dma_unmap_single(dev, req->dma, req->length,
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
}
}
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev);
void usb_gadget_unmap_request(struct usb_gadget *gadget,
struct usb_request *req, int is_in)
{
usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in);
}
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
#endif /* CONFIG_HAS_DMA */
/* ------------------------------------------------------------------------- */
/**
* usb_gadget_giveback_request - give the request back to the gadget layer
* Context: in_interrupt()
*
* This is called by device controller drivers in order to return the
* completed request back to the gadget layer.
*/
void usb_gadget_giveback_request(struct usb_ep *ep,
struct usb_request *req)
{
if (likely(req->status == 0))
usb_led_activity(USB_LED_EVENT_GADGET);
req->complete(ep, req);
}
EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
/* ------------------------------------------------------------------------- */
/**
* gadget_find_ep_by_name - returns ep whose name is the same as sting passed
* in second parameter or NULL if searched endpoint not found
* @g: controller to check for quirk
* @name: name of searched endpoint
*/
struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name)
{
struct usb_ep *ep;
gadget_for_each_ep(ep, g) {
if (!strcmp(ep->name, name))
return ep;
}
return NULL;
}
EXPORT_SYMBOL_GPL(gadget_find_ep_by_name);
/* ------------------------------------------------------------------------- */
int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
struct usb_ep *ep, struct usb_endpoint_descriptor *desc,
struct usb_ss_ep_comp_descriptor *ep_comp)
{
u8 type;
u16 max;
int num_req_streams = 0;
/* endpoint already claimed? */
if (ep->claimed)
return 0;
type = usb_endpoint_type(desc);
max = 0x7ff & usb_endpoint_maxp(desc);
if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
return 0;
if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
return 0;
if (max > ep->maxpacket_limit)
return 0;
/* "high bandwidth" works only at high speed */
if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11))
return 0;
switch (type) {
case USB_ENDPOINT_XFER_CONTROL:
/* only support ep0 for portable CONTROL traffic */
return 0;
case USB_ENDPOINT_XFER_ISOC:
if (!ep->caps.type_iso)
return 0;
/* ISO: limit 1023 bytes full speed, 1024 high/super speed */
if (!gadget_is_dualspeed(gadget) && max > 1023)
return 0;
break;
case USB_ENDPOINT_XFER_BULK:
if (!ep->caps.type_bulk)
return 0;
if (ep_comp && gadget_is_superspeed(gadget)) {
/* Get the number of required streams from the
* EP companion descriptor and see if the EP
* matches it
*/
num_req_streams = ep_comp->bmAttributes & 0x1f;
if (num_req_streams > ep->max_streams)
return 0;
}
break;
case USB_ENDPOINT_XFER_INT:
/* Bulk endpoints handle interrupt transfers,
* except the toggle-quirky iso-synch kind
*/
if (!ep->caps.type_int && !ep->caps.type_bulk)
return 0;
/* INT: limit 64 bytes full speed, 1024 high/super speed */
if (!gadget_is_dualspeed(gadget) && max > 64)
return 0;
break;
}
return 1;
}
EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc);
/* ------------------------------------------------------------------------- */
static void usb_gadget_state_work(struct work_struct *work)
{
struct usb_gadget *gadget = work_to_gadget(work);
struct usb_udc *udc = gadget->udc;
if (udc)
sysfs_notify(&udc->dev.kobj, NULL, "state");
}
void usb_gadget_set_state(struct usb_gadget *gadget,
enum usb_device_state state)
{
gadget->state = state;
schedule_work(&gadget->work);
}
EXPORT_SYMBOL_GPL(usb_gadget_set_state);
/* ------------------------------------------------------------------------- */
static void usb_udc_connect_control(struct usb_udc *udc)
{
if (udc->vbus)
usb_gadget_connect(udc->gadget);
else
usb_gadget_disconnect(udc->gadget);
}
/**
* usb_udc_vbus_handler - updates the udc core vbus status, and try to
* connect or disconnect gadget
* @gadget: The gadget which vbus change occurs
* @status: The vbus status
*
* The udc driver calls it when it wants to connect or disconnect gadget
* according to vbus status.
*/
void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
{
struct usb_udc *udc = gadget->udc;
if (udc) {
udc->vbus = status;
usb_udc_connect_control(udc);
}
}
EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
/**
* usb_gadget_udc_reset - notifies the udc core that bus reset occurs
* @gadget: The gadget which bus reset occurs
* @driver: The gadget driver we want to notify
*
* If the udc driver has bus reset handler, it needs to call this when the bus
* reset occurs, it notifies the gadget driver that the bus reset occurs as
* well as updates gadget state.
*/
void usb_gadget_udc_reset(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
driver->reset(gadget);
usb_gadget_set_state(gadget, USB_STATE_DEFAULT);
}
EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
/**
* usb_gadget_udc_start - tells usb device controller to start up
* @udc: The UDC to be started
*
* This call is issued by the UDC Class driver when it's about
* to register a gadget driver to the device controller, before
* calling gadget driver's bind() method.
*
* It allows the controller to be powered off until strictly
* necessary to have it powered on.
*
* Returns zero on success, else negative errno.
*/
static inline int usb_gadget_udc_start(struct usb_udc *udc)
{
return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
}
/**
* usb_gadget_udc_stop - tells usb device controller we don't need it anymore
* @gadget: The device we want to stop activity
* @driver: The driver to unbind from @gadget
*
* This call is issued by the UDC Class driver after calling
* gadget driver's unbind() method.
*
* The details are implementation specific, but it can go as
* far as powering off UDC completely and disable its data
* line pullups.
*/
static inline void usb_gadget_udc_stop(struct usb_udc *udc)
{
udc->gadget->ops->udc_stop(udc->gadget);
}
/**
* usb_udc_release - release the usb_udc struct
* @dev: the dev member within usb_udc
*
* This is called by driver's core in order to free memory once the last
* reference is released.
*/
static void usb_udc_release(struct device *dev)
{
struct usb_udc *udc;
udc = container_of(dev, struct usb_udc, dev);
dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
kfree(udc);
}
static const struct attribute_group *usb_udc_attr_groups[];
static void usb_udc_nop_release(struct device *dev)
{
dev_vdbg(dev, "%s\n", __func__);
}
/**
* usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
* @parent: the parent device to this udc. Usually the controller driver's
* device.
* @gadget: the gadget to be added to the list.
* @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
*/
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
{
struct usb_udc *udc;
struct usb_gadget_driver *driver;
int ret = -ENOMEM;
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
if (!udc)
goto err1;
dev_set_name(&gadget->dev, "gadget");
INIT_WORK(&gadget->work, usb_gadget_state_work);
gadget->dev.parent = parent;
if (release)
gadget->dev.release = release;
else
gadget->dev.release = usb_udc_nop_release;
ret = device_register(&gadget->dev);
if (ret)
goto err2;
device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
udc->dev.groups = usb_udc_attr_groups;
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
goto err3;
udc->gadget = gadget;
gadget->udc = udc;
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
ret = device_add(&udc->dev);
if (ret)
goto err4;
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true;
/* pick up one of pending gadget drivers */
list_for_each_entry(driver, &gadget_driver_pending_list, pending) {
if (!driver->udc_name || strcmp(driver->udc_name,
dev_name(&udc->dev)) == 0) {
ret = udc_bind_to_driver(udc, driver);
if (ret != -EPROBE_DEFER)
list_del(&driver->pending);
if (ret)
goto err4;
break;
}
}
mutex_unlock(&udc_lock);
return 0;
err4:
list_del(&udc->list);
mutex_unlock(&udc_lock);
err3:
put_device(&udc->dev);
device_del(&gadget->dev);
err2:
put_device(&gadget->dev);
kfree(udc);
err1:
return ret;
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
/**
* usb_get_gadget_udc_name - get the name of the first UDC controller
* This functions returns the name of the first UDC controller in the system.
* Please note that this interface is usefull only for legacy drivers which
* assume that there is only one UDC controller in the system and they need to
* get its name before initialization. There is no guarantee that the UDC
* of the returned name will be still available, when gadget driver registers
* itself.
*
* Returns pointer to string with UDC controller name on success, NULL
* otherwise. Caller should kfree() returned string.
*/
char *usb_get_gadget_udc_name(void)
{
struct usb_udc *udc;
char *name = NULL;
/* For now we take the first available UDC */
mutex_lock(&udc_lock);
list_for_each_entry(udc, &udc_list, list) {
if (!udc->driver) {
name = kstrdup(udc->gadget->name, GFP_KERNEL);
break;
}
}
mutex_unlock(&udc_lock);
return name;
}
EXPORT_SYMBOL_GPL(usb_get_gadget_udc_name);
/**
* usb_add_gadget_udc - adds a new gadget to the udc class driver list
* @parent: the parent device to this udc. Usually the controller
* driver's device.
* @gadget: the gadget to be added to the list
*
* Returns zero on success, negative errno otherwise.
*/
int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
{
return usb_add_gadget_udc_release(parent, gadget, NULL);
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
static void usb_gadget_remove_driver(struct usb_udc *udc)
{
dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
udc->driver->function);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
usb_gadget_disconnect(udc->gadget);
udc->driver->disconnect(udc->gadget);
udc->driver->unbind(udc->gadget);
usb_gadget_udc_stop(udc);
udc->driver = NULL;
udc->dev.driver = NULL;
udc->gadget->dev.driver = NULL;
}
/**
* usb_del_gadget_udc - deletes @udc from udc_list
* @gadget: the gadget to be removed.
*
* This, will call usb_gadget_unregister_driver() if
* the @udc is still busy.
*/
void usb_del_gadget_udc(struct usb_gadget *gadget)
{
struct usb_udc *udc = gadget->udc;
if (!udc)
return;
dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
mutex_lock(&udc_lock);
list_del(&udc->list);
if (udc->driver) {
struct usb_gadget_driver *driver = udc->driver;
usb_gadget_remove_driver(udc);
list_add(&driver->pending, &gadget_driver_pending_list);
}
mutex_unlock(&udc_lock);
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
flush_work(&gadget->work);
device_unregister(&udc->dev);
device_unregister(&gadget->dev);
}
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
/* ------------------------------------------------------------------------- */
static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
{
int ret;
dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
driver->function);
udc->driver = driver;
udc->dev.driver = &driver->driver;
udc->gadget->dev.driver = &driver->driver;
ret = driver->bind(udc->gadget, driver);
if (ret)
goto err1;
ret = usb_gadget_udc_start(udc);
if (ret) {
driver->unbind(udc->gadget);
goto err1;
}
usb_udc_connect_control(udc);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
return 0;
err1:
if (ret != -EISNAM)
dev_err(&udc->dev, "failed to start %s: %d\n",
udc->driver->function, ret);
udc->driver = NULL;
udc->dev.driver = NULL;
udc->gadget->dev.driver = NULL;
return ret;
}
int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
{
struct usb_udc *udc = NULL;
int ret = -ENODEV;
if (!driver || !driver->bind || !driver->setup)
return -EINVAL;
mutex_lock(&udc_lock);
if (driver->udc_name) {
list_for_each_entry(udc, &udc_list, list) {
ret = strcmp(driver->udc_name, dev_name(&udc->dev));
if (!ret)
break;
}
if (!ret && !udc->driver)
goto found;
} else {
list_for_each_entry(udc, &udc_list, list) {
/* For now we take the first one */
if (!udc->driver)
goto found;
}
}
if (!driver->match_existing_only) {
list_add_tail(&driver->pending, &gadget_driver_pending_list);
pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
driver->function);
ret = 0;
}
mutex_unlock(&udc_lock);
return ret;
found:
ret = udc_bind_to_driver(udc, driver);
mutex_unlock(&udc_lock);
return ret;
}
EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
struct usb_udc *udc = NULL;
int ret = -ENODEV;
if (!driver || !driver->unbind)
return -EINVAL;
mutex_lock(&udc_lock);
list_for_each_entry(udc, &udc_list, list)
if (udc->driver == driver) {
usb_gadget_remove_driver(udc);
usb_gadget_set_state(udc->gadget,
USB_STATE_NOTATTACHED);
ret = 0;
break;
}
if (ret) {
list_del(&driver->pending);
ret = 0;
}
mutex_unlock(&udc_lock);
return ret;
}
EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
/* ------------------------------------------------------------------------- */
static ssize_t usb_udc_srp_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
if (sysfs_streq(buf, "1"))
usb_gadget_wakeup(udc->gadget);
return n;
}
static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
static ssize_t usb_udc_softconn_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
if (!udc->driver) {
dev_err(dev, "soft-connect without a gadget driver\n");
return -EOPNOTSUPP;
}
if (sysfs_streq(buf, "connect")) {
usb_gadget_udc_start(udc);
usb_gadget_connect(udc->gadget);
} else if (sysfs_streq(buf, "disconnect")) {
usb_gadget_disconnect(udc->gadget);
udc->driver->disconnect(udc->gadget);
usb_gadget_udc_stop(udc);
} else {
dev_err(dev, "unsupported command '%s'\n", buf);
return -EINVAL;
}
return n;
}
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
static ssize_t state_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
struct usb_gadget *gadget = udc->gadget;
return sprintf(buf, "%s\n", usb_state_string(gadget->state));
}
static DEVICE_ATTR_RO(state);
#define USB_UDC_SPEED_ATTR(name, param) \
ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \
return snprintf(buf, PAGE_SIZE, "%s\n", \
usb_speed_string(udc->gadget->param)); \
} \
static DEVICE_ATTR_RO(name)
static USB_UDC_SPEED_ATTR(current_speed, speed);
static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
#define USB_UDC_ATTR(name) \
ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \
struct usb_gadget *gadget = udc->gadget; \
\
return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \
} \
static DEVICE_ATTR_RO(name)
static USB_UDC_ATTR(is_otg);
static USB_UDC_ATTR(is_a_peripheral);
static USB_UDC_ATTR(b_hnp_enable);
static USB_UDC_ATTR(a_hnp_support);
static USB_UDC_ATTR(a_alt_hnp_support);
static USB_UDC_ATTR(is_selfpowered);
static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr,
&dev_attr_soft_connect.attr,
&dev_attr_state.attr,
&dev_attr_current_speed.attr,
&dev_attr_maximum_speed.attr,
&dev_attr_is_otg.attr,
&dev_attr_is_a_peripheral.attr,
&dev_attr_b_hnp_enable.attr,
&dev_attr_a_hnp_support.attr,
&dev_attr_a_alt_hnp_support.attr,
&dev_attr_is_selfpowered.attr,
NULL,
};
static const struct attribute_group usb_udc_attr_group = {
.attrs = usb_udc_attrs,
};
static const struct attribute_group *usb_udc_attr_groups[] = {
&usb_udc_attr_group,
NULL,
};
static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
int ret;
ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name);
if (ret) {
dev_err(dev, "failed to add uevent USB_UDC_NAME\n");
return ret;
}
if (udc->driver) {
ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
udc->driver->function);
if (ret) {
dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
return ret;
}
}
return 0;
}
static int __init usb_udc_init(void)
{
udc_class = class_create(THIS_MODULE, "udc");
if (IS_ERR(udc_class)) {
pr_err("failed to create udc class --> %ld\n",
PTR_ERR(udc_class));
return PTR_ERR(udc_class);
}
udc_class->dev_uevent = usb_udc_uevent;
return 0;
}
subsys_initcall(usb_udc_init);
static void __exit usb_udc_exit(void)
{
class_destroy(udc_class);
}
module_exit(usb_udc_exit);
MODULE_DESCRIPTION("UDC Framework");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("GPL v2");

View file

@ -2055,7 +2055,6 @@ static int xudc_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct resource *res;
struct xusb_udc *udc;
struct xusb_ep *ep0;
int irq;
int ret;
u32 ier;
@ -2119,8 +2118,6 @@ static int xudc_probe(struct platform_device *pdev)
xudc_eps_init(udc);
ep0 = &udc->ep[0];
/* Set device address to 0.*/
udc->write_fn(udc->addr, XUSB_ADDRESS_OFFSET, 0);

View file

@ -180,7 +180,7 @@ config USB_EHCI_MXC
config USB_EHCI_HCD_OMAP
tristate "EHCI support for OMAP3 and later chips"
depends on ARCH_OMAP
select NOP_USB_XCEIV
depends on NOP_USB_XCEIV
default y
---help---
Enables support for the on-chip EHCI controller on

View file

@ -39,11 +39,12 @@
#define DRIVER_DESC "EHCI generic platform driver"
#define EHCI_MAX_CLKS 3
#define EHCI_MAX_RSTS 3
#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
struct ehci_platform_priv {
struct clk *clks[EHCI_MAX_CLKS];
struct reset_control *rst;
struct reset_control *rsts[EHCI_MAX_RSTS];
struct phy **phys;
int num_phys;
bool reset_on_resume;
@ -149,7 +150,7 @@ static int ehci_platform_probe(struct platform_device *dev)
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ehci_platform_priv *priv;
struct ehci_hcd *ehci;
int err, irq, phy_num, clk = 0;
int err, irq, phy_num, clk = 0, rst;
if (usb_disabled())
return -ENODEV;
@ -234,16 +235,20 @@ static int ehci_platform_probe(struct platform_device *dev)
}
}
priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
if (IS_ERR(priv->rst)) {
err = PTR_ERR(priv->rst);
if (err == -EPROBE_DEFER)
goto err_put_clks;
priv->rst = NULL;
} else {
err = reset_control_deassert(priv->rst);
for (rst = 0; rst < EHCI_MAX_RSTS; rst++) {
priv->rsts[rst] = devm_reset_control_get_shared_by_index(
&dev->dev, rst);
if (IS_ERR(priv->rsts[rst])) {
err = PTR_ERR(priv->rsts[rst]);
if (err == -EPROBE_DEFER)
goto err_reset;
priv->rsts[rst] = NULL;
break;
}
err = reset_control_deassert(priv->rsts[rst]);
if (err)
goto err_put_clks;
goto err_reset;
}
if (pdata->big_endian_desc)
@ -300,8 +305,8 @@ static int ehci_platform_probe(struct platform_device *dev)
if (pdata->power_off)
pdata->power_off(dev);
err_reset:
if (priv->rst)
reset_control_assert(priv->rst);
while (--rst >= 0)
reset_control_assert(priv->rsts[rst]);
err_put_clks:
while (--clk >= 0)
clk_put(priv->clks[clk]);
@ -319,15 +324,15 @@ static int ehci_platform_remove(struct platform_device *dev)
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
int clk;
int clk, rst;
usb_remove_hcd(hcd);
if (pdata->power_off)
pdata->power_off(dev);
if (priv->rst)
reset_control_assert(priv->rst);
for (rst = 0; rst < EHCI_MAX_RSTS && priv->rsts[rst]; rst++)
reset_control_assert(priv->rsts[rst]);
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
clk_put(priv->clks[clk]);

View file

@ -33,11 +33,12 @@
#define DRIVER_DESC "OHCI generic platform driver"
#define OHCI_MAX_CLKS 3
#define OHCI_MAX_RESETS 2
#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
struct ohci_platform_priv {
struct clk *clks[OHCI_MAX_CLKS];
struct reset_control *rst;
struct reset_control *resets[OHCI_MAX_RESETS];
struct phy **phys;
int num_phys;
};
@ -117,7 +118,7 @@ static int ohci_platform_probe(struct platform_device *dev)
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ohci_platform_priv *priv;
struct ohci_hcd *ohci;
int err, irq, phy_num, clk = 0;
int err, irq, phy_num, clk = 0, rst = 0;
if (usb_disabled())
return -ENODEV;
@ -195,19 +196,21 @@ static int ohci_platform_probe(struct platform_device *dev)
break;
}
}
}
priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
if (IS_ERR(priv->rst)) {
err = PTR_ERR(priv->rst);
if (err == -EPROBE_DEFER)
goto err_put_clks;
priv->rst = NULL;
} else {
err = reset_control_deassert(priv->rst);
if (err)
goto err_put_clks;
for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
priv->resets[rst] =
devm_reset_control_get_shared_by_index(
&dev->dev, rst);
if (IS_ERR(priv->resets[rst])) {
err = PTR_ERR(priv->resets[rst]);
if (err == -EPROBE_DEFER)
goto err_reset;
priv->resets[rst] = NULL;
break;
}
err = reset_control_deassert(priv->resets[rst]);
if (err)
goto err_reset;
}
}
if (pdata->big_endian_desc)
@ -265,8 +268,8 @@ static int ohci_platform_probe(struct platform_device *dev)
if (pdata->power_off)
pdata->power_off(dev);
err_reset:
if (priv->rst)
reset_control_assert(priv->rst);
while (--rst >= 0)
reset_control_assert(priv->resets[rst]);
err_put_clks:
while (--clk >= 0)
clk_put(priv->clks[clk]);
@ -284,15 +287,15 @@ static int ohci_platform_remove(struct platform_device *dev)
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
int clk;
int clk, rst;
usb_remove_hcd(hcd);
if (pdata->power_off)
pdata->power_off(dev);
if (priv->rst)
reset_control_assert(priv->rst);
for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++)
reset_control_assert(priv->resets[rst]);
for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
clk_put(priv->clks[clk]);

View file

@ -37,7 +37,9 @@
* "All components of all Command and Transfer TRBs shall be initialized to '0'"
*/
static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
unsigned int cycle_state, gfp_t flags)
unsigned int cycle_state,
unsigned int max_packet,
gfp_t flags)
{
struct xhci_segment *seg;
dma_addr_t dma;
@ -53,6 +55,14 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
return NULL;
}
if (max_packet) {
seg->bounce_buf = kzalloc(max_packet, flags | GFP_DMA);
if (!seg->bounce_buf) {
dma_pool_free(xhci->segment_pool, seg->trbs, dma);
kfree(seg);
return NULL;
}
}
/* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
if (cycle_state == 0) {
for (i = 0; i < TRBS_PER_SEGMENT; i++)
@ -70,6 +80,7 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
seg->trbs = NULL;
}
kfree(seg->bounce_buf);
kfree(seg);
}
@ -317,11 +328,11 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring,
static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
struct xhci_segment **first, struct xhci_segment **last,
unsigned int num_segs, unsigned int cycle_state,
enum xhci_ring_type type, gfp_t flags)
enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
{
struct xhci_segment *prev;
prev = xhci_segment_alloc(xhci, cycle_state, flags);
prev = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
if (!prev)
return -ENOMEM;
num_segs--;
@ -330,7 +341,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
while (num_segs > 0) {
struct xhci_segment *next;
next = xhci_segment_alloc(xhci, cycle_state, flags);
next = xhci_segment_alloc(xhci, cycle_state, max_packet, flags);
if (!next) {
prev = *first;
while (prev) {
@ -360,7 +371,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
*/
static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
unsigned int num_segs, unsigned int cycle_state,
enum xhci_ring_type type, gfp_t flags)
enum xhci_ring_type type, unsigned int max_packet, gfp_t flags)
{
struct xhci_ring *ring;
int ret;
@ -370,13 +381,15 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
return NULL;
ring->num_segs = num_segs;
ring->bounce_buf_len = max_packet;
INIT_LIST_HEAD(&ring->td_list);
ring->type = type;
if (num_segs == 0)
return ring;
ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
&ring->last_seg, num_segs, cycle_state, type, flags);
&ring->last_seg, num_segs, cycle_state, type,
max_packet, flags);
if (ret)
goto fail;
@ -470,7 +483,8 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
ring->num_segs : num_segs_needed;
ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
num_segs, ring->cycle_state, ring->type, flags);
num_segs, ring->cycle_state, ring->type,
ring->bounce_buf_len, flags);
if (ret)
return -ENOMEM;
@ -652,7 +666,8 @@ struct xhci_ring *xhci_stream_id_to_ring(
*/
struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
unsigned int num_stream_ctxs,
unsigned int num_streams, gfp_t mem_flags)
unsigned int num_streams,
unsigned int max_packet, gfp_t mem_flags)
{
struct xhci_stream_info *stream_info;
u32 cur_stream;
@ -704,9 +719,11 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
* and add their segment DMA addresses to the radix tree.
* Stream 0 is reserved.
*/
for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
stream_info->stream_rings[cur_stream] =
xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, mem_flags);
xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, max_packet,
mem_flags);
cur_ring = stream_info->stream_rings[cur_stream];
if (!cur_ring)
goto cleanup_rings;
@ -1003,7 +1020,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
}
/* Allocate endpoint 0 ring */
dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, flags);
dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, 0, flags);
if (!dev->eps[0].ring)
goto fail;
@ -1434,22 +1451,6 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
return -EINVAL;
ring_type = usb_endpoint_type(&ep->desc);
/* Set up the endpoint ring */
virt_dev->eps[ep_index].new_ring =
xhci_ring_alloc(xhci, 2, 1, ring_type, mem_flags);
if (!virt_dev->eps[ep_index].new_ring) {
/* Attempt to use the ring cache */
if (virt_dev->num_rings_cached == 0)
return -ENOMEM;
virt_dev->num_rings_cached--;
virt_dev->eps[ep_index].new_ring =
virt_dev->ring_cache[virt_dev->num_rings_cached];
virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
1, ring_type);
}
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
/*
* Get values to fill the endpoint context, mostly from ep descriptor.
@ -1479,6 +1480,23 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
if ((xhci->hci_version > 0x100) && HCC2_LEC(xhci->hcc_params2))
mult = 0;
/* Set up the endpoint ring */
virt_dev->eps[ep_index].new_ring =
xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags);
if (!virt_dev->eps[ep_index].new_ring) {
/* Attempt to use the ring cache */
if (virt_dev->num_rings_cached == 0)
return -ENOMEM;
virt_dev->num_rings_cached--;
virt_dev->eps[ep_index].new_ring =
virt_dev->ring_cache[virt_dev->num_rings_cached];
virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
1, ring_type);
}
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
/* Fill the endpoint context */
ep_ctx->ep_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) |
EP_INTERVAL(interval) |
@ -2409,7 +2427,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
goto fail;
/* Set up the command ring to have one segments for now. */
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, 0, flags);
if (!xhci->cmd_ring)
goto fail;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@ -2454,7 +2472,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
*/
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
flags);
0, flags);
if (!xhci->event_ring)
goto fail;
if (xhci_check_trb_in_td_math(xhci) < 0)

View file

@ -18,7 +18,6 @@
#include <linux/platform_device.h>
#include <linux/usb/phy.h>
#include <linux/slab.h>
#include <linux/usb/xhci_pdriver.h>
#include <linux/acpi.h>
#include "xhci.h"
@ -138,8 +137,6 @@ MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
static int xhci_plat_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
const struct of_device_id *match;
const struct hc_driver *driver;
struct xhci_hcd *xhci;
@ -202,7 +199,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
}
xhci = hcd_to_xhci(hcd);
match = of_match_node(usb_xhci_of_match, node);
match = of_match_node(usb_xhci_of_match, pdev->dev.of_node);
if (match) {
const struct xhci_plat_priv *priv_match = match->data;
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
@ -223,8 +220,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto disable_clk;
}
if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
(pdata && pdata->usb3_lpm_capable))
if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable"))
xhci->quirks |= XHCI_LPM_SUPPORT;
if (HCC_MAX_PSA(xhci->hcc_params) >= 4)

View file

@ -66,6 +66,7 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include "xhci.h"
#include "xhci-trace.h"
#include "xhci-mtk.h"
@ -88,36 +89,25 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
return seg->dma + (segment_offset * sizeof(*trb));
}
/* Does this link TRB point to the first segment in a ring,
* or was the previous TRB the last TRB on the last segment in the ERST?
*/
static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring,
struct xhci_segment *seg, union xhci_trb *trb)
static bool trb_is_link(union xhci_trb *trb)
{
if (ring == xhci->event_ring)
return (trb == &seg->trbs[TRBS_PER_SEGMENT]) &&
(seg->next == xhci->event_ring->first_seg);
else
return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
return TRB_TYPE_LINK_LE32(trb->link.control);
}
/* Is this TRB a link TRB or was the last TRB the last TRB in this event ring
* segment? I.e. would the updated event TRB pointer step off the end of the
* event seg?
*/
static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
struct xhci_segment *seg, union xhci_trb *trb)
static bool last_trb_on_seg(struct xhci_segment *seg, union xhci_trb *trb)
{
if (ring == xhci->event_ring)
return trb == &seg->trbs[TRBS_PER_SEGMENT];
else
return TRB_TYPE_LINK_LE32(trb->link.control);
return trb == &seg->trbs[TRBS_PER_SEGMENT - 1];
}
static int enqueue_is_link_trb(struct xhci_ring *ring)
static bool last_trb_on_ring(struct xhci_ring *ring,
struct xhci_segment *seg, union xhci_trb *trb)
{
struct xhci_link_trb *link = &ring->enqueue->link;
return TRB_TYPE_LINK_LE32(link->control);
return last_trb_on_seg(seg, trb) && (seg->next == ring->first_seg);
}
static bool link_trb_toggles_cycle(union xhci_trb *trb)
{
return le32_to_cpu(trb->link.control) & LINK_TOGGLE;
}
/* Updates trb to point to the next TRB in the ring, and updates seg if the next
@ -129,7 +119,7 @@ static void next_trb(struct xhci_hcd *xhci,
struct xhci_segment **seg,
union xhci_trb **trb)
{
if (last_trb(xhci, ring, *seg, *trb)) {
if (trb_is_link(*trb)) {
*seg = (*seg)->next;
*trb = ((*seg)->trbs);
} else {
@ -145,32 +135,29 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
ring->deq_updates++;
/*
* If this is not event ring, and the dequeue pointer
* is not on a link TRB, there is one more usable TRB
*/
if (ring->type != TYPE_EVENT &&
!last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
ring->num_trbs_free++;
do {
/*
* Update the dequeue pointer further if that was a link TRB or
* we're at the end of an event ring segment (which doesn't have
* link TRBS)
*/
if (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) {
if (ring->type == TYPE_EVENT &&
last_trb_on_last_seg(xhci, ring,
ring->deq_seg, ring->dequeue)) {
ring->cycle_state ^= 1;
}
ring->deq_seg = ring->deq_seg->next;
ring->dequeue = ring->deq_seg->trbs;
} else {
/* event ring doesn't have link trbs, check for last trb */
if (ring->type == TYPE_EVENT) {
if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) {
ring->dequeue++;
return;
}
} while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue));
if (last_trb_on_ring(ring, ring->deq_seg, ring->dequeue))
ring->cycle_state ^= 1;
ring->deq_seg = ring->deq_seg->next;
ring->dequeue = ring->deq_seg->trbs;
return;
}
/* All other rings have link trbs */
if (!trb_is_link(ring->dequeue)) {
ring->dequeue++;
ring->num_trbs_free++;
}
while (trb_is_link(ring->dequeue)) {
ring->deq_seg = ring->deq_seg->next;
ring->dequeue = ring->deq_seg->trbs;
}
return;
}
/*
@ -198,50 +185,42 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
/* If this is not event ring, there is one less usable TRB */
if (ring->type != TYPE_EVENT &&
!last_trb(xhci, ring, ring->enq_seg, ring->enqueue))
if (!trb_is_link(ring->enqueue))
ring->num_trbs_free--;
next = ++(ring->enqueue);
ring->enq_updates++;
/* Update the dequeue pointer further if that was a link TRB or we're at
* the end of an event ring segment (which doesn't have link TRBS)
*/
while (last_trb(xhci, ring, ring->enq_seg, next)) {
if (ring->type != TYPE_EVENT) {
/*
* If the caller doesn't plan on enqueueing more
* TDs before ringing the doorbell, then we
* don't want to give the link TRB to the
* hardware just yet. We'll give the link TRB
* back in prepare_ring() just before we enqueue
* the TD at the top of the ring.
*/
if (!chain && !more_trbs_coming)
break;
/* Update the dequeue pointer further if that was a link TRB */
while (trb_is_link(next)) {
/* If we're not dealing with 0.95 hardware or
* isoc rings on AMD 0.96 host,
* carry over the chain bit of the previous TRB
* (which may mean the chain bit is cleared).
*/
if (!(ring->type == TYPE_ISOC &&
(xhci->quirks & XHCI_AMD_0x96_HOST))
&& !xhci_link_trb_quirk(xhci)) {
next->link.control &=
cpu_to_le32(~TRB_CHAIN);
next->link.control |=
cpu_to_le32(chain);
}
/* Give this link TRB to the hardware */
wmb();
next->link.control ^= cpu_to_le32(TRB_CYCLE);
/*
* If the caller doesn't plan on enqueueing more TDs before
* ringing the doorbell, then we don't want to give the link TRB
* to the hardware just yet. We'll give the link TRB back in
* prepare_ring() just before we enqueue the TD at the top of
* the ring.
*/
if (!chain && !more_trbs_coming)
break;
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
ring->cycle_state ^= 1;
}
/* If we're not dealing with 0.95 hardware or isoc rings on
* AMD 0.96 host, carry over the chain bit of the previous TRB
* (which may mean the chain bit is cleared).
*/
if (!(ring->type == TYPE_ISOC &&
(xhci->quirks & XHCI_AMD_0x96_HOST)) &&
!xhci_link_trb_quirk(xhci)) {
next->link.control &= cpu_to_le32(~TRB_CHAIN);
next->link.control |= cpu_to_le32(chain);
}
/* Give this link TRB to the hardware */
wmb();
next->link.control ^= cpu_to_le32(TRB_CYCLE);
/* Toggle the cycle bit after the last ring segment. */
if (link_trb_toggles_cycle(next))
ring->cycle_state ^= 1;
ring->enq_seg = ring->enq_seg->next;
ring->enqueue = ring->enq_seg->trbs;
next = ring->enqueue;
@ -626,6 +605,31 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
}
}
void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct xhci_ring *ring,
struct xhci_td *td)
{
struct device *dev = xhci_to_hcd(xhci)->self.controller;
struct xhci_segment *seg = td->bounce_seg;
struct urb *urb = td->urb;
if (!seg || !urb)
return;
if (usb_urb_dir_out(urb)) {
dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
DMA_TO_DEVICE);
return;
}
/* for in tranfers we need to copy the data from bounce to sg */
sg_pcopy_from_buffer(urb->sg, urb->num_mapped_sgs, seg->bounce_buf,
seg->bounce_len, seg->bounce_offs);
dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
DMA_FROM_DEVICE);
seg->bounce_len = 0;
seg->bounce_offs = 0;
}
/*
* When we get a command completion for a Stop Endpoint Command, we need to
* unlink any cancelled TDs from the ring. There are two ways to do that:
@ -745,6 +749,9 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
/* Doesn't matter what we pass for status, since the core will
* just overwrite it (because the URB has been unlinked).
*/
ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);
if (ep_ring && cur_td->bounce_seg)
xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td);
xhci_giveback_urb_in_irq(xhci, cur_td, 0);
/* Stop processing the cancelled list if the watchdog timer is
@ -767,6 +774,9 @@ static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring)
list_del_init(&cur_td->td_list);
if (!list_empty(&cur_td->cancelled_td_list))
list_del_init(&cur_td->cancelled_td_list);
if (cur_td->bounce_seg)
xhci_unmap_td_bounce_buffer(xhci, ring, cur_td);
xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN);
}
}
@ -917,7 +927,7 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
* the dequeue pointer one segment further, or we'll jump off
* the segment into la-la-land.
*/
if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) {
if (trb_is_link(ep_ring->dequeue)) {
ep_ring->deq_seg = ep_ring->deq_seg->next;
ep_ring->dequeue = ep_ring->deq_seg->trbs;
}
@ -926,8 +936,7 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
/* We have more usable TRBs */
ep_ring->num_trbs_free++;
ep_ring->dequeue++;
if (last_trb(xhci, ep_ring, ep_ring->deq_seg,
ep_ring->dequeue)) {
if (trb_is_link(ep_ring->dequeue)) {
if (ep_ring->dequeue ==
dev->eps[ep_index].queued_deq_ptr)
break;
@ -1865,6 +1874,10 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
urb = td->urb;
urb_priv = urb->hcpriv;
/* if a bounce buffer was used to align this td then unmap it */
if (td->bounce_seg)
xhci_unmap_td_bounce_buffer(xhci, ep_ring, td);
/* Do one last check of the actual transfer length.
* If the host controller said we transferred more data than the buffer
* length, urb->actual_length will be a very big number (since it's
@ -2865,36 +2878,29 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
}
}
if (enqueue_is_link_trb(ep_ring)) {
struct xhci_ring *ring = ep_ring;
union xhci_trb *next;
while (trb_is_link(ep_ring->enqueue)) {
/* If we're not dealing with 0.95 hardware or isoc rings
* on AMD 0.96 host, clear the chain bit.
*/
if (!xhci_link_trb_quirk(xhci) &&
!(ep_ring->type == TYPE_ISOC &&
(xhci->quirks & XHCI_AMD_0x96_HOST)))
ep_ring->enqueue->link.control &=
cpu_to_le32(~TRB_CHAIN);
else
ep_ring->enqueue->link.control |=
cpu_to_le32(TRB_CHAIN);
next = ring->enqueue;
wmb();
ep_ring->enqueue->link.control ^= cpu_to_le32(TRB_CYCLE);
while (last_trb(xhci, ring, ring->enq_seg, next)) {
/* If we're not dealing with 0.95 hardware or isoc rings
* on AMD 0.96 host, clear the chain bit.
*/
if (!xhci_link_trb_quirk(xhci) &&
!(ring->type == TYPE_ISOC &&
(xhci->quirks & XHCI_AMD_0x96_HOST)))
next->link.control &= cpu_to_le32(~TRB_CHAIN);
else
next->link.control |= cpu_to_le32(TRB_CHAIN);
/* Toggle the cycle bit after the last ring segment. */
if (link_trb_toggles_cycle(ep_ring->enqueue))
ep_ring->cycle_state ^= 1;
wmb();
next->link.control ^= cpu_to_le32(TRB_CYCLE);
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
ring->cycle_state ^= 1;
}
ring->enq_seg = ring->enq_seg->next;
ring->enqueue = ring->enq_seg->trbs;
next = ring->enqueue;
}
ep_ring->enq_seg = ep_ring->enq_seg->next;
ep_ring->enqueue = ep_ring->enq_seg->trbs;
}
return 0;
}
@ -3092,7 +3098,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
*/
static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
int trb_buff_len, unsigned int td_total_len,
struct urb *urb, unsigned int num_trbs_left)
struct urb *urb, bool more_trbs_coming)
{
u32 maxp, total_packet_count;
@ -3101,7 +3107,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
return ((td_total_len - transferred) >> 10);
/* One TRB with a zero-length data packet. */
if (num_trbs_left == 0 || (transferred == 0 && trb_buff_len == 0) ||
if (!more_trbs_coming || (transferred == 0 && trb_buff_len == 0) ||
trb_buff_len == td_total_len)
return 0;
@ -3116,37 +3122,103 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
return (total_packet_count - ((transferred + trb_buff_len) / maxp));
}
static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
u32 *trb_buff_len, struct xhci_segment *seg)
{
struct device *dev = xhci_to_hcd(xhci)->self.controller;
unsigned int unalign;
unsigned int max_pkt;
u32 new_buff_len;
max_pkt = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
unalign = (enqd_len + *trb_buff_len) % max_pkt;
/* we got lucky, last normal TRB data on segment is packet aligned */
if (unalign == 0)
return 0;
xhci_dbg(xhci, "Unaligned %d bytes, buff len %d\n",
unalign, *trb_buff_len);
/* is the last nornal TRB alignable by splitting it */
if (*trb_buff_len > unalign) {
*trb_buff_len -= unalign;
xhci_dbg(xhci, "split align, new buff len %d\n", *trb_buff_len);
return 0;
}
/*
* We want enqd_len + trb_buff_len to sum up to a number aligned to
* number which is divisible by the endpoint's wMaxPacketSize. IOW:
* (size of currently enqueued TRBs + remainder) % wMaxPacketSize == 0.
*/
new_buff_len = max_pkt - (enqd_len % max_pkt);
if (new_buff_len > (urb->transfer_buffer_length - enqd_len))
new_buff_len = (urb->transfer_buffer_length - enqd_len);
/* create a max max_pkt sized bounce buffer pointed to by last trb */
if (usb_urb_dir_out(urb)) {
sg_pcopy_to_buffer(urb->sg, urb->num_mapped_sgs,
seg->bounce_buf, new_buff_len, enqd_len);
seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
max_pkt, DMA_TO_DEVICE);
} else {
seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
max_pkt, DMA_FROM_DEVICE);
}
if (dma_mapping_error(dev, seg->bounce_dma)) {
/* try without aligning. Some host controllers survive */
xhci_warn(xhci, "Failed mapping bounce buffer, not aligning\n");
return 0;
}
*trb_buff_len = new_buff_len;
seg->bounce_len = new_buff_len;
seg->bounce_offs = enqd_len;
xhci_dbg(xhci, "Bounce align, new buff len %d\n", *trb_buff_len);
return 1;
}
/* This is very similar to what ehci-q.c qtd_fill() does */
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
{
struct xhci_ring *ep_ring;
struct xhci_ring *ring;
struct urb_priv *urb_priv;
struct xhci_td *td;
struct xhci_generic_trb *start_trb;
struct scatterlist *sg = NULL;
bool more_trbs_coming;
bool zero_length_needed;
unsigned int num_trbs, last_trb_num, i;
bool more_trbs_coming = true;
bool need_zero_pkt = false;
bool first_trb = true;
unsigned int num_trbs;
unsigned int start_cycle, num_sgs = 0;
unsigned int running_total, block_len, trb_buff_len;
unsigned int full_len;
int ret;
unsigned int enqd_len, block_len, trb_buff_len, full_len;
int sent_len, ret;
u32 field, length_field, remainder;
u64 addr;
u64 addr, send_addr;
ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
if (!ep_ring)
ring = xhci_urb_to_transfer_ring(xhci, urb);
if (!ring)
return -EINVAL;
full_len = urb->transfer_buffer_length;
/* If we have scatter/gather list, we use it. */
if (urb->num_sgs) {
num_sgs = urb->num_mapped_sgs;
sg = urb->sg;
addr = (u64) sg_dma_address(sg);
block_len = sg_dma_len(sg);
num_trbs = count_sg_trbs_needed(urb);
} else
} else {
num_trbs = count_trbs_needed(urb);
addr = (u64) urb->transfer_dma;
block_len = full_len;
}
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
num_trbs, urb, 0, mem_flags);
@ -3155,20 +3227,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
urb_priv = urb->hcpriv;
last_trb_num = num_trbs - 1;
/* Deal with URB_ZERO_PACKET - need one more td/trb */
zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET &&
urb_priv->length == 2;
if (zero_length_needed) {
num_trbs++;
xhci_dbg(xhci, "Creating zero length td.\n");
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
1, urb, 1, mem_flags);
if (unlikely(ret < 0))
return ret;
}
if (urb->transfer_flags & URB_ZERO_PACKET && urb_priv->length > 1)
need_zero_pkt = true;
td = urb_priv->td[0];
@ -3177,102 +3238,97 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
* until we've finished creating all the other TRBs. The ring's cycle
* state may change as we enqueue the other TRBs, so save it too.
*/
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
full_len = urb->transfer_buffer_length;
running_total = 0;
block_len = 0;
start_trb = &ring->enqueue->generic;
start_cycle = ring->cycle_state;
send_addr = addr;
/* Queue the TRBs, even if they are zero-length */
for (i = 0; i < num_trbs; i++) {
for (enqd_len = 0; enqd_len < full_len; enqd_len += trb_buff_len) {
field = TRB_TYPE(TRB_NORMAL);
if (block_len == 0) {
/* A new contiguous block. */
if (sg) {
addr = (u64) sg_dma_address(sg);
block_len = sg_dma_len(sg);
} else {
addr = (u64) urb->transfer_dma;
block_len = full_len;
}
/* TRB buffer should not cross 64KB boundaries */
trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
trb_buff_len = min_t(unsigned int,
trb_buff_len,
block_len);
} else {
/* Further through the contiguous block. */
trb_buff_len = block_len;
if (trb_buff_len > TRB_MAX_BUFF_SIZE)
trb_buff_len = TRB_MAX_BUFF_SIZE;
}
/* TRB buffer should not cross 64KB boundaries */
trb_buff_len = TRB_BUFF_LEN_UP_TO_BOUNDARY(addr);
trb_buff_len = min_t(unsigned int, trb_buff_len, block_len);
if (running_total + trb_buff_len > full_len)
trb_buff_len = full_len - running_total;
if (enqd_len + trb_buff_len > full_len)
trb_buff_len = full_len - enqd_len;
/* Don't change the cycle bit of the first TRB until later */
if (i == 0) {
if (first_trb) {
first_trb = false;
if (start_cycle == 0)
field |= TRB_CYCLE;
} else
field |= ep_ring->cycle_state;
field |= ring->cycle_state;
/* Chain all the TRBs together; clear the chain bit in the last
* TRB to indicate it's the last TRB in the chain.
*/
if (i < last_trb_num) {
if (enqd_len + trb_buff_len < full_len) {
field |= TRB_CHAIN;
} else {
field |= TRB_IOC;
if (i == last_trb_num)
td->last_trb = ep_ring->enqueue;
else if (zero_length_needed) {
trb_buff_len = 0;
urb_priv->td[1]->last_trb = ep_ring->enqueue;
if (trb_is_link(ring->enqueue + 1)) {
if (xhci_align_td(xhci, urb, enqd_len,
&trb_buff_len,
ring->enq_seg)) {
send_addr = ring->enq_seg->bounce_dma;
/* assuming TD won't span 2 segs */
td->bounce_seg = ring->enq_seg;
}
}
}
if (enqd_len + trb_buff_len >= full_len) {
field &= ~TRB_CHAIN;
field |= TRB_IOC;
more_trbs_coming = false;
td->last_trb = ring->enqueue;
}
/* Only set interrupt on short packet for IN endpoints */
if (usb_urb_dir_in(urb))
field |= TRB_ISP;
/* Set the TRB length, TD size, and interrupter fields. */
remainder = xhci_td_remainder(xhci, running_total,
trb_buff_len, full_len,
urb, num_trbs - i - 1);
remainder = xhci_td_remainder(xhci, enqd_len, trb_buff_len,
full_len, urb, more_trbs_coming);
length_field = TRB_LEN(trb_buff_len) |
TRB_TD_SIZE(remainder) |
TRB_INTR_TARGET(0);
if (i < num_trbs - 1)
more_trbs_coming = true;
else
more_trbs_coming = false;
queue_trb(xhci, ep_ring, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
queue_trb(xhci, ring, more_trbs_coming | need_zero_pkt,
lower_32_bits(send_addr),
upper_32_bits(send_addr),
length_field,
field);
running_total += trb_buff_len;
addr += trb_buff_len;
block_len -= trb_buff_len;
sent_len = trb_buff_len;
if (sg) {
if (block_len == 0) {
/* New sg entry */
--num_sgs;
if (num_sgs == 0)
break;
while (sg && sent_len >= block_len) {
/* New sg entry */
--num_sgs;
sent_len -= block_len;
if (num_sgs != 0) {
sg = sg_next(sg);
block_len = sg_dma_len(sg);
addr = (u64) sg_dma_address(sg);
addr += sent_len;
}
}
block_len -= sent_len;
send_addr = addr;
}
check_trb_math(urb, running_total);
if (need_zero_pkt) {
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
1, urb, 1, mem_flags);
urb_priv->td[1]->last_trb = ring->enqueue;
field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC;
queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field);
}
check_trb_math(urb, enqd_len);
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
@ -3666,7 +3722,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Set the TRB length, TD size, & interrupter fields. */
remainder = xhci_td_remainder(xhci, running_total,
trb_buff_len, td_len,
urb, trbs_per_td - j - 1);
urb, more_trbs_coming);
length_field = TRB_LEN(trb_buff_len) |
TRB_INTR_TARGET(0);

View file

@ -3139,6 +3139,7 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_input_control_ctx *ctrl_ctx;
unsigned int ep_index;
unsigned int num_stream_ctxs;
unsigned int max_packet;
unsigned long flags;
u32 changed_ep_bitmask = 0;
@ -3212,9 +3213,11 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
for (i = 0; i < num_eps; i++) {
ep_index = xhci_get_endpoint_index(&eps[i]->desc);
max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&eps[i]->desc));
vdev->eps[ep_index].stream_info = xhci_alloc_stream_info(xhci,
num_stream_ctxs,
num_streams, mem_flags);
num_streams,
max_packet, mem_flags);
if (!vdev->eps[ep_index].stream_info)
goto cleanup;
/* Set maxPstreams in endpoint context and update deq ptr to

View file

@ -1347,6 +1347,11 @@ struct xhci_segment {
/* private to HCD */
struct xhci_segment *next;
dma_addr_t dma;
/* Max packet sized bounce buffer for td-fragmant alignment */
dma_addr_t bounce_dma;
void *bounce_buf;
unsigned int bounce_offs;
unsigned int bounce_len;
};
struct xhci_td {
@ -1356,6 +1361,7 @@ struct xhci_td {
struct xhci_segment *start_seg;
union xhci_trb *first_trb;
union xhci_trb *last_trb;
struct xhci_segment *bounce_seg;
/* actual_length of the URB has already been set */
bool urb_length_set;
};
@ -1405,6 +1411,7 @@ struct xhci_ring {
unsigned int num_segs;
unsigned int num_trbs_free;
unsigned int num_trbs_free_temp;
unsigned int bounce_buf_len;
enum xhci_ring_type type;
bool last_td_was_short;
struct radix_tree_root *trb_address_map;
@ -1807,7 +1814,8 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
unsigned int ep_index);
struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
unsigned int num_stream_ctxs,
unsigned int num_streams, gfp_t flags);
unsigned int num_streams,
unsigned int max_packet, gfp_t flags);
void xhci_free_stream_info(struct xhci_hcd *xhci,
struct xhci_stream_info *stream_info);
void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,

View file

@ -13,11 +13,11 @@ typedef void (*mts_scsi_cmnd_callback)(struct scsi_cmnd *);
struct mts_transfer_context
{
struct mts_desc* instance;
struct mts_desc *instance;
mts_scsi_cmnd_callback final_callback;
struct scsi_cmnd *srb;
void* data;
void *data;
unsigned data_length;
int data_pipe;
int fragment;
@ -38,7 +38,7 @@ struct mts_desc {
u8 ep_response;
u8 ep_image;
struct Scsi_Host * host;
struct Scsi_Host *host;
struct urb *urb;
struct mts_transfer_context context;

View file

@ -330,6 +330,17 @@ static int usb3503_i2c_probe(struct i2c_client *i2c,
return usb3503_probe(hub);
}
static int usb3503_i2c_remove(struct i2c_client *i2c)
{
struct usb3503 *hub;
hub = i2c_get_clientdata(i2c);
if (hub->clk)
clk_disable_unprepare(hub->clk);
return 0;
}
static int usb3503_platform_probe(struct platform_device *pdev)
{
struct usb3503 *hub;
@ -338,10 +349,22 @@ static int usb3503_platform_probe(struct platform_device *pdev)
if (!hub)
return -ENOMEM;
hub->dev = &pdev->dev;
platform_set_drvdata(pdev, hub);
return usb3503_probe(hub);
}
static int usb3503_platform_remove(struct platform_device *pdev)
{
struct usb3503 *hub;
hub = platform_get_drvdata(pdev);
if (hub->clk)
clk_disable_unprepare(hub->clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int usb3503_i2c_suspend(struct device *dev)
{
@ -395,6 +418,7 @@ static struct i2c_driver usb3503_i2c_driver = {
.of_match_table = of_match_ptr(usb3503_of_match),
},
.probe = usb3503_i2c_probe,
.remove = usb3503_i2c_remove,
.id_table = usb3503_id,
};
@ -404,6 +428,7 @@ static struct platform_driver usb3503_platform_driver = {
.of_match_table = of_match_ptr(usb3503_of_match),
},
.probe = usb3503_platform_probe,
.remove = usb3503_platform_remove,
};
static int __init usb3503_init(void)

View file

@ -2,9 +2,12 @@
# for USB OTG silicon based on Mentor Graphics INVENTRA designs
#
# define_trace.h needs to know how to find our header
CFLAGS_musb_trace.o := -I$(src)
obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
musb_hdrc-y := musb_core.o
musb_hdrc-y := musb_core.o musb_trace.o
musb_hdrc-$(CONFIG_USB_MUSB_HOST)$(CONFIG_USB_MUSB_DUAL_ROLE) += musb_virthub.o musb_host.o
musb_hdrc-$(CONFIG_USB_MUSB_GADGET)$(CONFIG_USB_MUSB_DUAL_ROLE) += musb_gadget_ep0.o musb_gadget.o

View file

@ -14,6 +14,7 @@
#include "musb_core.h"
#include "musb_debug.h"
#include "cppi_dma.h"
#include "davinci.h"
/* CPPI DMA status 7-mar-2006:
@ -232,7 +233,7 @@ static void cppi_controller_stop(struct cppi *controller)
musb_writel(tibase, DAVINCI_RXCPPI_INTCLR_REG,
DAVINCI_DMA_ALL_CHANNELS_ENABLE);
dev_dbg(musb->controller, "Tearing down RX and TX Channels\n");
musb_dbg(musb, "Tearing down RX and TX Channels");
for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
/* FIXME restructure of txdma to use bds like rxdma */
controller->tx[i].last_processed = NULL;
@ -297,13 +298,13 @@ cppi_channel_allocate(struct dma_controller *c,
*/
if (transmit) {
if (index >= ARRAY_SIZE(controller->tx)) {
dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'T', index);
musb_dbg(musb, "no %cX%d CPPI channel", 'T', index);
return NULL;
}
cppi_ch = controller->tx + index;
} else {
if (index >= ARRAY_SIZE(controller->rx)) {
dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'R', index);
musb_dbg(musb, "no %cX%d CPPI channel", 'R', index);
return NULL;
}
cppi_ch = controller->rx + index;
@ -314,13 +315,13 @@ cppi_channel_allocate(struct dma_controller *c,
* with the other DMA engine too
*/
if (cppi_ch->hw_ep)
dev_dbg(musb->controller, "re-allocating DMA%d %cX channel %p\n",
musb_dbg(musb, "re-allocating DMA%d %cX channel %p",
index, transmit ? 'T' : 'R', cppi_ch);
cppi_ch->hw_ep = ep;
cppi_ch->channel.status = MUSB_DMA_STATUS_FREE;
cppi_ch->channel.max_len = 0x7fffffff;
dev_dbg(musb->controller, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R');
musb_dbg(musb, "Allocate CPPI%d %cX", index, transmit ? 'T' : 'R');
return &cppi_ch->channel;
}
@ -335,8 +336,8 @@ static void cppi_channel_release(struct dma_channel *channel)
c = container_of(channel, struct cppi_channel, channel);
tibase = c->controller->tibase;
if (!c->hw_ep)
dev_dbg(c->controller->musb->controller,
"releasing idle DMA channel %p\n", c);
musb_dbg(c->controller->musb,
"releasing idle DMA channel %p", c);
else if (!c->transmit)
core_rxirq_enable(tibase, c->index + 1);
@ -354,11 +355,10 @@ cppi_dump_rx(int level, struct cppi_channel *c, const char *tag)
musb_ep_select(base, c->index + 1);
dev_dbg(c->controller->musb->controller,
musb_dbg(c->controller->musb,
"RX DMA%d%s: %d left, csr %04x, "
"%08x H%08x S%08x C%08x, "
"B%08x L%08x %08x .. %08x"
"\n",
"B%08x L%08x %08x .. %08x",
c->index, tag,
musb_readl(c->controller->tibase,
DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index),
@ -385,11 +385,10 @@ cppi_dump_tx(int level, struct cppi_channel *c, const char *tag)
musb_ep_select(base, c->index + 1);
dev_dbg(c->controller->musb->controller,
musb_dbg(c->controller->musb,
"TX DMA%d%s: csr %04x, "
"H%08x S%08x C%08x %08x, "
"F%08x L%08x .. %08x"
"\n",
"F%08x L%08x .. %08x",
c->index, tag,
musb_readw(c->hw_ep->regs, MUSB_TXCSR),
@ -590,7 +589,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
length = min(n_bds * maxpacket, length);
}
dev_dbg(musb->controller, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n",
musb_dbg(musb, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u",
tx->index,
maxpacket,
rndis ? "rndis" : "transparent",
@ -647,7 +646,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx)
bd->hw_options |= CPPI_ZERO_SET;
}
dev_dbg(musb->controller, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n",
musb_dbg(musb, "TXBD %p: nxt %08x buf %08x len %04x opt %08x",
bd, bd->hw_next, bd->hw_bufp,
bd->hw_off_len, bd->hw_options);
@ -813,8 +812,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
length = min(n_bds * maxpacket, length);
dev_dbg(musb->controller, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
"dma 0x%llx len %u %u/%u\n",
musb_dbg(musb, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) "
"dma 0x%llx len %u %u/%u",
rx->index, maxpacket,
onepacket
? (is_rndis ? "rndis" : "onepacket")
@ -924,7 +923,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4))
& 0xffff;
if (i < (2 + n_bds)) {
dev_dbg(musb->controller, "bufcnt%d underrun - %d (for %d)\n",
musb_dbg(musb, "bufcnt%d underrun - %d (for %d)",
rx->index, i, n_bds);
musb_writel(tibase,
DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4),
@ -973,7 +972,7 @@ static int cppi_channel_program(struct dma_channel *ch,
/* WARN_ON(1); */
break;
case MUSB_DMA_STATUS_UNKNOWN:
dev_dbg(musb->controller, "%cX DMA%d not allocated!\n",
musb_dbg(musb, "%cX DMA%d not allocated!",
cppi_ch->transmit ? 'T' : 'R',
cppi_ch->index);
/* FALLTHROUGH */
@ -1029,8 +1028,8 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
if (!completed && (bd->hw_options & CPPI_OWN_SET))
break;
dev_dbg(musb->controller, "C/RXBD %llx: nxt %08x buf %08x "
"off.len %08x opt.len %08x (%d)\n",
musb_dbg(musb, "C/RXBD %llx: nxt %08x buf %08x "
"off.len %08x opt.len %08x (%d)",
(unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp,
bd->hw_off_len, bd->hw_options,
rx->channel.actual_len);
@ -1051,7 +1050,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
* CPPI ignores those BDs even though OWN is still set.
*/
completed = true;
dev_dbg(musb->controller, "rx short %d/%d (%d)\n",
musb_dbg(musb, "rx short %d/%d (%d)",
len, bd->buflen,
rx->channel.actual_len);
}
@ -1101,7 +1100,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
musb_ep_select(cppi->mregs, rx->index + 1);
csr = musb_readw(regs, MUSB_RXCSR);
if (csr & MUSB_RXCSR_DMAENAB) {
dev_dbg(musb->controller, "list%d %p/%p, last %llx%s, csr %04x\n",
musb_dbg(musb, "list%d %p/%p, last %llx%s, csr %04x",
rx->index,
rx->head, rx->tail,
rx->last_processed
@ -1164,7 +1163,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
return IRQ_NONE;
}
dev_dbg(musb->controller, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
musb_dbg(musb, "CPPI IRQ Tx%x Rx%x", tx, rx);
/* process TX channels */
for (index = 0; tx; tx = tx >> 1, index++) {
@ -1192,7 +1191,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
* that needs to be acknowledged.
*/
if (NULL == bd) {
dev_dbg(musb->controller, "null BD\n");
musb_dbg(musb, "null BD");
musb_writel(&tx_ram->tx_complete, 0, 0);
continue;
}
@ -1207,7 +1206,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
if (bd->hw_options & CPPI_OWN_SET)
break;
dev_dbg(musb->controller, "C/TXBD %p n %x b %x off %x opt %x\n",
musb_dbg(musb, "C/TXBD %p n %x b %x off %x opt %x",
bd, bd->hw_next, bd->hw_bufp,
bd->hw_off_len, bd->hw_options);

View file

@ -7,17 +7,10 @@
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/dmapool.h>
#include <linux/dmaengine.h>
#include "musb_dma.h"
#include "musb_core.h"
/* FIXME fully isolate CPPI from DaVinci ... the "CPPI generic" registers
* would seem to be shared with the TUSB6020 (over VLYNQ).
*/
#include "davinci.h"
#include "musb_dma.h"
/* CPPI RX/TX state RAM */
@ -131,4 +124,24 @@ struct cppi {
/* CPPI IRQ handler */
extern irqreturn_t cppi_interrupt(int, void *);
struct cppi41_dma_channel {
struct dma_channel channel;
struct cppi41_dma_controller *controller;
struct musb_hw_ep *hw_ep;
struct dma_chan *dc;
dma_cookie_t cookie;
u8 port_num;
u8 is_tx;
u8 is_allocated;
u8 usb_toggle;
dma_addr_t buf_addr;
u32 total_len;
u32 prog_len;
u32 transferred;
u32 packet_sz;
struct list_head tx_check;
int tx_zlp;
};
#endif /* end of ifndef _CPPI_DMA_H_ */

View file

@ -102,6 +102,7 @@
#include <linux/usb.h>
#include "musb_core.h"
#include "musb_trace.h"
#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
@ -258,31 +259,43 @@ static u32 musb_default_busctl_offset(u8 epnum, u16 offset)
static u8 musb_default_readb(const void __iomem *addr, unsigned offset)
{
return __raw_readb(addr + offset);
u8 data = __raw_readb(addr + offset);
trace_musb_readb(__builtin_return_address(0), addr, offset, data);
return data;
}
static void musb_default_writeb(void __iomem *addr, unsigned offset, u8 data)
{
trace_musb_writeb(__builtin_return_address(0), addr, offset, data);
__raw_writeb(data, addr + offset);
}
static u16 musb_default_readw(const void __iomem *addr, unsigned offset)
{
return __raw_readw(addr + offset);
u16 data = __raw_readw(addr + offset);
trace_musb_readw(__builtin_return_address(0), addr, offset, data);
return data;
}
static void musb_default_writew(void __iomem *addr, unsigned offset, u16 data)
{
trace_musb_writew(__builtin_return_address(0), addr, offset, data);
__raw_writew(data, addr + offset);
}
static u32 musb_default_readl(const void __iomem *addr, unsigned offset)
{
return __raw_readl(addr + offset);
u32 data = __raw_readl(addr + offset);
trace_musb_readl(__builtin_return_address(0), addr, offset, data);
return data;
}
static void musb_default_writel(void __iomem *addr, unsigned offset, u32 data)
{
trace_musb_writel(__builtin_return_address(0), addr, offset, data);
__raw_writel(data, addr + offset);
}
@ -461,20 +474,21 @@ static void musb_otg_timer_func(unsigned long data)
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->otg->state) {
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n");
musb_dbg(musb,
"HNP: b_wait_acon timeout; back to b_peripheral");
musb_g_disconnect(musb);
musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 0;
break;
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
dev_dbg(musb->controller, "HNP: %s timeout\n",
musb_dbg(musb, "HNP: %s timeout",
usb_otg_state_string(musb->xceiv->otg->state));
musb_platform_set_vbus(musb, 0);
musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
musb_dbg(musb, "HNP: Unhandled mode %s",
usb_otg_state_string(musb->xceiv->otg->state));
}
spin_unlock_irqrestore(&musb->lock, flags);
@ -489,17 +503,17 @@ void musb_hnp_stop(struct musb *musb)
void __iomem *mbase = musb->mregs;
u8 reg;
dev_dbg(musb->controller, "HNP: stop from %s\n",
musb_dbg(musb, "HNP: stop from %s",
usb_otg_state_string(musb->xceiv->otg->state));
switch (musb->xceiv->otg->state) {
case OTG_STATE_A_PERIPHERAL:
musb_g_disconnect(musb);
dev_dbg(musb->controller, "HNP: back to %s\n",
musb_dbg(musb, "HNP: back to %s",
usb_otg_state_string(musb->xceiv->otg->state));
break;
case OTG_STATE_B_HOST:
dev_dbg(musb->controller, "HNP: Disabling HR\n");
musb_dbg(musb, "HNP: Disabling HR");
if (hcd)
hcd->self.is_b_host = 0;
musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
@ -510,7 +524,7 @@ void musb_hnp_stop(struct musb *musb)
/* REVISIT: Start SESSION_REQUEST here? */
break;
default:
dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
musb_dbg(musb, "HNP: Stopping in unknown state %s",
usb_otg_state_string(musb->xceiv->otg->state));
}
@ -541,8 +555,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
{
irqreturn_t handled = IRQ_NONE;
dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl,
int_usb);
musb_dbg(musb, "<== DevCtl=%02x, int_usb=0x%x", devctl, int_usb);
/* in host mode, the peripheral may issue remote wakeup.
* in peripheral mode, the host may resume the link.
@ -550,7 +563,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
*/
if (int_usb & MUSB_INTR_RESUME) {
handled = IRQ_HANDLED;
dev_dbg(musb->controller, "RESUME (%s)\n",
musb_dbg(musb, "RESUME (%s)",
usb_otg_state_string(musb->xceiv->otg->state));
if (devctl & MUSB_DEVCTL_HM) {
@ -619,11 +632,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS
&& (devctl & MUSB_DEVCTL_BDEVICE)) {
dev_dbg(musb->controller, "SessReq while on B state\n");
musb_dbg(musb, "SessReq while on B state");
return IRQ_HANDLED;
}
dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
musb_dbg(musb, "SESSION_REQUEST (%s)",
usb_otg_state_string(musb->xceiv->otg->state));
/* IRQ arrives from ID pin sense or (later, if VBUS power
@ -714,7 +727,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
if (int_usb & MUSB_INTR_SUSPEND) {
dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n",
musb_dbg(musb, "SUSPEND (%s) devctl %02x",
usb_otg_state_string(musb->xceiv->otg->state), devctl);
handled = IRQ_HANDLED;
@ -743,7 +756,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->is_active = musb->g.b_hnp_enable;
if (musb->is_active) {
musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON;
dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
musb_dbg(musb, "HNP: Setting timer for b_ase0_brst");
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(
OTG_TIME_B_ASE0_BRST));
@ -760,7 +773,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break;
case OTG_STATE_B_HOST:
/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
dev_dbg(musb->controller, "REVISIT: SUSPEND as B_HOST\n");
musb_dbg(musb, "REVISIT: SUSPEND as B_HOST");
break;
default:
/* "should not happen" */
@ -797,14 +810,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
switch (musb->xceiv->otg->state) {
case OTG_STATE_B_PERIPHERAL:
if (int_usb & MUSB_INTR_SUSPEND) {
dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n");
musb_dbg(musb, "HNP: SUSPEND+CONNECT, now b_host");
int_usb &= ~MUSB_INTR_SUSPEND;
goto b_host;
} else
dev_dbg(musb->controller, "CONNECT as b_peripheral???\n");
musb_dbg(musb, "CONNECT as b_peripheral???");
break;
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n");
musb_dbg(musb, "HNP: CONNECT, now b_host");
b_host:
musb->xceiv->otg->state = OTG_STATE_B_HOST;
if (musb->hcd)
@ -823,12 +836,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb_host_poke_root_hub(musb);
dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
musb_dbg(musb, "CONNECT (%s) devctl %02x",
usb_otg_state_string(musb->xceiv->otg->state), devctl);
}
if (int_usb & MUSB_INTR_DISCONNECT) {
dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
musb_dbg(musb, "DISCONNECT (%s) as %s, devctl %02x",
usb_otg_state_string(musb->xceiv->otg->state),
MUSB_MODE(musb), devctl);
handled = IRQ_HANDLED;
@ -891,7 +904,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (is_host_active(musb))
musb_recover_from_babble(musb);
} else {
dev_dbg(musb->controller, "BUS RESET as %s\n",
musb_dbg(musb, "BUS RESET as %s",
usb_otg_state_string(musb->xceiv->otg->state));
switch (musb->xceiv->otg->state) {
case OTG_STATE_A_SUSPEND:
@ -899,7 +912,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
/* FALLTHROUGH */
case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
/* never use invalid T(a_wait_bcon) */
dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n",
musb_dbg(musb, "HNP: in %s, %d msec timeout",
usb_otg_state_string(musb->xceiv->otg->state),
TA_WAIT_BCON(musb));
mod_timer(&musb->otg_timer, jiffies
@ -910,7 +923,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb_g_reset(musb);
break;
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
musb_dbg(musb, "HNP: RESET (%s), to b_peripheral",
usb_otg_state_string(musb->xceiv->otg->state));
musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
musb_g_reset(musb);
@ -922,7 +935,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb_g_reset(musb);
break;
default:
dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
musb_dbg(musb, "Unhandled BUS RESET as %s",
usb_otg_state_string(musb->xceiv->otg->state));
}
}
@ -1030,7 +1043,7 @@ void musb_start(struct musb *musb)
u8 devctl = musb_readb(regs, MUSB_DEVCTL);
u8 power;
dev_dbg(musb->controller, "<== devctl %02x\n", devctl);
musb_dbg(musb, "<== devctl %02x", devctl);
musb_enable_interrupts(musb);
musb_writeb(regs, MUSB_TESTMODE, 0);
@ -1078,7 +1091,7 @@ void musb_stop(struct musb *musb)
/* stop IRQs, timers, ... */
musb_platform_disable(musb);
musb_generic_disable(musb);
dev_dbg(musb->controller, "HDRC disabled\n");
musb_dbg(musb, "HDRC disabled");
/* FIXME
* - mark host and/or peripheral drivers unusable/inactive
@ -1391,7 +1404,7 @@ static int ep_config_from_hw(struct musb *musb)
void __iomem *mbase = musb->mregs;
int ret = 0;
dev_dbg(musb->controller, "<== static silicon ep config\n");
musb_dbg(musb, "<== static silicon ep config");
/* FIXME pick up ep0 maxpacket size */
@ -1532,8 +1545,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
hw_ep->tx_reinit = 1;
if (hw_ep->max_packet_sz_tx) {
dev_dbg(musb->controller,
"%s: hw_ep %d%s, %smax %d\n",
musb_dbg(musb, "%s: hw_ep %d%s, %smax %d",
musb_driver_name, i,
hw_ep->is_shared_fifo ? "shared" : "tx",
hw_ep->tx_double_buffered
@ -1541,8 +1553,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
hw_ep->max_packet_sz_tx);
}
if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) {
dev_dbg(musb->controller,
"%s: hw_ep %d%s, %smax %d\n",
musb_dbg(musb, "%s: hw_ep %d%s, %smax %d",
musb_driver_name, i,
"rx",
hw_ep->rx_double_buffered
@ -1550,7 +1561,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb)
hw_ep->max_packet_sz_rx);
}
if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx))
dev_dbg(musb->controller, "hw_ep %d not configured\n", i);
musb_dbg(musb, "hw_ep %d not configured", i);
}
return 0;
@ -1577,9 +1588,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n",
is_host_active(musb) ? "host" : "peripheral",
musb->int_usb, musb->int_tx, musb->int_rx);
trace_musb_isr(musb);
/**
* According to Mentor Graphics' documentation, flowchart on page 98,
@ -1976,7 +1985,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
* Fail when the board needs a feature that's not enabled.
*/
if (!plat) {
dev_dbg(dev, "no platform_data?\n");
dev_err(dev, "no platform_data?\n");
status = -ENODEV;
goto fail0;
}

View file

@ -5,7 +5,9 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include "cppi_dma.h"
#include "musb_core.h"
#include "musb_trace.h"
#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
@ -22,26 +24,6 @@
#define USB_CTRL_AUTOREQ 0xd0
#define USB_TDOWN 0xd8
struct cppi41_dma_channel {
struct dma_channel channel;
struct cppi41_dma_controller *controller;
struct musb_hw_ep *hw_ep;
struct dma_chan *dc;
dma_cookie_t cookie;
u8 port_num;
u8 is_tx;
u8 is_allocated;
u8 usb_toggle;
dma_addr_t buf_addr;
u32 total_len;
u32 prog_len;
u32 transferred;
u32 packet_sz;
struct list_head tx_check;
int tx_zlp;
};
#define MUSB_DMA_NUM_CHANNELS 15
struct cppi41_dma_controller {
@ -96,8 +78,8 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
if (!toggle && toggle == cppi41_channel->usb_toggle) {
csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE;
musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr);
dev_dbg(cppi41_channel->controller->musb->controller,
"Restoring DATA1 toggle.\n");
musb_dbg(cppi41_channel->controller->musb,
"Restoring DATA1 toggle.");
}
cppi41_channel->usb_toggle = toggle;
@ -145,6 +127,8 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY;
musb_writew(epio, MUSB_TXCSR, csr);
}
trace_musb_cppi41_done(cppi41_channel);
musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
} else {
/* next iteration, reload */
@ -173,6 +157,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
dma_desc->callback = cppi41_dma_callback;
dma_desc->callback_param = &cppi41_channel->channel;
cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
trace_musb_cppi41_cont(cppi41_channel);
dma_async_issue_pending(dc);
if (!cppi41_channel->is_tx) {
@ -240,10 +225,7 @@ static void cppi41_dma_callback(void *private_data)
transferred = cppi41_channel->prog_len - txstate.residue;
cppi41_channel->transferred += transferred;
dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n",
hw_ep->epnum, cppi41_channel->transferred,
cppi41_channel->total_len);
trace_musb_cppi41_gb(cppi41_channel);
update_rx_toggle(cppi41_channel);
if (cppi41_channel->transferred == cppi41_channel->total_len ||
@ -374,12 +356,6 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
struct musb *musb = cppi41_channel->controller->musb;
unsigned use_gen_rndis = 0;
dev_dbg(musb->controller,
"configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num),
packet_sz, mode, (unsigned long long) dma_addr,
len, cppi41_channel->is_tx);
cppi41_channel->buf_addr = dma_addr;
cppi41_channel->total_len = len;
cppi41_channel->transferred = 0;
@ -431,6 +407,8 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
cppi41_channel->channel.rx_packet_done = false;
trace_musb_cppi41_config(cppi41_channel);
save_rx_toggle(cppi41_channel);
dma_async_issue_pending(dc);
return true;
@ -461,6 +439,7 @@ static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c,
cppi41_channel->hw_ep = hw_ep;
cppi41_channel->is_allocated = 1;
trace_musb_cppi41_alloc(cppi41_channel);
return &cppi41_channel->channel;
}
@ -468,6 +447,7 @@ static void cppi41_dma_channel_release(struct dma_channel *channel)
{
struct cppi41_dma_channel *cppi41_channel = channel->private_data;
trace_musb_cppi41_free(cppi41_channel);
if (cppi41_channel->is_allocated) {
cppi41_channel->is_allocated = 0;
channel->status = MUSB_DMA_STATUS_FREE;
@ -537,8 +517,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
u16 csr;
is_tx = cppi41_channel->is_tx;
dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n",
cppi41_channel->port_num, is_tx);
trace_musb_cppi41_abort(cppi41_channel);
if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)
return 0;

View file

@ -42,6 +42,8 @@
#define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args)
#define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)
void musb_dbg(struct musb *musb, const char *fmt, ...);
#ifdef CONFIG_DEBUG_FS
int musb_init_debugfs(struct musb *musb);
void musb_exit_debugfs(struct musb *musb);

View file

@ -51,30 +51,6 @@
static const struct of_device_id musb_dsps_of_match[];
/**
* avoid using musb_readx()/musb_writex() as glue layer should not be
* dependent on musb core layer symbols.
*/
static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
{
return __raw_readb(addr + offset);
}
static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
{
return __raw_readl(addr + offset);
}
static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
{
__raw_writeb(data, addr + offset);
}
static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
{
__raw_writel(data, addr + offset);
}
/**
* DSPS musb wrapper register offset.
* FIXME: This should be expanded to have all the wrapper registers from TI DSPS
@ -223,8 +199,8 @@ static void dsps_musb_enable(struct musb *musb)
((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift);
coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF);
dsps_writel(reg_base, wrp->epintr_set, epmask);
dsps_writel(reg_base, wrp->coreintr_set, coremask);
musb_writel(reg_base, wrp->epintr_set, epmask);
musb_writel(reg_base, wrp->coreintr_set, coremask);
/* start polling for ID change in dual-role idle mode */
if (musb->xceiv->otg->state == OTG_STATE_B_IDLE &&
musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
@ -244,10 +220,10 @@ static void dsps_musb_disable(struct musb *musb)
const struct dsps_musb_wrapper *wrp = glue->wrp;
void __iomem *reg_base = musb->ctrl_base;
dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
dsps_writel(reg_base, wrp->epintr_clear,
musb_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
musb_writel(reg_base, wrp->epintr_clear,
wrp->txep_bitmap | wrp->rxep_bitmap);
dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
}
static void otg_timer(unsigned long _musb)
@ -265,14 +241,14 @@ static void otg_timer(unsigned long _musb)
* We poll because DSPS IP's won't expose several OTG-critical
* status change events (from the transceiver) otherwise.
*/
devctl = dsps_readb(mregs, MUSB_DEVCTL);
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
usb_otg_state_string(musb->xceiv->otg->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->otg->state) {
case OTG_STATE_A_WAIT_BCON:
dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
skip_session = 1;
/* fall */
@ -286,13 +262,13 @@ static void otg_timer(unsigned long _musb)
MUSB_HST_MODE(musb);
}
if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session)
dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
musb_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
mod_timer(&glue->timer, jiffies +
msecs_to_jiffies(wrp->poll_timeout));
break;
case OTG_STATE_A_WAIT_VFALL:
musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
dsps_writel(musb->ctrl_base, wrp->coreintr_set,
musb_writel(musb->ctrl_base, wrp->coreintr_set,
MUSB_INTR_VBUSERROR << wrp->usb_shift);
break;
default:
@ -315,29 +291,29 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
spin_lock_irqsave(&musb->lock, flags);
/* Get endpoint interrupts */
epintr = dsps_readl(reg_base, wrp->epintr_status);
epintr = musb_readl(reg_base, wrp->epintr_status);
musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;
if (epintr)
dsps_writel(reg_base, wrp->epintr_status, epintr);
musb_writel(reg_base, wrp->epintr_status, epintr);
/* Get usb core interrupts */
usbintr = dsps_readl(reg_base, wrp->coreintr_status);
usbintr = musb_readl(reg_base, wrp->coreintr_status);
if (!usbintr && !epintr)
goto out;
musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
if (usbintr)
dsps_writel(reg_base, wrp->coreintr_status, usbintr);
musb_writel(reg_base, wrp->coreintr_status, usbintr);
dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
usbintr, epintr);
if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
int drvvbus = dsps_readl(reg_base, wrp->status);
int drvvbus = musb_readl(reg_base, wrp->status);
void __iomem *mregs = musb->mregs;
u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err;
err = musb->int_usb & MUSB_INTR_VBUSERROR;
@ -442,7 +418,7 @@ static int dsps_musb_init(struct musb *musb)
musb->phy = devm_phy_get(dev->parent, "usb2-phy");
/* Returns zero if e.g. not clocked */
rev = dsps_readl(reg_base, wrp->revision);
rev = musb_readl(reg_base, wrp->revision);
if (!rev)
return -ENODEV;
@ -463,14 +439,14 @@ static int dsps_musb_init(struct musb *musb)
setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
/* Reset the musb */
dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
musb_writel(reg_base, wrp->control, (1 << wrp->reset));
musb->isr = dsps_interrupt;
/* reset the otgdisable bit, needed for host mode to work */
val = dsps_readl(reg_base, wrp->phy_utmi);
val = musb_readl(reg_base, wrp->phy_utmi);
val &= ~(1 << wrp->otg_disable);
dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
musb_writel(musb->ctrl_base, wrp->phy_utmi, val);
/*
* Check whether the dsps version has babble control enabled.
@ -478,11 +454,11 @@ static int dsps_musb_init(struct musb *musb)
* If MUSB_BABBLE_CTL returns 0x4 then we have the babble control
* logic enabled.
*/
val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
val = musb_readb(musb->mregs, MUSB_BABBLE_CTL);
if (val & MUSB_BABBLE_RCV_DISABLE) {
glue->sw_babble_enabled = true;
val |= MUSB_BABBLE_SW_SESSION_CTRL;
dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val);
musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val);
}
return dsps_musb_dbg_init(musb, glue);
@ -510,7 +486,7 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode)
void __iomem *ctrl_base = musb->ctrl_base;
u32 reg;
reg = dsps_readl(ctrl_base, wrp->mode);
reg = musb_readl(ctrl_base, wrp->mode);
switch (mode) {
case MUSB_HOST:
@ -523,8 +499,8 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode)
*/
reg |= (1 << wrp->iddig_mux);
dsps_writel(ctrl_base, wrp->mode, reg);
dsps_writel(ctrl_base, wrp->phy_utmi, 0x02);
musb_writel(ctrl_base, wrp->mode, reg);
musb_writel(ctrl_base, wrp->phy_utmi, 0x02);
break;
case MUSB_PERIPHERAL:
reg |= (1 << wrp->iddig);
@ -536,10 +512,10 @@ static int dsps_musb_set_mode(struct musb *musb, u8 mode)
*/
reg |= (1 << wrp->iddig_mux);
dsps_writel(ctrl_base, wrp->mode, reg);
musb_writel(ctrl_base, wrp->mode, reg);
break;
case MUSB_OTG:
dsps_writel(ctrl_base, wrp->phy_utmi, 0x02);
musb_writel(ctrl_base, wrp->phy_utmi, 0x02);
break;
default:
dev_err(glue->dev, "unsupported mode %d\n", mode);
@ -554,7 +530,7 @@ static bool dsps_sw_babble_control(struct musb *musb)
u8 babble_ctl;
bool session_restart = false;
babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL);
dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n",
babble_ctl);
/*
@ -571,14 +547,14 @@ static bool dsps_sw_babble_control(struct musb *musb)
* babble is due to noise, then set transmit idle (d7 bit)
* to resume normal operation
*/
babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL);
babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE;
dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl);
musb_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl);
/* wait till line monitor flag cleared */
dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n");
do {
babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL);
udelay(1);
} while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--);
@ -896,13 +872,13 @@ static int dsps_suspend(struct device *dev)
return 0;
mbase = musb->ctrl_base;
glue->context.control = dsps_readl(mbase, wrp->control);
glue->context.epintr = dsps_readl(mbase, wrp->epintr_set);
glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set);
glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi);
glue->context.mode = dsps_readl(mbase, wrp->mode);
glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode);
glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode);
glue->context.control = musb_readl(mbase, wrp->control);
glue->context.epintr = musb_readl(mbase, wrp->epintr_set);
glue->context.coreintr = musb_readl(mbase, wrp->coreintr_set);
glue->context.phy_utmi = musb_readl(mbase, wrp->phy_utmi);
glue->context.mode = musb_readl(mbase, wrp->mode);
glue->context.tx_mode = musb_readl(mbase, wrp->tx_mode);
glue->context.rx_mode = musb_readl(mbase, wrp->rx_mode);
return 0;
}
@ -918,13 +894,13 @@ static int dsps_resume(struct device *dev)
return 0;
mbase = musb->ctrl_base;
dsps_writel(mbase, wrp->control, glue->context.control);
dsps_writel(mbase, wrp->epintr_set, glue->context.epintr);
dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr);
dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi);
dsps_writel(mbase, wrp->mode, glue->context.mode);
dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode);
dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode);
musb_writel(mbase, wrp->control, glue->context.control);
musb_writel(mbase, wrp->epintr_set, glue->context.epintr);
musb_writel(mbase, wrp->coreintr_set, glue->context.coreintr);
musb_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi);
musb_writel(mbase, wrp->mode, glue->context.mode);
musb_writel(mbase, wrp->tx_mode, glue->context.tx_mode);
musb_writel(mbase, wrp->rx_mode, glue->context.rx_mode);
if (musb->xceiv->otg->state == OTG_STATE_B_IDLE &&
musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
mod_timer(&glue->timer, jiffies +

View file

@ -44,6 +44,7 @@
#include <linux/slab.h>
#include "musb_core.h"
#include "musb_trace.h"
/* ----------------------------------------------------------------------- */
@ -167,15 +168,7 @@ __acquires(ep->musb->lock)
if (!dma_mapping_error(&musb->g.dev, request->dma))
unmap_dma_buffer(req, musb);
if (request->status == 0)
dev_dbg(musb->controller, "%s done request %p, %d/%d\n",
ep->end_point.name, request,
req->request.actual, req->request.length);
else
dev_dbg(musb->controller, "%s request %p, %d/%d fault %d\n",
ep->end_point.name, request,
req->request.actual, req->request.length,
request->status);
trace_musb_req_gb(req);
usb_gadget_giveback_request(&req->ep->end_point, &req->request);
spin_lock(&musb->lock);
ep->busy = busy;
@ -217,8 +210,7 @@ static void nuke(struct musb_ep *ep, const int status)
}
value = c->channel_abort(ep->dma);
dev_dbg(musb->controller, "%s: abort DMA --> %d\n",
ep->name, value);
musb_dbg(musb, "%s: abort DMA --> %d", ep->name, value);
c->channel_release(ep->dma);
ep->dma = NULL;
}
@ -266,14 +258,14 @@ static void txstate(struct musb *musb, struct musb_request *req)
/* Check if EP is disabled */
if (!musb_ep->desc) {
dev_dbg(musb->controller, "ep:%s disabled - ignore request\n",
musb_dbg(musb, "ep:%s disabled - ignore request",
musb_ep->end_point.name);
return;
}
/* we shouldn't get here while DMA is active ... but we do ... */
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
dev_dbg(musb->controller, "dma pending...\n");
musb_dbg(musb, "dma pending...");
return;
}
@ -285,18 +277,18 @@ static void txstate(struct musb *musb, struct musb_request *req)
(int)(request->length - request->actual));
if (csr & MUSB_TXCSR_TXPKTRDY) {
dev_dbg(musb->controller, "%s old packet still ready , txcsr %03x\n",
musb_dbg(musb, "%s old packet still ready , txcsr %03x",
musb_ep->end_point.name, csr);
return;
}
if (csr & MUSB_TXCSR_P_SENDSTALL) {
dev_dbg(musb->controller, "%s stalling, txcsr %03x\n",
musb_dbg(musb, "%s stalling, txcsr %03x",
musb_ep->end_point.name, csr);
return;
}
dev_dbg(musb->controller, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n",
musb_dbg(musb, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x",
epnum, musb_ep->packet_sz, fifo_count,
csr);
@ -424,7 +416,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
}
/* host may already have the data when this message shows... */
dev_dbg(musb->controller, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n",
musb_dbg(musb, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d",
musb_ep->end_point.name, use_dma ? "dma" : "pio",
request->actual, request->length,
musb_readw(epio, MUSB_TXCSR),
@ -450,8 +442,9 @@ void musb_g_tx(struct musb *musb, u8 epnum)
req = next_request(musb_ep);
request = &req->request;
trace_musb_req_tx(req);
csr = musb_readw(epio, MUSB_TXCSR);
dev_dbg(musb->controller, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr);
musb_dbg(musb, "<== %s, txcsr %04x", musb_ep->end_point.name, csr);
dma = is_dma_capable() ? musb_ep->dma : NULL;
@ -480,7 +473,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
* SHOULD NOT HAPPEN... has with CPPI though, after
* changing SENDSTALL (and other cases); harmless?
*/
dev_dbg(musb->controller, "%s dma still busy?\n", musb_ep->end_point.name);
musb_dbg(musb, "%s dma still busy?", musb_ep->end_point.name);
return;
}
@ -497,7 +490,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
/* Ensure writebuffer is empty. */
csr = musb_readw(epio, MUSB_TXCSR);
request->actual += musb_ep->dma->actual_len;
dev_dbg(musb->controller, "TXCSR%d %04x, DMA off, len %zu, req %p\n",
musb_dbg(musb, "TXCSR%d %04x, DMA off, len %zu, req %p",
epnum, csr, musb_ep->dma->actual_len, request);
}
@ -524,7 +517,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
if (csr & MUSB_TXCSR_TXPKTRDY)
return;
dev_dbg(musb->controller, "sending zero pkt\n");
musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE
| MUSB_TXCSR_TXPKTRDY);
request->zero = 0;
@ -543,7 +535,7 @@ void musb_g_tx(struct musb *musb, u8 epnum)
musb_ep_select(mbase, epnum);
req = musb_ep->desc ? next_request(musb_ep) : NULL;
if (!req) {
dev_dbg(musb->controller, "%s idle now\n",
musb_dbg(musb, "%s idle now",
musb_ep->end_point.name);
return;
}
@ -579,19 +571,19 @@ static void rxstate(struct musb *musb, struct musb_request *req)
/* Check if EP is disabled */
if (!musb_ep->desc) {
dev_dbg(musb->controller, "ep:%s disabled - ignore request\n",
musb_dbg(musb, "ep:%s disabled - ignore request",
musb_ep->end_point.name);
return;
}
/* We shouldn't get here while DMA is active, but we do... */
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
dev_dbg(musb->controller, "DMA pending...\n");
musb_dbg(musb, "DMA pending...");
return;
}
if (csr & MUSB_RXCSR_P_SENDSTALL) {
dev_dbg(musb->controller, "%s stalling, RXCSR %04x\n",
musb_dbg(musb, "%s stalling, RXCSR %04x",
musb_ep->end_point.name, csr);
return;
}
@ -766,7 +758,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
}
len = request->length - request->actual;
dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
musb_dbg(musb, "%s OUT/RX pio fifo %d/%d, maxpacket %d",
musb_ep->end_point.name,
fifo_count, len,
musb_ep->packet_sz);
@ -849,12 +841,13 @@ void musb_g_rx(struct musb *musb, u8 epnum)
if (!req)
return;
trace_musb_req_rx(req);
request = &req->request;
csr = musb_readw(epio, MUSB_RXCSR);
dma = is_dma_capable() ? musb_ep->dma : NULL;
dev_dbg(musb->controller, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name,
musb_dbg(musb, "<== %s, rxcsr %04x%s %p", musb_ep->end_point.name,
csr, dma ? " (dma)" : "", request);
if (csr & MUSB_RXCSR_P_SENTSTALL) {
@ -869,18 +862,18 @@ void musb_g_rx(struct musb *musb, u8 epnum)
csr &= ~MUSB_RXCSR_P_OVERRUN;
musb_writew(epio, MUSB_RXCSR, csr);
dev_dbg(musb->controller, "%s iso overrun on %p\n", musb_ep->name, request);
musb_dbg(musb, "%s iso overrun on %p", musb_ep->name, request);
if (request->status == -EINPROGRESS)
request->status = -EOVERFLOW;
}
if (csr & MUSB_RXCSR_INCOMPRX) {
/* REVISIT not necessarily an error */
dev_dbg(musb->controller, "%s, incomprx\n", musb_ep->end_point.name);
musb_dbg(musb, "%s, incomprx", musb_ep->end_point.name);
}
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
/* "should not happen"; likely RXPKTRDY pending for DMA */
dev_dbg(musb->controller, "%s busy, csr %04x\n",
musb_dbg(musb, "%s busy, csr %04x",
musb_ep->end_point.name, csr);
return;
}
@ -894,11 +887,6 @@ void musb_g_rx(struct musb *musb, u8 epnum)
request->actual += musb_ep->dma->actual_len;
dev_dbg(musb->controller, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n",
epnum, csr,
musb_readw(epio, MUSB_RXCSR),
musb_ep->dma->actual_len, request);
#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \
defined(CONFIG_USB_UX500_DMA)
/* Autoclear doesn't clear RxPktRdy for short packets */
@ -996,7 +984,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
ok = musb->hb_iso_rx;
if (!ok) {
dev_dbg(musb->controller, "no support for high bandwidth ISO\n");
musb_dbg(musb, "no support for high bandwidth ISO");
goto fail;
}
musb_ep->hb_mult = (tmp >> 11) & 3;
@ -1019,7 +1007,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
goto fail;
if (tmp > hw_ep->max_packet_sz_tx) {
dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n");
musb_dbg(musb, "packet size beyond hardware FIFO size");
goto fail;
}
@ -1062,7 +1050,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
goto fail;
if (tmp > hw_ep->max_packet_sz_rx) {
dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n");
musb_dbg(musb, "packet size beyond hardware FIFO size");
goto fail;
}
@ -1174,7 +1162,7 @@ static int musb_gadget_disable(struct usb_ep *ep)
spin_unlock_irqrestore(&(musb->lock), flags);
dev_dbg(musb->controller, "%s\n", musb_ep->end_point.name);
musb_dbg(musb, "%s", musb_ep->end_point.name);
return status;
}
@ -1186,19 +1174,17 @@ static int musb_gadget_disable(struct usb_ep *ep)
struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
{
struct musb_ep *musb_ep = to_musb_ep(ep);
struct musb *musb = musb_ep->musb;
struct musb_request *request = NULL;
request = kzalloc(sizeof *request, gfp_flags);
if (!request) {
dev_dbg(musb->controller, "not enough memory\n");
if (!request)
return NULL;
}
request->request.dma = DMA_ADDR_INVALID;
request->epnum = musb_ep->current_epnum;
request->ep = musb_ep;
trace_musb_req_alloc(request);
return &request->request;
}
@ -1208,7 +1194,10 @@ struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
*/
void musb_free_request(struct usb_ep *ep, struct usb_request *req)
{
kfree(to_musb_request(req));
struct musb_request *request = to_musb_request(req);
trace_musb_req_free(request);
kfree(request);
}
static LIST_HEAD(buffers);
@ -1225,10 +1214,7 @@ struct free_record {
*/
void musb_ep_restart(struct musb *musb, struct musb_request *req)
{
dev_dbg(musb->controller, "<== %s request %p len %u on hw_ep%d\n",
req->tx ? "TX/IN" : "RX/OUT",
&req->request, req->request.length, req->epnum);
trace_musb_req_start(req);
musb_ep_select(musb->mregs, req->epnum);
if (req->tx)
txstate(musb, req);
@ -1259,7 +1245,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
if (request->ep != musb_ep)
return -EINVAL;
dev_dbg(musb->controller, "<== to %s request=%p\n", ep->name, req);
trace_musb_req_enq(request);
/* request is mine now... */
request->request.actual = 0;
@ -1273,7 +1259,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
/* don't queue if the ep is down */
if (!musb_ep->desc) {
dev_dbg(musb->controller, "req %p queued to %s while ep %s\n",
musb_dbg(musb, "req %p queued to %s while ep %s",
req, ep->name, "disabled");
status = -ESHUTDOWN;
unmap_dma_buffer(request, musb);
@ -1301,9 +1287,11 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
int status = 0;
struct musb *musb = musb_ep->musb;
if (!ep || !request || to_musb_request(request)->ep != musb_ep)
if (!ep || !request || req->ep != musb_ep)
return -EINVAL;
trace_musb_req_deq(req);
spin_lock_irqsave(&musb->lock, flags);
list_for_each_entry(r, &musb_ep->req_list, list) {
@ -1311,7 +1299,8 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request)
break;
}
if (r != req) {
dev_dbg(musb->controller, "request %p not queued to %s\n", request, ep->name);
dev_err(musb->controller, "request %p not queued to %s\n",
request, ep->name);
status = -EINVAL;
goto done;
}
@ -1377,7 +1366,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)
request = next_request(musb_ep);
if (value) {
if (request) {
dev_dbg(musb->controller, "request in progress, cannot halt %s\n",
musb_dbg(musb, "request in progress, cannot halt %s",
ep->name);
status = -EAGAIN;
goto done;
@ -1386,7 +1375,8 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)
if (musb_ep->is_in) {
csr = musb_readw(epio, MUSB_TXCSR);
if (csr & MUSB_TXCSR_FIFONOTEMPTY) {
dev_dbg(musb->controller, "FIFO busy, cannot halt %s\n", ep->name);
musb_dbg(musb, "FIFO busy, cannot halt %s",
ep->name);
status = -EAGAIN;
goto done;
}
@ -1395,7 +1385,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)
musb_ep->wedged = 0;
/* set/clear the stall and toggle bits */
dev_dbg(musb->controller, "%s: %s stall\n", ep->name, value ? "set" : "clear");
musb_dbg(musb, "%s: %s stall", ep->name, value ? "set" : "clear");
if (musb_ep->is_in) {
csr = musb_readw(epio, MUSB_TXCSR);
csr |= MUSB_TXCSR_P_WZC_BITS
@ -1422,7 +1412,7 @@ static int musb_gadget_set_halt(struct usb_ep *ep, int value)
/* maybe start the first request in the queue */
if (!musb_ep->busy && !value && request) {
dev_dbg(musb->controller, "restarting the request\n");
musb_dbg(musb, "restarting the request");
musb_ep_restart(musb, request);
}
@ -1558,7 +1548,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
case OTG_STATE_B_IDLE:
/* Start SRP ... OTG not required. */
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Sending SRP: devctl: %02x\n", devctl);
musb_dbg(musb, "Sending SRP: devctl: %02x", devctl);
devctl |= MUSB_DEVCTL_SESSION;
musb_writeb(mregs, MUSB_DEVCTL, devctl);
devctl = musb_readb(mregs, MUSB_DEVCTL);
@ -1586,7 +1576,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
status = 0;
goto done;
default:
dev_dbg(musb->controller, "Unhandled wake: %s\n",
musb_dbg(musb, "Unhandled wake: %s",
usb_otg_state_string(musb->xceiv->otg->state));
goto done;
}
@ -1596,7 +1586,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
power = musb_readb(mregs, MUSB_POWER);
power |= MUSB_POWER_RESUME;
musb_writeb(mregs, MUSB_POWER, power);
dev_dbg(musb->controller, "issue wakeup\n");
musb_dbg(musb, "issue wakeup");
/* FIXME do this next chunk in a timer callback, no udelay */
mdelay(2);
@ -1628,7 +1618,7 @@ static void musb_pullup(struct musb *musb, int is_on)
/* FIXME if on, HdrcStart; if off, HdrcStop */
dev_dbg(musb->controller, "gadget D+ pullup %s\n",
musb_dbg(musb, "gadget D+ pullup %s",
is_on ? "on" : "off");
musb_writeb(musb->mregs, MUSB_POWER, power);
}
@ -1636,7 +1626,7 @@ static void musb_pullup(struct musb *musb, int is_on)
#if 0
static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active)
{
dev_dbg(musb->controller, "<= %s =>\n", __func__);
musb_dbg(musb, "<= %s =>\n", __func__);
/*
* FIXME iff driver's softconnect flag is set (as it is during probe,
@ -2011,7 +2001,7 @@ void musb_g_suspend(struct musb *musb)
u8 devctl;
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "devctl %02x\n", devctl);
musb_dbg(musb, "musb_g_suspend: devctl %02x", devctl);
switch (musb->xceiv->otg->state) {
case OTG_STATE_B_IDLE:
@ -2030,7 +2020,7 @@ void musb_g_suspend(struct musb *musb)
/* REVISIT if B_HOST, clear DEVCTL.HOSTREQ;
* A_PERIPHERAL may need care too
*/
WARNING("unhandled SUSPEND transition (%s)\n",
WARNING("unhandled SUSPEND transition (%s)",
usb_otg_state_string(musb->xceiv->otg->state));
}
}
@ -2047,7 +2037,7 @@ void musb_g_disconnect(struct musb *musb)
void __iomem *mregs = musb->mregs;
u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "devctl %02x\n", devctl);
musb_dbg(musb, "musb_g_disconnect: devctl %02x", devctl);
/* clear HR */
musb_writeb(mregs, MUSB_DEVCTL, devctl & MUSB_DEVCTL_SESSION);
@ -2064,7 +2054,7 @@ void musb_g_disconnect(struct musb *musb)
switch (musb->xceiv->otg->state) {
default:
dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
musb_dbg(musb, "Unhandled disconnect %s, setting a_idle",
usb_otg_state_string(musb->xceiv->otg->state));
musb->xceiv->otg->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
@ -2094,7 +2084,7 @@ __acquires(musb->lock)
u8 devctl = musb_readb(mbase, MUSB_DEVCTL);
u8 power;
dev_dbg(musb->controller, "<== %s driver '%s'\n",
musb_dbg(musb, "<== %s driver '%s'",
(devctl & MUSB_DEVCTL_BDEVICE)
? "B-Device" : "A-Device",
musb->gadget_driver

View file

@ -206,7 +206,7 @@ static inline void musb_try_b_hnp_enable(struct musb *musb)
void __iomem *mbase = musb->mregs;
u8 devctl;
dev_dbg(musb->controller, "HNP: Setting HR\n");
musb_dbg(musb, "HNP: Setting HR");
devctl = musb_readb(mbase, MUSB_DEVCTL);
musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR);
}
@ -303,7 +303,7 @@ __acquires(musb->lock)
/* Maybe start the first request in the queue */
request = next_request(musb_ep);
if (!musb_ep->busy && request) {
dev_dbg(musb->controller, "restarting the request\n");
musb_dbg(musb, "restarting the request");
musb_ep_restart(musb, request);
}
@ -550,7 +550,7 @@ static void ep0_txstate(struct musb *musb)
if (!req) {
/* WARN_ON(1); */
dev_dbg(musb->controller, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0));
musb_dbg(musb, "odd; csr0 %04x", musb_readw(regs, MUSB_CSR0));
return;
}
@ -607,7 +607,7 @@ musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req)
/* NOTE: earlier 2.6 versions changed setup packets to host
* order, but now USB packets always stay in USB byte order.
*/
dev_dbg(musb->controller, "SETUP req%02x.%02x v%04x i%04x l%d\n",
musb_dbg(musb, "SETUP req%02x.%02x v%04x i%04x l%d",
req->bRequestType,
req->bRequest,
le16_to_cpu(req->wValue),
@ -675,7 +675,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
csr = musb_readw(regs, MUSB_CSR0);
len = musb_readb(regs, MUSB_COUNT0);
dev_dbg(musb->controller, "csr %04x, count %d, ep0stage %s\n",
musb_dbg(musb, "csr %04x, count %d, ep0stage %s",
csr, len, decode_ep0stage(musb->ep0_state));
if (csr & MUSB_CSR0_P_DATAEND) {
@ -752,7 +752,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
/* enter test mode if needed (exit by reset) */
else if (musb->test_mode) {
dev_dbg(musb->controller, "entering TESTMODE\n");
musb_dbg(musb, "entering TESTMODE");
if (MUSB_TEST_PACKET == musb->test_mode_nr)
musb_load_testpacket(musb);
@ -864,7 +864,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
break;
}
dev_dbg(musb->controller, "handled %d, csr %04x, ep0stage %s\n",
musb_dbg(musb, "handled %d, csr %04x, ep0stage %s",
handled, csr,
decode_ep0stage(musb->ep0_state));
@ -881,7 +881,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
if (handled < 0) {
musb_ep_select(mbase, 0);
stall:
dev_dbg(musb->controller, "stall (%d)\n", handled);
musb_dbg(musb, "stall (%d)", handled);
musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
musb->ep0_state = MUSB_EP0_STAGE_IDLE;
finish:
@ -961,7 +961,7 @@ musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
status = 0;
break;
default:
dev_dbg(musb->controller, "ep0 request queued in state %d\n",
musb_dbg(musb, "ep0 request queued in state %d",
musb->ep0_state);
status = -EINVAL;
goto cleanup;
@ -970,7 +970,7 @@ musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
/* add request to the list */
list_add_tail(&req->list, &ep->req_list);
dev_dbg(musb->controller, "queue to %s (%s), length=%d\n",
musb_dbg(musb, "queue to %s (%s), length=%d",
ep->name, ep->is_in ? "IN/TX" : "OUT/RX",
req->request.length);
@ -1063,7 +1063,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value)
musb->ackpend = 0;
break;
default:
dev_dbg(musb->controller, "ep0 can't halt in state %d\n", musb->ep0_state);
musb_dbg(musb, "ep0 can't halt in state %d", musb->ep0_state);
status = -EINVAL;
}

View file

@ -44,6 +44,7 @@
#include "musb_core.h"
#include "musb_host.h"
#include "musb_trace.h"
/* MUSB HOST status 22-mar-2006
*
@ -131,7 +132,7 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
* I found using a usb-ethernet device and running iperf
* (client on AM335x) has very high chance to trigger it.
*
* Better to turn on dev_dbg() in musb_cleanup_urb() with
* Better to turn on musb_dbg() in musb_cleanup_urb() with
* CPPI enabled to see the issue when aborting the tx channel.
*/
if (dev_WARN_ONCE(musb->controller, retries-- < 1,
@ -225,8 +226,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
void *buf = urb->transfer_buffer;
u32 offset = 0;
struct musb_hw_ep *hw_ep = qh->hw_ep;
unsigned pipe = urb->pipe;
u8 address = usb_pipedevice(pipe);
int epnum = hw_ep->epnum;
/* initialize software qh state */
@ -254,16 +253,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
len = urb->transfer_buffer_length - urb->actual_length;
}
dev_dbg(musb->controller, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n",
qh, urb, address, qh->epnum,
is_in ? "in" : "out",
({char *s; switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL: s = ""; break;
case USB_ENDPOINT_XFER_BULK: s = "-bulk"; break;
case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break;
default: s = "-intr"; break;
} s; }),
epnum, buf + offset, len);
trace_musb_urb_start(musb, urb);
/* Configure endpoint */
musb_ep_set_qh(hw_ep, is_in, qh);
@ -277,7 +267,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
switch (qh->type) {
case USB_ENDPOINT_XFER_ISOC:
case USB_ENDPOINT_XFER_INT:
dev_dbg(musb->controller, "check whether there's still time for periodic Tx\n");
musb_dbg(musb, "check whether there's still time for periodic Tx");
frame = musb_readw(mbase, MUSB_FRAME);
/* FIXME this doesn't implement that scheduling policy ...
* or handle framecounter wrapping
@ -291,7 +281,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
} else {
qh->frame = urb->start_frame;
/* enable SOF interrupt so we can count down */
dev_dbg(musb->controller, "SOF for %d\n", epnum);
musb_dbg(musb, "SOF for %d", epnum);
#if 1 /* ifndef CONFIG_ARCH_DAVINCI */
musb_writeb(mbase, MUSB_INTRUSBE, 0xff);
#endif
@ -299,7 +289,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
break;
default:
start:
dev_dbg(musb->controller, "Start TX%d %s\n", epnum,
musb_dbg(musb, "Start TX%d %s", epnum,
hw_ep->tx_channel ? "dma" : "pio");
if (!hw_ep->tx_channel)
@ -314,14 +304,7 @@ static void musb_giveback(struct musb *musb, struct urb *urb, int status)
__releases(musb->lock)
__acquires(musb->lock)
{
dev_dbg(musb->controller,
"complete %p %pF (%d), dev%d ep%d%s, %d/%d\n",
urb, urb->complete, status,
usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
urb->actual_length, urb->transfer_buffer_length
);
trace_musb_urb_gb(musb, urb);
usb_hcd_unlink_urb_from_ep(musb->hcd, urb);
spin_unlock(&musb->lock);
@ -441,7 +424,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
* for RX, until we have a test case to understand the behavior of TX.
*/
if ((!status || !is_in) && qh && qh->is_ready) {
dev_dbg(musb->controller, "... next ep%d %cX urb %p\n",
musb_dbg(musb, "... next ep%d %cX urb %p",
hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
musb_start_urb(musb, is_in, qh);
}
@ -486,7 +469,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)
/* musb_ep_select(mbase, epnum); */
rx_count = musb_readw(epio, MUSB_RXCOUNT);
dev_dbg(musb->controller, "RX%d count %d, buffer %p len %d/%d\n", epnum, rx_count,
musb_dbg(musb, "RX%d count %d, buffer %p len %d/%d", epnum, rx_count,
urb->transfer_buffer, qh->offset,
urb->transfer_buffer_length);
@ -508,7 +491,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)
status = -EOVERFLOW;
urb->error_count++;
}
dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length);
musb_dbg(musb, "OVERFLOW %d into %d", rx_count, length);
do_flush = 1;
} else
length = rx_count;
@ -526,7 +509,7 @@ musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err)
if (rx_count > length) {
if (urb->status == -EINPROGRESS)
urb->status = -EOVERFLOW;
dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length);
musb_dbg(musb, "OVERFLOW %d into %d", rx_count, length);
do_flush = 1;
} else
length = rx_count;
@ -750,8 +733,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
u8 use_dma = 1;
u16 csr;
dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s "
"h_addr%02x h_port%02x bytes %d\n",
musb_dbg(musb, "%s hw%d urb %p spd%d dev%d ep%d%s "
"h_addr%02x h_port%02x bytes %d",
is_out ? "-->" : "<--",
epnum, urb, urb->dev->speed,
qh->addr_reg, qh->epnum, is_out ? "out" : "in",
@ -969,7 +952,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
}
csr |= MUSB_RXCSR_H_REQPKT;
dev_dbg(musb->controller, "RXCSR%d := %04x\n", epnum, csr);
musb_dbg(musb, "RXCSR%d := %04x", epnum, csr);
musb_writew(hw_ep->regs, MUSB_RXCSR, csr);
csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
}
@ -1085,15 +1068,15 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
request = (struct usb_ctrlrequest *) urb->setup_packet;
if (!request->wLength) {
dev_dbg(musb->controller, "start no-DATA\n");
musb_dbg(musb, "start no-DATA");
break;
} else if (request->bRequestType & USB_DIR_IN) {
dev_dbg(musb->controller, "start IN-DATA\n");
musb_dbg(musb, "start IN-DATA");
musb->ep0_stage = MUSB_EP0_IN;
more = true;
break;
} else {
dev_dbg(musb->controller, "start OUT-DATA\n");
musb_dbg(musb, "start OUT-DATA");
musb->ep0_stage = MUSB_EP0_OUT;
more = true;
}
@ -1105,7 +1088,7 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
if (fifo_count) {
fifo_dest = (u8 *) (urb->transfer_buffer
+ urb->actual_length);
dev_dbg(musb->controller, "Sending %d byte%s to ep0 fifo %p\n",
musb_dbg(musb, "Sending %d byte%s to ep0 fifo %p",
fifo_count,
(fifo_count == 1) ? "" : "s",
fifo_dest);
@ -1150,7 +1133,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
? musb_readb(epio, MUSB_COUNT0)
: 0;
dev_dbg(musb->controller, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n",
musb_dbg(musb, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d",
csr, qh, len, urb, musb->ep0_stage);
/* if we just did status stage, we are done */
@ -1161,15 +1144,15 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
/* prepare status */
if (csr & MUSB_CSR0_H_RXSTALL) {
dev_dbg(musb->controller, "STALLING ENDPOINT\n");
musb_dbg(musb, "STALLING ENDPOINT");
status = -EPIPE;
} else if (csr & MUSB_CSR0_H_ERROR) {
dev_dbg(musb->controller, "no response, csr0 %04x\n", csr);
musb_dbg(musb, "no response, csr0 %04x", csr);
status = -EPROTO;
} else if (csr & MUSB_CSR0_H_NAKTIMEOUT) {
dev_dbg(musb->controller, "control NAK timeout\n");
musb_dbg(musb, "control NAK timeout");
/* NOTE: this code path would be a good place to PAUSE a
* control transfer, if another one is queued, so that
@ -1184,7 +1167,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
}
if (status) {
dev_dbg(musb->controller, "aborting\n");
musb_dbg(musb, "aborting");
retval = IRQ_HANDLED;
if (urb)
urb->status = status;
@ -1237,7 +1220,7 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
/* flag status stage */
musb->ep0_stage = MUSB_EP0_STATUS;
dev_dbg(musb->controller, "ep0 STATUS, csr %04x\n", csr);
musb_dbg(musb, "ep0 STATUS, csr %04x", csr);
}
musb_writew(epio, MUSB_CSR0, csr);
@ -1291,38 +1274,37 @@ void musb_host_tx(struct musb *musb, u8 epnum)
/* with CPPI, DMA sometimes triggers "extra" irqs */
if (!urb) {
dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
musb_dbg(musb, "extra TX%d ready, csr %04x", epnum, tx_csr);
return;
}
pipe = urb->pipe;
dma = is_dma_capable() ? hw_ep->tx_channel : NULL;
dev_dbg(musb->controller, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr,
trace_musb_urb_tx(musb, urb);
musb_dbg(musb, "OUT/TX%d end, csr %04x%s", epnum, tx_csr,
dma ? ", dma" : "");
/* check for errors */
if (tx_csr & MUSB_TXCSR_H_RXSTALL) {
/* dma was disabled, fifo flushed */
dev_dbg(musb->controller, "TX end %d stall\n", epnum);
musb_dbg(musb, "TX end %d stall", epnum);
/* stall; record URB status */
status = -EPIPE;
} else if (tx_csr & MUSB_TXCSR_H_ERROR) {
/* (NON-ISO) dma was disabled, fifo flushed */
dev_dbg(musb->controller, "TX 3strikes on ep=%d\n", epnum);
musb_dbg(musb, "TX 3strikes on ep=%d", epnum);
status = -ETIMEDOUT;
} else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) {
if (USB_ENDPOINT_XFER_BULK == qh->type && qh->mux == 1
&& !list_is_singular(&musb->out_bulk)) {
dev_dbg(musb->controller,
"NAK timeout on TX%d ep\n", epnum);
musb_dbg(musb, "NAK timeout on TX%d ep", epnum);
musb_bulk_nak_timeout(musb, hw_ep, 0);
} else {
dev_dbg(musb->controller,
"TX end=%d device not responding\n", epnum);
musb_dbg(musb, "TX ep%d device not responding", epnum);
/* NOTE: this code path would be a good place to PAUSE a
* transfer, if there's some other (nonperiodic) tx urb
* that could use this fifo. (dma complicates it...)
@ -1368,7 +1350,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
/* second cppi case */
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr);
musb_dbg(musb, "extra TX%d ready, csr %04x", epnum, tx_csr);
return;
}
@ -1427,8 +1409,9 @@ void musb_host_tx(struct musb *musb, u8 epnum)
* FIFO mode too...
*/
if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) {
dev_dbg(musb->controller, "DMA complete but packet still in FIFO, "
"CSR %04x\n", tx_csr);
musb_dbg(musb,
"DMA complete but FIFO not empty, CSR %04x",
tx_csr);
return;
}
}
@ -1494,7 +1477,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
}
} else if (tx_csr & MUSB_TXCSR_DMAENAB) {
dev_dbg(musb->controller, "not complete, but DMA enabled?\n");
musb_dbg(musb, "not complete, but DMA enabled?");
return;
}
@ -1723,7 +1706,7 @@ static int musb_rx_dma_in_inventra_cppi41(struct dma_controller *dma,
d_status = -EOVERFLOW;
urb->error_count++;
}
dev_dbg(musb->controller, "** OVERFLOW %d into %d\n",
musb_dbg(musb, "** OVERFLOW %d into %d",
rx_count, d->length);
length = d->length;
@ -1847,28 +1830,26 @@ void musb_host_rx(struct musb *musb, u8 epnum)
* usbtest #11 (unlinks) triggers it regularly, sometimes
* with fifo full. (Only with DMA??)
*/
dev_dbg(musb->controller, "BOGUS RX%d ready, csr %04x, count %d\n", epnum, val,
musb_readw(epio, MUSB_RXCOUNT));
musb_dbg(musb, "BOGUS RX%d ready, csr %04x, count %d",
epnum, val, musb_readw(epio, MUSB_RXCOUNT));
musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG);
return;
}
pipe = urb->pipe;
dev_dbg(musb->controller, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n",
epnum, rx_csr, urb->actual_length,
dma ? dma->actual_len : 0);
trace_musb_urb_rx(musb, urb);
/* check for errors, concurrent stall & unlink is not really
* handled yet! */
if (rx_csr & MUSB_RXCSR_H_RXSTALL) {
dev_dbg(musb->controller, "RX end %d STALL\n", epnum);
musb_dbg(musb, "RX end %d STALL", epnum);
/* stall; record URB status */
status = -EPIPE;
} else if (rx_csr & MUSB_RXCSR_H_ERROR) {
dev_dbg(musb->controller, "end %d RX proto error\n", epnum);
musb_dbg(musb, "end %d RX proto error", epnum);
status = -EPROTO;
musb_writeb(epio, MUSB_RXINTERVAL, 0);
@ -1879,7 +1860,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
} else if (rx_csr & MUSB_RXCSR_DATAERROR) {
if (USB_ENDPOINT_XFER_ISOC != qh->type) {
dev_dbg(musb->controller, "RX end %d NAK timeout\n", epnum);
musb_dbg(musb, "RX end %d NAK timeout", epnum);
/* NOTE: NAKing is *NOT* an error, so we want to
* continue. Except ... if there's a request for
@ -1902,12 +1883,12 @@ void musb_host_rx(struct musb *musb, u8 epnum)
goto finish;
} else {
dev_dbg(musb->controller, "RX end %d ISO data error\n", epnum);
musb_dbg(musb, "RX end %d ISO data error", epnum);
/* packet error reported later */
iso_err = true;
}
} else if (rx_csr & MUSB_RXCSR_INCOMPRX) {
dev_dbg(musb->controller, "end %d high bandwidth incomplete ISO packet RX\n",
musb_dbg(musb, "end %d high bandwidth incomplete ISO packet RX",
epnum);
status = -EPROTO;
}
@ -1952,7 +1933,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
done = true;
}
dev_dbg(musb->controller, "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr,
musb_dbg(musb, "RXCSR%d %04x, reqpkt, len %zu%s", epnum, rx_csr,
xfer_len, dma ? ", dma" : "");
rx_csr &= ~MUSB_RXCSR_H_REQPKT;
@ -1973,8 +1954,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
if (musb_dma_inventra(musb) || musb_dma_ux500(musb) ||
musb_dma_cppi41(musb)) {
done = musb_rx_dma_inventra_cppi41(c, hw_ep, qh, urb, xfer_len);
dev_dbg(hw_ep->musb->controller,
"ep %d dma %s, rxcsr %04x, rxcount %d\n",
musb_dbg(hw_ep->musb,
"ep %d dma %s, rxcsr %04x, rxcount %d",
epnum, done ? "off" : "reset",
musb_readw(epio, MUSB_RXCSR),
musb_readw(epio, MUSB_RXCOUNT));
@ -2001,8 +1982,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
/* we are expecting IN packets */
if ((musb_dma_inventra(musb) || musb_dma_ux500(musb) ||
musb_dma_cppi41(musb)) && dma) {
dev_dbg(hw_ep->musb->controller,
"RX%d count %d, buffer 0x%llx len %d/%d\n",
musb_dbg(hw_ep->musb,
"RX%d count %d, buffer 0x%llx len %d/%d",
epnum, musb_readw(epio, MUSB_RXCOUNT),
(unsigned long long) urb->transfer_dma
+ urb->actual_length,
@ -2054,7 +2035,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
done = musb_host_packet_rx(musb, urb,
epnum, iso_err);
}
dev_dbg(musb->controller, "read %spacket\n", done ? "last " : "");
musb_dbg(musb, "read %spacket", done ? "last " : "");
}
}
@ -2178,7 +2159,7 @@ static int musb_schedule(
idle = 1;
qh->mux = 0;
hw_ep = musb->endpoints + best_end;
dev_dbg(musb->controller, "qh %p periodic slot %d\n", qh, best_end);
musb_dbg(musb, "qh %p periodic slot %d", qh, best_end);
success:
if (head) {
idle = list_empty(head);
@ -2210,6 +2191,8 @@ static int musb_urb_enqueue(
if (!is_host_active(musb) || !musb->is_active)
return -ENODEV;
trace_musb_urb_enq(musb, urb);
spin_lock_irqsave(&musb->lock, flags);
ret = usb_hcd_link_urb_to_ep(hcd, urb);
qh = ret ? NULL : hep->hcpriv;
@ -2400,8 +2383,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
dma = is_in ? ep->rx_channel : ep->tx_channel;
if (dma) {
status = ep->musb->dma_controller->channel_abort(dma);
dev_dbg(musb->controller,
"abort %cX%d DMA for urb %p --> %d\n",
musb_dbg(musb, "abort %cX%d DMA for urb %p --> %d",
is_in ? 'R' : 'T', ep->epnum,
urb, status);
urb->actual_length += dma->actual_len;
@ -2447,10 +2429,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
int is_in = usb_pipein(urb->pipe);
int ret;
dev_dbg(musb->controller, "urb=%p, dev%d ep%d%s\n", urb,
usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe),
is_in ? "in" : "out");
trace_musb_urb_deq(musb, urb);
spin_lock_irqsave(&musb->lock, flags);
ret = usb_hcd_check_unlink_urb(hcd, urb, status);

View file

@ -0,0 +1,33 @@
/*
* musb_trace.c - MUSB Controller Trace Support
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Bin Liu <b-liu@ti.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define CREATE_TRACE_POINTS
#include "musb_trace.h"
void musb_dbg(struct musb *musb, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
trace_musb_log(musb, &vaf);
va_end(args);
}

View file

@ -0,0 +1,371 @@
/*
* musb_trace.h - MUSB Controller Trace Support
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Bin Liu <b-liu@ti.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM musb
#if !defined(__MUSB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define __MUSB_TRACE_H
#include <linux/types.h>
#include <linux/tracepoint.h>
#include <linux/usb.h>
#include "musb_core.h"
#ifdef CONFIG_USB_TI_CPPI41_DMA
#include "cppi_dma.h"
#endif
#define MUSB_MSG_MAX 500
TRACE_EVENT(musb_log,
TP_PROTO(struct musb *musb, struct va_format *vaf),
TP_ARGS(musb, vaf),
TP_STRUCT__entry(
__string(name, dev_name(musb->controller))
__dynamic_array(char, msg, MUSB_MSG_MAX)
),
TP_fast_assign(
__assign_str(name, dev_name(musb->controller));
vsnprintf(__get_str(msg), MUSB_MSG_MAX, vaf->fmt, *vaf->va);
),
TP_printk("%s: %s", __get_str(name), __get_str(msg))
);
DECLARE_EVENT_CLASS(musb_regb,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u8 data),
TP_ARGS(caller, addr, offset, data),
TP_STRUCT__entry(
__field(void *, caller)
__field(const void *, addr)
__field(unsigned int, offset)
__field(u8, data)
),
TP_fast_assign(
__entry->caller = caller;
__entry->addr = addr;
__entry->offset = offset;
__entry->data = data;
),
TP_printk("%pS: %p + %04x: %02x",
__entry->caller, __entry->addr, __entry->offset, __entry->data)
);
DEFINE_EVENT(musb_regb, musb_readb,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u8 data),
TP_ARGS(caller, addr, offset, data)
);
DEFINE_EVENT(musb_regb, musb_writeb,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u8 data),
TP_ARGS(caller, addr, offset, data)
);
DECLARE_EVENT_CLASS(musb_regw,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u16 data),
TP_ARGS(caller, addr, offset, data),
TP_STRUCT__entry(
__field(void *, caller)
__field(const void *, addr)
__field(unsigned int, offset)
__field(u16, data)
),
TP_fast_assign(
__entry->caller = caller;
__entry->addr = addr;
__entry->offset = offset;
__entry->data = data;
),
TP_printk("%pS: %p + %04x: %04x",
__entry->caller, __entry->addr, __entry->offset, __entry->data)
);
DEFINE_EVENT(musb_regw, musb_readw,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u16 data),
TP_ARGS(caller, addr, offset, data)
);
DEFINE_EVENT(musb_regw, musb_writew,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u16 data),
TP_ARGS(caller, addr, offset, data)
);
DECLARE_EVENT_CLASS(musb_regl,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u32 data),
TP_ARGS(caller, addr, offset, data),
TP_STRUCT__entry(
__field(void *, caller)
__field(const void *, addr)
__field(unsigned int, offset)
__field(u32, data)
),
TP_fast_assign(
__entry->caller = caller;
__entry->addr = addr;
__entry->offset = offset;
__entry->data = data;
),
TP_printk("%pS: %p + %04x: %08x",
__entry->caller, __entry->addr, __entry->offset, __entry->data)
);
DEFINE_EVENT(musb_regl, musb_readl,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u32 data),
TP_ARGS(caller, addr, offset, data)
);
DEFINE_EVENT(musb_regl, musb_writel,
TP_PROTO(void *caller, const void *addr, unsigned int offset, u32 data),
TP_ARGS(caller, addr, offset, data)
);
TRACE_EVENT(musb_isr,
TP_PROTO(struct musb *musb),
TP_ARGS(musb),
TP_STRUCT__entry(
__string(name, dev_name(musb->controller))
__field(u8, int_usb)
__field(u16, int_tx)
__field(u16, int_rx)
),
TP_fast_assign(
__assign_str(name, dev_name(musb->controller));
__entry->int_usb = musb->int_usb;
__entry->int_tx = musb->int_tx;
__entry->int_rx = musb->int_rx;
),
TP_printk("%s: usb %02x, tx %04x, rx %04x",
__get_str(name), __entry->int_usb,
__entry->int_tx, __entry->int_rx
)
);
DECLARE_EVENT_CLASS(musb_urb,
TP_PROTO(struct musb *musb, struct urb *urb),
TP_ARGS(musb, urb),
TP_STRUCT__entry(
__string(name, dev_name(musb->controller))
__field(struct urb *, urb)
__field(unsigned int, pipe)
__field(int, status)
__field(unsigned int, flag)
__field(u32, buf_len)
__field(u32, actual_len)
),
TP_fast_assign(
__assign_str(name, dev_name(musb->controller));
__entry->urb = urb;
__entry->pipe = urb->pipe;
__entry->status = urb->status;
__entry->flag = urb->transfer_flags;
__entry->buf_len = urb->transfer_buffer_length;
__entry->actual_len = urb->actual_length;
),
TP_printk("%s: %p, dev%d ep%d%s, flag 0x%x, len %d/%d, status %d",
__get_str(name), __entry->urb,
usb_pipedevice(__entry->pipe),
usb_pipeendpoint(__entry->pipe),
usb_pipein(__entry->pipe) ? "in" : "out",
__entry->flag,
__entry->actual_len, __entry->buf_len,
__entry->status
)
);
DEFINE_EVENT(musb_urb, musb_urb_start,
TP_PROTO(struct musb *musb, struct urb *urb),
TP_ARGS(musb, urb)
);
DEFINE_EVENT(musb_urb, musb_urb_gb,
TP_PROTO(struct musb *musb, struct urb *urb),
TP_ARGS(musb, urb)
);
DEFINE_EVENT(musb_urb, musb_urb_rx,
TP_PROTO(struct musb *musb, struct urb *urb),
TP_ARGS(musb, urb)
);
DEFINE_EVENT(musb_urb, musb_urb_tx,
TP_PROTO(struct musb *musb, struct urb *urb),
TP_ARGS(musb, urb)
);
DEFINE_EVENT(musb_urb, musb_urb_enq,
TP_PROTO(struct musb *musb, struct urb *urb),
TP_ARGS(musb, urb)
);
DEFINE_EVENT(musb_urb, musb_urb_deq,
TP_PROTO(struct musb *musb, struct urb *urb),
TP_ARGS(musb, urb)
);
DECLARE_EVENT_CLASS(musb_req,
TP_PROTO(struct musb_request *req),
TP_ARGS(req),
TP_STRUCT__entry(
__field(struct usb_request *, req)
__field(u8, is_tx)
__field(u8, epnum)
__field(int, status)
__field(unsigned int, buf_len)
__field(unsigned int, actual_len)
__field(unsigned int, zero)
__field(unsigned int, short_not_ok)
__field(unsigned int, no_interrupt)
),
TP_fast_assign(
__entry->req = &req->request;
__entry->is_tx = req->tx;
__entry->epnum = req->epnum;
__entry->status = req->request.status;
__entry->buf_len = req->request.length;
__entry->actual_len = req->request.actual;
__entry->zero = req->request.zero;
__entry->short_not_ok = req->request.short_not_ok;
__entry->no_interrupt = req->request.no_interrupt;
),
TP_printk("%p, ep%d %s, %s%s%s, len %d/%d, status %d",
__entry->req, __entry->epnum,
__entry->is_tx ? "tx/IN" : "rx/OUT",
__entry->zero ? "Z" : "z",
__entry->short_not_ok ? "S" : "s",
__entry->no_interrupt ? "I" : "i",
__entry->actual_len, __entry->buf_len,
__entry->status
)
);
DEFINE_EVENT(musb_req, musb_req_gb,
TP_PROTO(struct musb_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(musb_req, musb_req_tx,
TP_PROTO(struct musb_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(musb_req, musb_req_rx,
TP_PROTO(struct musb_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(musb_req, musb_req_alloc,
TP_PROTO(struct musb_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(musb_req, musb_req_free,
TP_PROTO(struct musb_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(musb_req, musb_req_start,
TP_PROTO(struct musb_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(musb_req, musb_req_enq,
TP_PROTO(struct musb_request *req),
TP_ARGS(req)
);
DEFINE_EVENT(musb_req, musb_req_deq,
TP_PROTO(struct musb_request *req),
TP_ARGS(req)
);
#ifdef CONFIG_USB_TI_CPPI41_DMA
DECLARE_EVENT_CLASS(musb_cppi41,
TP_PROTO(struct cppi41_dma_channel *ch),
TP_ARGS(ch),
TP_STRUCT__entry(
__field(struct cppi41_dma_channel *, ch)
__string(name, dev_name(ch->hw_ep->musb->controller))
__field(u8, hwep)
__field(u8, port)
__field(u8, is_tx)
__field(u32, len)
__field(u32, prog_len)
__field(u32, xferred)
),
TP_fast_assign(
__entry->ch = ch;
__assign_str(name, dev_name(ch->hw_ep->musb->controller));
__entry->hwep = ch->hw_ep->epnum;
__entry->port = ch->port_num;
__entry->is_tx = ch->is_tx;
__entry->len = ch->total_len;
__entry->prog_len = ch->prog_len;
__entry->xferred = ch->transferred;
),
TP_printk("%s: %p, hwep%d ch%d%s, prog_len %d, len %d/%d",
__get_str(name), __entry->ch, __entry->hwep,
__entry->port, __entry->is_tx ? "tx" : "rx",
__entry->prog_len, __entry->xferred, __entry->len
)
);
DEFINE_EVENT(musb_cppi41, musb_cppi41_done,
TP_PROTO(struct cppi41_dma_channel *ch),
TP_ARGS(ch)
);
DEFINE_EVENT(musb_cppi41, musb_cppi41_gb,
TP_PROTO(struct cppi41_dma_channel *ch),
TP_ARGS(ch)
);
DEFINE_EVENT(musb_cppi41, musb_cppi41_config,
TP_PROTO(struct cppi41_dma_channel *ch),
TP_ARGS(ch)
);
DEFINE_EVENT(musb_cppi41, musb_cppi41_cont,
TP_PROTO(struct cppi41_dma_channel *ch),
TP_ARGS(ch)
);
DEFINE_EVENT(musb_cppi41, musb_cppi41_alloc,
TP_PROTO(struct cppi41_dma_channel *ch),
TP_ARGS(ch)
);
DEFINE_EVENT(musb_cppi41, musb_cppi41_abort,
TP_PROTO(struct cppi41_dma_channel *ch),
TP_ARGS(ch)
);
DEFINE_EVENT(musb_cppi41, musb_cppi41_free,
TP_PROTO(struct cppi41_dma_channel *ch),
TP_ARGS(ch)
);
#endif /* CONFIG_USB_TI_CPPI41_DMA */
#endif /* __MUSB_TRACE_H */
/* this part has to be here */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE musb_trace
#include <trace/define_trace.h>

View file

@ -55,8 +55,7 @@ void musb_host_finish_resume(struct work_struct *work)
power = musb_readb(musb->mregs, MUSB_POWER);
power &= ~MUSB_POWER_RESUME;
dev_dbg(musb->controller, "root port resume stopped, power %02x\n",
power);
musb_dbg(musb, "root port resume stopped, power %02x", power);
musb_writeb(musb->mregs, MUSB_POWER, power);
/*
@ -104,7 +103,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend)
break;
}
dev_dbg(musb->controller, "Root port suspended, power %02x\n", power);
musb_dbg(musb, "Root port suspended, power %02x", power);
musb->port1_status |= USB_PORT_STAT_SUSPEND;
switch (musb->xceiv->otg->state) {
@ -123,7 +122,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend)
musb_platform_try_idle(musb, 0);
break;
default:
dev_dbg(musb->controller, "bogus rh suspend? %s\n",
musb_dbg(musb, "bogus rh suspend? %s",
usb_otg_state_string(musb->xceiv->otg->state));
}
} else if (power & MUSB_POWER_SUSPENDM) {
@ -131,7 +130,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend)
power |= MUSB_POWER_RESUME;
musb_writeb(mbase, MUSB_POWER, power);
dev_dbg(musb->controller, "Root port resuming, power %02x\n", power);
musb_dbg(musb, "Root port resuming, power %02x", power);
/* later, GetPortStatus will stop RESUME signaling */
musb->port1_status |= MUSB_PORT_STAT_RESUME;
@ -146,7 +145,7 @@ void musb_port_reset(struct musb *musb, bool do_reset)
void __iomem *mbase = musb->mregs;
if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) {
dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n");
musb_dbg(musb, "HNP: Returning from HNP; no hub reset from b_idle");
musb->port1_status &= ~USB_PORT_STAT_RESET;
return;
}
@ -194,7 +193,7 @@ void musb_port_reset(struct musb *musb, bool do_reset)
schedule_delayed_work(&musb->deassert_reset_work,
msecs_to_jiffies(50));
} else {
dev_dbg(musb->controller, "root port reset stopped\n");
musb_dbg(musb, "root port reset stopped");
musb_platform_pre_root_reset_end(musb);
musb_writeb(mbase, MUSB_POWER,
power & ~MUSB_POWER_RESET);
@ -202,7 +201,7 @@ void musb_port_reset(struct musb *musb, bool do_reset)
power = musb_readb(mbase, MUSB_POWER);
if (power & MUSB_POWER_HSMODE) {
dev_dbg(musb->controller, "high-speed device connected\n");
musb_dbg(musb, "high-speed device connected");
musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;
}
@ -242,7 +241,7 @@ void musb_root_disconnect(struct musb *musb)
musb->xceiv->otg->state = OTG_STATE_B_IDLE;
break;
default:
dev_dbg(musb->controller, "host disconnect (%s)\n",
musb_dbg(musb, "host disconnect (%s)",
usb_otg_state_string(musb->xceiv->otg->state));
}
}
@ -337,7 +336,7 @@ int musb_hub_control(
default:
goto error;
}
dev_dbg(musb->controller, "clear feature %d\n", wValue);
musb_dbg(musb, "clear feature %d", wValue);
musb->port1_status &= ~(1 << wValue);
break;
case GetHubDescriptor:
@ -372,8 +371,7 @@ int musb_hub_control(
(__le32 *) buf);
/* port change status is more interesting */
dev_dbg(musb->controller, "port status %08x\n",
musb->port1_status);
musb_dbg(musb, "port status %08x", musb->port1_status);
break;
case SetPortFeature:
if ((wIndex & 0xff) != 1)
@ -443,7 +441,7 @@ int musb_hub_control(
default:
goto error;
}
dev_dbg(musb->controller, "set feature %d\n", wValue);
musb_dbg(musb, "set feature %d", wValue);
musb->port1_status |= 1 << wValue;
break;

View file

@ -117,7 +117,7 @@ static void configure_channel(struct dma_channel *channel,
u8 bchannel = musb_channel->idx;
u16 csr = 0;
dev_dbg(musb->controller, "%p, pkt_sz %d, addr %pad, len %d, mode %d\n",
musb_dbg(musb, "%p, pkt_sz %d, addr %pad, len %d, mode %d",
channel, packet_sz, &dma_addr, len, mode);
if (mode) {
@ -152,7 +152,7 @@ static int dma_channel_program(struct dma_channel *channel,
struct musb_dma_controller *controller = musb_channel->controller;
struct musb *musb = controller->private_data;
dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr %pad length %d, mode %d\n",
musb_dbg(musb, "ep%d-%s pkt_sz %d, dma_addr %pad length %d, mode %d",
musb_channel->epnum,
musb_channel->transmit ? "Tx" : "Rx",
packet_sz, &dma_addr, len, mode);
@ -266,7 +266,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
#endif
if (!int_hsdma) {
dev_dbg(musb->controller, "spurious DMA irq\n");
musb_dbg(musb, "spurious DMA irq");
for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
musb_channel = (struct musb_dma_channel *)
@ -280,7 +280,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
}
}
dev_dbg(musb->controller, "int_hsdma = 0x%x\n", int_hsdma);
musb_dbg(musb, "int_hsdma = 0x%x", int_hsdma);
if (!int_hsdma)
goto done;
@ -307,7 +307,7 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
channel->actual_len = addr
- musb_channel->start_addr;
dev_dbg(musb->controller, "ch %p, 0x%x -> 0x%x (%zu / %d) %s\n",
musb_dbg(musb, "ch %p, 0x%x -> 0x%x (%zu / %d) %s",
channel, musb_channel->start_addr,
addr, channel->actual_len,
musb_channel->len,

View file

@ -256,12 +256,10 @@ static int sunxi_musb_init(struct musb *musb)
writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0);
/* Register notifier before calling phy_init() */
if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) {
ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
if (ret)
goto error_reset_assert;
}
ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
if (ret)
goto error_reset_assert;
ret = phy_init(glue->phy);
if (ret)
@ -275,9 +273,8 @@ static int sunxi_musb_init(struct musb *musb)
return 0;
error_unregister_notifier:
if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
error_reset_assert:
if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
reset_control_assert(glue->rst);
@ -301,9 +298,8 @@ static int sunxi_musb_exit(struct musb *musb)
phy_exit(glue->phy);
if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
reset_control_assert(glue->rst);
@ -315,25 +311,6 @@ static int sunxi_musb_exit(struct musb *musb)
return 0;
}
static int sunxi_set_mode(struct musb *musb, u8 mode)
{
struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
int ret;
if (mode == MUSB_HOST) {
ret = phy_power_on(glue->phy);
if (ret)
return ret;
set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
/* Stop musb work from turning vbus off again */
set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
}
return 0;
}
static void sunxi_musb_enable(struct musb *musb)
{
struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
@ -354,13 +331,13 @@ static void sunxi_musb_disable(struct musb *musb)
clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags);
}
struct dma_controller *sunxi_musb_dma_controller_create(struct musb *musb,
void __iomem *base)
static struct dma_controller *
sunxi_musb_dma_controller_create(struct musb *musb, void __iomem *base)
{
return NULL;
}
void sunxi_musb_dma_controller_destroy(struct dma_controller *c)
static void sunxi_musb_dma_controller_destroy(struct dma_controller *c)
{
}
@ -582,7 +559,6 @@ static const struct musb_platform_ops sunxi_musb_ops = {
.exit = sunxi_musb_exit,
.enable = sunxi_musb_enable,
.disable = sunxi_musb_disable,
.set_mode = sunxi_set_mode,
.fifo_offset = sunxi_musb_fifo_offset,
.ep_offset = sunxi_musb_ep_offset,
.busctl_offset = sunxi_musb_busctl_offset,
@ -638,10 +614,6 @@ static int sunxi_musb_probe(struct platform_device *pdev)
return -EINVAL;
}
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue)
return -ENOMEM;
memset(&pdata, 0, sizeof(pdata));
switch (usb_get_dr_mode(&pdev->dev)) {
#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST
@ -649,15 +621,13 @@ static int sunxi_musb_probe(struct platform_device *pdev)
pdata.mode = MUSB_PORT_MODE_HOST;
break;
#endif
#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_GADGET
case USB_DR_MODE_PERIPHERAL:
pdata.mode = MUSB_PORT_MODE_GADGET;
break;
#endif
#ifdef CONFIG_USB_MUSB_DUAL_ROLE
case USB_DR_MODE_OTG:
glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
if (IS_ERR(glue->extcon)) {
if (PTR_ERR(glue->extcon) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "Invalid or missing extcon\n");
return PTR_ERR(glue->extcon);
}
pdata.mode = MUSB_PORT_MODE_DUAL_ROLE;
break;
#endif
@ -668,6 +638,10 @@ static int sunxi_musb_probe(struct platform_device *pdev)
pdata.platform_ops = &sunxi_musb_ops;
pdata.config = &sunxi_musb_hdrc_config;
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue)
return -ENOMEM;
glue->dev = &pdev->dev;
INIT_WORK(&glue->work, sunxi_musb_work);
glue->host_nb.notifier_call = sunxi_musb_host_notifier;
@ -701,6 +675,14 @@ static int sunxi_musb_probe(struct platform_device *pdev)
}
}
glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
if (IS_ERR(glue->extcon)) {
if (PTR_ERR(glue->extcon) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "Invalid or missing extcon\n");
return PTR_ERR(glue->extcon);
}
glue->phy = devm_phy_get(&pdev->dev, "usb");
if (IS_ERR(glue->phy)) {
if (PTR_ERR(glue->phy) == -EPROBE_DEFER)

View file

@ -21,6 +21,7 @@ config AB8500_USB
config FSL_USB2_OTG
bool "Freescale USB OTG Transceiver Driver"
depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
select USB_PHY
help
Enable this to support Freescale USB OTG transceiver.
@ -29,6 +30,7 @@ config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
depends on USB
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
select USB_PHY
help
If you say yes here you get support for the Philips ISP1301
@ -43,7 +45,7 @@ config ISP1301_OMAP
config KEYSTONE_USB_PHY
tristate "Keystone USB PHY Driver"
depends on ARCH_KEYSTONE || COMPILE_TEST
select NOP_USB_XCEIV
depends on NOP_USB_XCEIV
help
Enable this to support Keystone USB phy. This driver provides
interface to interact with USB 2.0 and USB 3.0 PHY that is part
@ -51,6 +53,7 @@ config KEYSTONE_USB_PHY
config NOP_USB_XCEIV
tristate "NOP USB Transceiver Driver"
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, NOP can't be built-in
select USB_PHY
help
This driver is to be used by all the usb transceiver which are either
@ -63,9 +66,9 @@ config AM335X_CONTROL_USB
config AM335X_PHY_USB
tristate "AM335x USB PHY Driver"
depends on ARM || COMPILE_TEST
depends on NOP_USB_XCEIV
select USB_PHY
select AM335X_CONTROL_USB
select NOP_USB_XCEIV
select USB_COMMON
help
This driver provides PHY support for that phy which part for the
@ -92,6 +95,7 @@ config TWL6030_USB
config USB_GPIO_VBUS
tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
depends on GPIOLIB || COMPILE_TEST
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
select USB_PHY
help
Provides simple GPIO VBUS sensing for controllers with an
@ -112,6 +116,7 @@ config OMAP_OTG
config TAHVO_USB
tristate "Tahvo USB transceiver driver"
depends on MFD_RETU && EXTCON
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
select USB_PHY
help
Enable this to support USB transceiver on Tahvo. This is used
@ -140,6 +145,7 @@ config USB_ISP1301
config USB_MSM_OTG
tristate "Qualcomm on-chip USB OTG controller support"
depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST)
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
depends on RESET_CONTROLLER
depends on EXTCON
select USB_PHY
@ -169,6 +175,7 @@ config USB_QCOM_8X16_PHY
config USB_MV_OTG
tristate "Marvell USB OTG support"
depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG
depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y'
select USB_PHY
help
Say Y here if you want to build Marvell USB OTG transciever

View file

@ -54,7 +54,7 @@ static int am335x_phy_probe(struct platform_device *pdev)
return am_phy->id;
}
am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node);
am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1);
ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL);
if (ret)

View file

@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/extcon.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
@ -35,6 +36,8 @@
#include <linux/of_device.h>
#include <linux/reboot.h>
#include <linux/reset.h>
#include <linux/types.h>
#include <linux/usb/otg.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
@ -42,10 +45,183 @@
#include <linux/usb/ulpi.h>
#include <linux/usb/gadget.h>
#include <linux/usb/hcd.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/regulator/consumer.h>
/**
* OTG control
*
* OTG_NO_CONTROL Id/VBUS notifications not required. Useful in host
* only configuration.
* OTG_PHY_CONTROL Id/VBUS notifications comes form USB PHY.
* OTG_PMIC_CONTROL Id/VBUS notifications comes from PMIC hardware.
* OTG_USER_CONTROL Id/VBUS notifcations comes from User via sysfs.
*
*/
enum otg_control_type {
OTG_NO_CONTROL = 0,
OTG_PHY_CONTROL,
OTG_PMIC_CONTROL,
OTG_USER_CONTROL,
};
/**
* PHY used in
*
* INVALID_PHY Unsupported PHY
* CI_45NM_INTEGRATED_PHY Chipidea 45nm integrated PHY
* SNPS_28NM_INTEGRATED_PHY Synopsis 28nm integrated PHY
*
*/
enum msm_usb_phy_type {
INVALID_PHY = 0,
CI_45NM_INTEGRATED_PHY,
SNPS_28NM_INTEGRATED_PHY,
};
#define IDEV_CHG_MAX 1500
#define IUNIT 100
/**
* Different states involved in USB charger detection.
*
* USB_CHG_STATE_UNDEFINED USB charger is not connected or detection
* process is not yet started.
* USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact.
* USB_CHG_STATE_DCD_DONE Data pin contact is detected.
* USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects
* between SDP and DCP/CDP).
* USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects
* between DCP and CDP).
* USB_CHG_STATE_DETECTED USB charger type is determined.
*
*/
enum usb_chg_state {
USB_CHG_STATE_UNDEFINED = 0,
USB_CHG_STATE_WAIT_FOR_DCD,
USB_CHG_STATE_DCD_DONE,
USB_CHG_STATE_PRIMARY_DONE,
USB_CHG_STATE_SECONDARY_DONE,
USB_CHG_STATE_DETECTED,
};
/**
* USB charger types
*
* USB_INVALID_CHARGER Invalid USB charger.
* USB_SDP_CHARGER Standard downstream port. Refers to a downstream port
* on USB2.0 compliant host/hub.
* USB_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger).
* USB_CDP_CHARGER Charging downstream port. Enumeration can happen and
* IDEV_CHG_MAX can be drawn irrespective of USB state.
*
*/
enum usb_chg_type {
USB_INVALID_CHARGER = 0,
USB_SDP_CHARGER,
USB_DCP_CHARGER,
USB_CDP_CHARGER,
};
/**
* struct msm_otg_platform_data - platform device data
* for msm_otg driver.
* @phy_init_seq: PHY configuration sequence values. Value of -1 is reserved as
* "do not overwrite default vaule at this address".
* @phy_init_sz: PHY configuration sequence size.
* @vbus_power: VBUS power on/off routine.
* @power_budget: VBUS power budget in mA (0 will be treated as 500mA).
* @mode: Supported mode (OTG/peripheral/host).
* @otg_control: OTG switch controlled by user/Id pin
*/
struct msm_otg_platform_data {
int *phy_init_seq;
int phy_init_sz;
void (*vbus_power)(bool on);
unsigned power_budget;
enum usb_dr_mode mode;
enum otg_control_type otg_control;
enum msm_usb_phy_type phy_type;
void (*setup_gpio)(enum usb_otg_state state);
};
/**
* struct msm_usb_cable - structure for exteternal connector cable
* state tracking
* @nb: hold event notification callback
* @conn: used for notification registration
*/
struct msm_usb_cable {
struct notifier_block nb;
struct extcon_dev *extcon;
};
/**
* struct msm_otg: OTG driver data. Shared by HCD and DCD.
* @otg: USB OTG Transceiver structure.
* @pdata: otg device platform data.
* @irq: IRQ number assigned for HSUSB controller.
* @clk: clock struct of usb_hs_clk.
* @pclk: clock struct of usb_hs_pclk.
* @core_clk: clock struct of usb_hs_core_clk.
* @regs: ioremapped register base address.
* @inputs: OTG state machine inputs(Id, SessValid etc).
* @sm_work: OTG state machine work.
* @in_lpm: indicates low power mode (LPM) state.
* @async_int: Async interrupt arrived.
* @cur_power: The amount of mA available from downstream port.
* @chg_work: Charger detection work.
* @chg_state: The state of charger detection process.
* @chg_type: The type of charger attached.
* @dcd_retires: The retry count used to track Data contact
* detection process.
* @manual_pullup: true if VBUS is not routed to USB controller/phy
* and controller driver therefore enables pull-up explicitly before
* starting controller using usbcmd run/stop bit.
* @vbus: VBUS signal state trakining, using extcon framework
* @id: ID signal state trakining, using extcon framework
* @switch_gpio: Descriptor for GPIO used to control external Dual
* SPDT USB Switch.
* @reboot: Used to inform the driver to route USB D+/D- line to Device
* connector
*/
struct msm_otg {
struct usb_phy phy;
struct msm_otg_platform_data *pdata;
int irq;
struct clk *clk;
struct clk *pclk;
struct clk *core_clk;
void __iomem *regs;
#define ID 0
#define B_SESS_VLD 1
unsigned long inputs;
struct work_struct sm_work;
atomic_t in_lpm;
int async_int;
unsigned cur_power;
int phy_number;
struct delayed_work chg_work;
enum usb_chg_state chg_state;
enum usb_chg_type chg_type;
u8 dcd_retries;
struct regulator *v3p3;
struct regulator *v1p8;
struct regulator *vddcx;
struct reset_control *phy_rst;
struct reset_control *link_rst;
int vdd_levels[3];
bool manual_pullup;
struct msm_usb_cable vbus;
struct msm_usb_cable id;
struct gpio_desc *switch_gpio;
struct notifier_block reboot;
};
#define MSM_USB_BASE (motg->regs)
#define DRIVER_NAME "msm_otg"

View file

@ -148,7 +148,7 @@ static int omap_otg_remove(struct platform_device *pdev)
struct otg_device *otg_dev = platform_get_drvdata(pdev);
struct extcon_dev *edev = otg_dev->extcon;
extcon_unregister_notifier(edev, EXTCON_USB_HOST,&otg_dev->id_nb);
extcon_unregister_notifier(edev, EXTCON_USB_HOST, &otg_dev->id_nb);
extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb);
return 0;

View file

@ -697,7 +697,7 @@ static int usbhs_probe(struct platform_device *pdev)
probe_end_pipe_exit:
usbhs_pipe_remove(priv);
dev_info(&pdev->dev, "probe failed\n");
dev_info(&pdev->dev, "probe failed (%d)\n", ret);
return ret;
}

View file

@ -810,20 +810,27 @@ static void xfer_work(struct work_struct *work)
{
struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
struct usbhs_fifo *fifo;
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
struct dma_chan *chan;
struct device *dev = usbhs_priv_to_dev(priv);
enum dma_transfer_direction dir;
unsigned long flags;
usbhs_lock(priv, flags);
fifo = usbhs_pipe_to_fifo(pipe);
if (!fifo)
goto xfer_work_end;
chan = usbhsf_dma_chan_get(fifo, pkt);
dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
desc = dmaengine_prep_slave_single(chan, pkt->dma + pkt->actual,
pkt->trans, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
return;
goto xfer_work_end;
desc->callback = usbhsf_dma_complete;
desc->callback_param = pipe;
@ -831,7 +838,7 @@ static void xfer_work(struct work_struct *work)
pkt->cookie = dmaengine_submit(desc);
if (pkt->cookie < 0) {
dev_err(dev, "Failed to submit dma descriptor\n");
return;
goto xfer_work_end;
}
dev_dbg(dev, " %s %d (%d/ %d)\n",
@ -842,6 +849,9 @@ static void xfer_work(struct work_struct *work)
usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
dma_async_issue_pending(chan);
usbhs_pipe_enable(pipe);
xfer_work_end:
usbhs_unlock(priv, flags);
}
/*

Some files were not shown because too many files have changed in this diff Show more