Commit e152813f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

Felipe writes:

usb: patches for v4.2 merge window

- dwc2 adds hibernation support
- preparation for sunxi glue to musb driver
- new ULPI bus
- new ULPI PHY driver for TUSB1210
- musb patches to support multiple DMA engines on same binary
- support for R-Car E2 on renesas_usbhs
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parents 74db22cb e18b7975
TWL BCI (Battery Charger Interface)
The battery charger needs to interact with the USB phy in order
to know when charging is permissible, and when there is a connection
or disconnection.
The choice of phy cannot be configured at a hardware level, so there
is no value in explicit configuration in device-tree. Rather
if there is a sibling of the BCI node which is compatible with
"ti,twl4030-usb", then that is used to determine when and how
use USB power for charging.
Required properties:
- compatible:
- "ti,twl4030-bci"
......
......@@ -49,8 +49,7 @@ st_dwc3: dwc3@8f94000 {
st,syscfg = <&syscfg_core>;
resets = <&powerdown STIH407_USB3_POWERDOWN>,
<&softreset STIH407_MIPHY2_SOFTRESET>;
reset-names = "powerdown",
"softreset";
reset-names = "powerdown", "softreset";
#address-cells = <1>;
#size-cells = <1>;
pinctrl-names = "default";
......@@ -62,7 +61,7 @@ st_dwc3: dwc3@8f94000 {
reg = <0x09900000 0x100000>;
interrupts = <GIC_SPI 155 IRQ_TYPE_NONE>;
dr_mode = "host";
phys-names = "usb2-phy", "usb3-phy";
phys = <&usb2_picophy2>, <&phy_port2 MIPHY_TYPE_USB>;
phy-names = "usb2-phy", "usb3-phy";
phys = <&usb2_picophy2>, <&phy_port2 PHY_TYPE_USB3>;
};
};
......@@ -38,6 +38,8 @@ Optional properties:
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
utmi_l1_suspend_n, false when asserts utmi_sleep_n
- snps,hird-threshold: HIRD threshold
- snps,hsphy_interface: High-Speed PHY interface selection between "utmi" for
UTMI+ and "ulpi" for ULPI when the DWC_USB3_HSPHY_INTERFACE has value 3.
This is usually a subnode to DWC3 glue to which it is connected.
......
......@@ -69,6 +69,17 @@ Optional properties:
(no, min, max) where each value represents either a voltage
in microvolts or a value corresponding to voltage corner.
- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy
and controller driver therefore enables pull-up explicitly
before starting controller using usbcmd run/stop bit.
- extcon: phandles to external connector devices. First phandle
should point to external connector, which provide "USB"
cable events, the second should point to external connector
device, which provide "USB-HOST" cable events. If one of
the external connector devices is not required empty <0>
phandle should be specified.
Example HSUSB OTG controller device node:
usb@f9a55000 {
......
......@@ -4,6 +4,7 @@ Required properties:
- compatible: Must contain one of the following:
- "renesas,usbhs-r8a7790"
- "renesas,usbhs-r8a7791"
- "renesas,usbhs-r8a7794"
- reg: Base address and length of the register for the USBHS
- interrupts: Interrupt specifier for the USBHS
- clocks: A list of phandle + clock specifier pairs
......@@ -15,10 +16,8 @@ Optional properties:
- phys: phandle + phy specifier pair
- phy-names: must be "usb"
- dmas: Must contain a list of references to DMA specifiers.
- dma-names : Must contain a list of DMA names:
- tx0 ... tx<n>
- rx0 ... rx<n>
- This <n> means DnFIFO in USBHS module.
- dma-names : named "ch%d", where %d is the channel number ranging from zero
to the number of channels (DnFIFOs) minus one.
Example:
usbhs: usb@e6590000 {
......
......@@ -30,6 +30,9 @@ TWL4030 USB PHY AND COMPARATOR
- usb_mode : The mode used by the phy to connect to the controller. "1"
specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode.
If a sibling node is compatible "ti,twl4030-bci", then it will find
this device and query it for USB power status.
twl4030-usb {
compatible = "ti,twl4030-usb";
interrupts = < 10 4 >;
......
......@@ -526,8 +526,6 @@ Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
By default there can be only 1 RNDIS interface in the system.
Testing the RNDIS function
--------------------------
......@@ -629,7 +627,7 @@ Function-specific configfs interface
The function name to use when creating the function directory is "uac2".
The uac2 function provides these attributes in its function directory:
chmask - capture channel mask
c_chmask - capture channel mask
c_srate - capture sampling rate
c_ssize - capture sample size (bytes)
p_chmask - playback channel mask
......
......@@ -10489,6 +10489,13 @@ S: Maintained
F: Documentation/video4linux/zr364xx.txt
F: drivers/media/usb/zr364xx/
ULPI BUS
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/common/ulpi.c
F: include/linux/ulpi/
USER-MODE LINUX (UML)
M: Jeff Dike <jdike@addtoit.com>
M: Richard Weinberger <richard@nod.at>
......
......@@ -309,4 +309,11 @@ config PHY_QCOM_UFS
help
Support for UFS PHY on QCOM chipsets.
config PHY_TUSB1210
tristate "TI TUSB1210 ULPI PHY module"
depends on USB_ULPI_BUS
select GENERIC_PHY
help
Support for TI TUSB1210 USB ULPI PHY.
endmenu
......@@ -40,3 +40,4 @@ obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
......@@ -30,6 +30,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/phy/phy-sun4i-usb.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
......@@ -58,6 +59,7 @@
#define PHY_OTG_FUNC_EN 0x28
#define PHY_VBUS_DET_EN 0x29
#define PHY_DISCON_TH_SEL 0x2a
#define PHY_SQUELCH_DETECT 0x3c
#define MAX_PHYS 3
......@@ -204,6 +206,13 @@ static int sun4i_usb_phy_power_off(struct phy *_phy)
return 0;
}
void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
{
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
}
static struct phy_ops sun4i_usb_phy_ops = {
.init = sun4i_usb_phy_init,
.exit = sun4i_usb_phy_exit,
......
/**
* tusb1210.c - TUSB1210 USB ULPI PHY driver
*
* Copyright (C) 2015 Intel Corporation
*
* Author: Heikki Krogerus <heikki.krogerus@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 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/ulpi/driver.h>
#include <linux/gpio/consumer.h>
#include "ulpi_phy.h"
#define TUSB1210_VENDOR_SPECIFIC2 0x80
#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT 0
#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT 4
#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT 6
struct tusb1210 {
struct ulpi *ulpi;
struct phy *phy;
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_cs;
u8 vendor_specific2;
};
static int tusb1210_power_on(struct phy *phy)
{
struct tusb1210 *tusb = phy_get_drvdata(phy);
gpiod_set_value_cansleep(tusb->gpio_reset, 1);
gpiod_set_value_cansleep(tusb->gpio_cs, 1);
/* Restore the optional eye diagram optimization value */
if (tusb->vendor_specific2)
ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2,
tusb->vendor_specific2);
return 0;
}
static int tusb1210_power_off(struct phy *phy)
{
struct tusb1210 *tusb = phy_get_drvdata(phy);
gpiod_set_value_cansleep(tusb->gpio_reset, 0);
gpiod_set_value_cansleep(tusb->gpio_cs, 0);
return 0;
}
static struct phy_ops phy_ops = {
.power_on = tusb1210_power_on,
.power_off = tusb1210_power_off,
.owner = THIS_MODULE,
};
static int tusb1210_probe(struct ulpi *ulpi)
{
struct gpio_desc *gpio;
struct tusb1210 *tusb;
u8 val, reg;
int ret;
tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
if (!tusb)
return -ENOMEM;
gpio = devm_gpiod_get(&ulpi->dev, "reset");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
return ret;
gpiod_set_value_cansleep(gpio, 1);
tusb->gpio_reset = gpio;
}
gpio = devm_gpiod_get(&ulpi->dev, "cs");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
return ret;
gpiod_set_value_cansleep(gpio, 1);
tusb->gpio_cs = gpio;
}
/*
* VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye
* diagram optimization and DP/DM swap.
*/
/* High speed output drive strength configuration */
device_property_read_u8(&ulpi->dev, "ihstx", &val);
reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT;
/* High speed output impedance configuration */
device_property_read_u8(&ulpi->dev, "zhsdrv", &val);
reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT;
/* DP/DM swap control */
device_property_read_u8(&ulpi->dev, "datapolarity", &val);
reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT;
if (reg) {
ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
tusb->vendor_specific2 = reg;
}
tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
if (IS_ERR(tusb->phy))
return PTR_ERR(tusb->phy);
tusb->ulpi = ulpi;
phy_set_drvdata(tusb->phy, tusb);
ulpi_set_drvdata(ulpi, tusb);
return 0;
}
static void tusb1210_remove(struct ulpi *ulpi)
{
struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
ulpi_phy_destroy(ulpi, tusb->phy);
}
#define TI_VENDOR_ID 0x0451
static const struct ulpi_device_id tusb1210_ulpi_id[] = {
{ TI_VENDOR_ID, 0x1507, },
{ },
};
MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
static struct ulpi_driver tusb1210_driver = {
.id_table = tusb1210_ulpi_id,
.probe = tusb1210_probe,
.remove = tusb1210_remove,
.driver = {
.name = "tusb1210",
.owner = THIS_MODULE,
},
};
module_ulpi_driver(tusb1210_driver);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");
#include <linux/phy/phy.h>
/**
* Helper that registers PHY for a ULPI device and adds a lookup for binding it
* and it's controller, which is always the parent.
*/
static inline struct phy
*ulpi_phy_create(struct ulpi *ulpi, struct phy_ops *ops)
{
struct phy *phy;
int ret;
phy = phy_create(&ulpi->dev, NULL, ops);
if (IS_ERR(phy))
return phy;
ret = phy_create_lookup(phy, "usb2-phy", dev_name(ulpi->dev.parent));
if (ret) {
phy_destroy(phy);
return ERR_PTR(ret);
}
return phy;
}
/* Remove a PHY that was created with ulpi_phy_create() and it's lookup. */
static inline void ulpi_phy_destroy(struct ulpi *ulpi, struct phy *phy)
{
phy_remove_lookup(phy, "usb2-phy", dev_name(ulpi->dev.parent));
phy_destroy(phy);
}
......@@ -638,10 +638,15 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
INIT_WORK(&bci->work, twl4030_bci_usb_work);
bci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (!IS_ERR_OR_NULL(bci->transceiver)) {
bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
usb_register_notifier(bci->transceiver, &bci->usb_nb);
bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
if (bci->dev->of_node) {
struct device_node *phynode;
phynode = of_find_compatible_node(bci->dev->of_node->parent,
NULL, "ti,twl4030-usb");
if (phynode)
bci->transceiver = devm_usb_get_phy_by_node(
bci->dev, phynode, &bci->usb_nb);
}
/* Enable interrupts now. */
......@@ -671,10 +676,6 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
return 0;
fail_unmask_interrupts:
if (!IS_ERR_OR_NULL(bci->transceiver)) {
usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
usb_put_phy(bci->transceiver);
}
free_irq(bci->irq_bci, bci);
fail_bci_irq:
free_irq(bci->irq_chg, bci);
......@@ -703,10 +704,6 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
TWL4030_INTERRUPTS_BCIIMR2A);
if (!IS_ERR_OR_NULL(bci->transceiver)) {
usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
usb_put_phy(bci->transceiver);
}
free_irq(bci->irq_bci, bci);
free_irq(bci->irq_chg, bci);
power_supply_unregister(bci->usb);
......
......@@ -7,3 +7,4 @@ usb-common-y += common.o
usb-common-$(CONFIG_USB_LED_TRIG) += led.o
obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
obj-$(CONFIG_USB_ULPI_BUS) += ulpi.o
/**
* ulpi.c - USB ULPI PHY bus
*
* Copyright (C) 2015 Intel Corporation
*
* Author: Heikki Krogerus <heikki.krogerus@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 as
* published by the Free Software Foundation.
*/
#include <linux/ulpi/interface.h>
#include <linux/ulpi/driver.h>
#include <linux/ulpi/regs.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/acpi.h>
/* -------------------------------------------------------------------------- */
int ulpi_read(struct ulpi *ulpi, u8 addr)
{
return ulpi->ops->read(ulpi->ops, addr);
}
EXPORT_SYMBOL_GPL(ulpi_read);
int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val)
{
return ulpi->ops->write(ulpi->ops, addr, val);
}
EXPORT_SYMBOL_GPL(ulpi_write);
/* -------------------------------------------------------------------------- */
static int ulpi_match(struct device *dev, struct device_driver *driver)
{
struct ulpi_driver *drv = to_ulpi_driver(driver);
struct ulpi *ulpi = to_ulpi_dev(dev);
const struct ulpi_device_id *id;
for (id = drv->id_table; id->vendor; id++)
if (id->vendor == ulpi->id.vendor &&
id->product == ulpi->id.product)
return 1;
return 0;
}
static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct ulpi *ulpi = to_ulpi_dev(dev);
if (add_uevent_var(env, "MODALIAS=ulpi:v%04xp%04x",
ulpi->id.vendor, ulpi->id.product))
return -ENOMEM;
return 0;
}
static int ulpi_probe(struct device *dev)
{
struct ulpi_driver *drv = to_ulpi_driver(dev->driver);
return drv->probe(to_ulpi_dev(dev));
}
static int ulpi_remove(struct device *dev)
{
struct ulpi_driver *drv = to_ulpi_driver(dev->driver);
if (drv->remove)
drv->remove(to_ulpi_dev(dev));
return 0;
}
static struct bus_type ulpi_bus = {
.name = "ulpi",
.match = ulpi_match,
.uevent = ulpi_uevent,
.probe = ulpi_probe,
.remove = ulpi_remove,
};
/* -------------------------------------------------------------------------- */
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ulpi *ulpi = to_ulpi_dev(dev);
return sprintf(buf, "ulpi:v%04xp%04x\n",
ulpi->id.vendor, ulpi->id.product);
}
static DEVICE_ATTR_RO(modalias);
static struct attribute *ulpi_dev_attrs[] = {
&dev_attr_modalias.attr,
NULL
};
static struct attribute_group ulpi_dev_attr_group = {
.attrs = ulpi_dev_attrs,
};
static const struct attribute_group *ulpi_dev_attr_groups[] = {
&ulpi_dev_attr_group,
NULL
};
static void ulpi_dev_release(struct device *dev)
{
kfree(to_ulpi_dev(dev));
}
static struct device_type ulpi_dev_type = {
.name = "ulpi_device",
.groups = ulpi_dev_attr_groups,
.release = ulpi_dev_release,
};
/* -------------------------------------------------------------------------- */
/**
* ulpi_register_driver - register a driver with the ULPI bus
* @drv: driver being registered
*
* Registers a driver with the ULPI bus.
*/
int ulpi_register_driver(struct ulpi_driver *drv)
{
if (!drv->probe)
return -EINVAL;
drv->driver.bus = &ulpi_bus;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(ulpi_register_driver);
/**
* ulpi_unregister_driver - unregister a driver with the ULPI bus
* @drv: driver to unregister
*
* Unregisters a driver with the ULPI bus.
*/
void ulpi_unregister_driver(struct ulpi_driver *drv)
{
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(ulpi_unregister_driver);
/* -------------------------------------------------------------------------- */
static int ulpi_register(struct device *dev, struct ulpi *ulpi)
{
int ret;
/* Test the interface */
ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
if (ret < 0)
return ret;
ret = ulpi_read(ulpi, ULPI_SCRATCH);
if (ret < 0)
return ret;
if (ret != 0xaa)
return -ENODEV;
ulpi->id.vendor = ulpi_read(ulpi, ULPI_VENDOR_ID_LOW);
ulpi->id.vendor |= ulpi_read(ulpi, ULPI_VENDOR_ID_HIGH) << 8;
ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW);
ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8;
ulpi->dev.parent = dev;
ulpi->dev.bus = &ulpi_bus;
ulpi->dev.type = &ulpi_dev_type;
dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev));
ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product);
ret = device_register(&ulpi->dev);
if (ret)
return ret;
dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n",
ulpi->id.vendor, ulpi->id.product);
return 0;
}
/**
* ulpi_register_interface - instantiate new ULPI device
* @dev: USB controller's device interface
* @ops: ULPI register access
*
* Allocates and registers a ULPI device and an interface for it. Called from
* the USB controller that provides the ULPI interface.
*/
struct ulpi *ulpi_register_interface(struct device *dev, struct ulpi_ops *ops)
{
struct ulpi *ulpi;
int ret;
ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
if (!ulpi)
return ERR_PTR(-ENOMEM);
ulpi->ops = ops;
ops->dev = dev;
ret = ulpi_register(dev, ulpi);
if (ret) {
kfree(ulpi);
return ERR_PTR(ret);
}
return ulpi;
}
EXPORT_SYMBOL_GPL(ulpi_register_interface);
/**
* ulpi_unregister_interface - unregister ULPI interface
* @intrf: struct ulpi_interface
*
* Unregisters a ULPI device and it's interface that was created with
* ulpi_create_interface().
*/
void ulpi_unregister_interface(struct ulpi *ulpi)
{
device_unregister(&ulpi->dev);
}
EXPORT_SYMBOL_GPL(ulpi_unregister_interface);
/* -------------------------------------------------------------------------- */
static int __init ulpi_init(void)
{
return bus_register(&ulpi_bus);
}
module_init(ulpi_init);
static void __exit ulpi_exit(void)
{
bus_unregister(&ulpi_bus);
}
module_exit(ulpi_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("USB ULPI PHY bus");
......@@ -84,3 +84,23 @@ config USB_OTG_FSM
Implements OTG Finite State Machine as specified in On-The-Go
and Embedded Host Supplement to the USB Revision 2.0 Specification.
config USB_ULPI_BUS
tristate "USB ULPI PHY interface support"
depends on USB_SUPPORT
help
UTMI+ Low Pin Interface (ULPI) is specification for a commonly used
USB 2.0 PHY interface. The ULPI specification defines a standard set
of registers that can be used to detect the vendor and product which
allows ULPI to be handled as a bus. This module is the driver for that
bus.
The ULPI interfaces (the buses) are registered by the drivers for USB
controllers which support ULPI register access and have ULPI PHY
attached to them. The ULPI PHY drivers themselves are normal PHY
drivers.
ULPI PHYs provide often functions such as ADP sensing/probing (OTG
protocol) and USB charger detection.
To compile this driver as a module, choose M here: the module will
be called ulpi.
......@@ -50,18 +50,10 @@ config USB_DWC2_DUAL_ROLE
option requires USB_GADGET to be enabled.
endchoice
config USB_DWC2_PLATFORM
tristate "DWC2 Platform"
default USB_DWC2_HOST || USB_DWC2_PERIPHERAL
help
The Designware USB2.0 platform interface module for
controllers directly connected to the CPU.
config USB_DWC2_PCI
tristate "DWC2 PCI"
depends on PCI
default n
select USB_DWC2_PLATFORM
select NOP_USB_XCEIV
help
The Designware USB2.0 PCI interface module for controllers
......
......@@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG
ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC2) += dwc2.o
dwc2-y := core.o core_intr.o
dwc2-y := core.o core_intr.o platform.o
ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
dwc2-y += hcd.o hcd_intr.o
......@@ -13,6 +13,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC2_PERIPHERAL) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
dwc2-y += gadget.o
endif
ifneq ($(CONFIG_DEBUG_FS),)
dwc2-y += debugfs.o
endif
# NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to
# this location and renamed gadget.c. When building for dynamically linked
# modules, dwc2.ko will get built for host mode, peripheral mode, and dual-role
......@@ -21,6 +25,3 @@ endif
obj-$(CONFIG_USB_DWC2_PCI) += dwc2_pci.o
dwc2_pci-y := pci.o
obj-$(CONFIG_USB_DWC2_PLATFORM) += dwc2_platform.o
dwc2_platform-y := platform.o
This diff is collapsed.
......@@ -331,6 +331,17 @@ enum dwc2_ep0_state {
* by the driver and are ignored in this
* configuration value.
* @uframe_sched: True to enable the microframe scheduler
* @external_id_pin_ctl: Specifies whether ID pin is handled externally.
* Disable CONIDSTSCHNG controller interrupt in such
* case.
* 0 - No (default)
* 1 - Yes
* @hibernation: Specifies whether the controller support hibernation.
* If hibernation is enabled, the controller will enter
* hibernation in both peripheral and host mode when
* needed.
* 0 - No (default)
* 1 - Yes
*
* The following parameters may be specified when starting the module. These
* parameters define how the DWC_otg controller should be configured. A
......@@ -368,6 +379,8 @@ struct dwc2_core_params {
int reload_ctl;
int ahbcfg;
int uframe_sched;
int external_id_pin_ctl;
int hibernation;
};
/**
......@@ -451,6 +464,82 @@ struct dwc2_hw_params {
/* Size of control and EP0 buffers */
#define DWC2_CTRL_BUFF_SIZE 8
/**
* struct dwc2_gregs_backup - Holds global registers state before entering partial
* power down
* @gotgctl: Backup of GOTGCTL register
* @gintmsk: Backup of GINTMSK register
* @gahbcfg: Backup of GAHBCFG register
* @gusbcfg: Backup of GUSBCFG register
* @grxfsiz: Backup of GRXFSIZ register
* @gnptxfsiz: Backup of GNPTXFSIZ register
* @gi2cctl: Backup of GI2CCTL register
* @hptxfsiz: Backup of HPTXFSIZ register
* @gdfifocfg: Backup of GDFIFOCFG register
* @dtxfsiz: Backup of DTXFSIZ registers for each endpoint
* @gpwrdn: Backup of GPWRDN register
*/
struct dwc2_gregs_backup {
u32 gotgctl;
u32 gintmsk;
u32 gahbcfg;
u32 gusbcfg;
u32 grxfsiz;
u32 gnptxfsiz;
u32 gi2cctl;
u32 hptxfsiz;
u32 pcgcctl;
u32 gdfifocfg;
u32 dtxfsiz[MAX_EPS_CHANNELS];
u32 gpwrdn;
};
/**
* struct dwc2_dregs_backup - Holds device registers state before entering partial
* power down
* @dcfg: Backup of DCFG register
* @dctl: Backup of DCTL register
* @daintmsk: Backup of DAINTMSK register
* @diepmsk: Backup of DIEPMSK register
* @doepmsk: Backup of DOEPMSK register
* @diepctl: Backup of DIEPCTL register
* @dieptsiz: Backup of DIEPTSIZ register
* @diepdma: Backup of DIEPDMA register
* @doepctl: Backup of DOEPCTL register
* @doeptsiz: Backup of DOEPTSIZ register
* @doepdma: Backup of DOEPDMA register
*/
struct dwc2_dregs_backup {
u32 dcfg;
u32 dctl;
u32 daintmsk;
u32 diepmsk;
u32 doepmsk;
u32 diepctl[MAX_EPS_CHANNELS];
u32 dieptsiz[MAX_EPS_CHANNELS];
u32 diepdma[MAX_EPS_CHANNELS];
u32 doepctl[MAX_EPS_CHANNELS];
u32 doeptsiz[MAX_EPS_CHANNELS];
u32 doepdma[MAX_EPS_CHANNELS];
};
/**
* struct dwc2_hregs_backup - Holds host registers state before entering partial
* power down
* @hcfg: Backup of HCFG register
* @haintmsk: Backup of HAINTMSK register
* @hcintmsk: Backup of HCINTMSK register
* @hptr0: Backup of HPTR0 register
* @hfir: Backup of HFIR register
*/
struct dwc2_hregs_backup {
u32 hcfg;
u32 haintmsk;
u32 hcintmsk[MAX_EPS_CHANNELS];
u32 hprt0;
u32 hfir;
};
/**
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
* and periodic schedules
......@@ -481,6 +570,9 @@ struct dwc2_hw_params {
* interrupt
* @wkp_timer: Timer object for handling Wakeup Detected interrupt
* @lx_state: Lx state of connected device
* @gregs_backup: Backup of global registers during suspend
* @dregs_backup: Backup of device registers during suspend
* @hregs_backup: Backup of host registers during suspend
*
* These are for host mode:
*
......@@ -613,11 +705,12 @@ struct dwc2_hsotg {
struct work_struct wf_otg;
struct timer_list wkp_timer;
enum dwc2_lx_state lx_state;
struct dwc2_gregs_backup *gr_backup;
struct dwc2_dregs_backup *dr_backup;
struct dwc2_hregs_backup *hr_backup;
struct dentry *debug_root;
struct dentry *debug_file;
struct dentry *debug_testmode;
struct dentry *debug_fifo;
struct debugfs_regset32 *regset;
/* DWC OTG HW Release versions */
#define DWC2_CORE_REV_2_71a 0x4f54271a
......@@ -751,6 +844,8 @@ enum dwc2_halt_status {
* and the DWC_otg controller
*/
extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
/*
* Host core Functions.
......@@ -983,6 +1078,15 @@ extern void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
const struct dwc2_core_params *params);
extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
/*
* Dump core registers and SPRAM
*/
......@@ -1005,6 +1109,8 @@ extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset);
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
extern int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
#define dwc2_is_device_connected(hsotg) (hsotg->connected)
#else
static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
{ return 0; }
......@@ -1018,6 +1124,10 @@ static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset) {}
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
static inline int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
int testmode)
{ return 0; }
#define dwc2_is_device_connected(hsotg) (0)
#endif
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
......@@ -1025,14 +1135,12 @@ extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
#else
static inline void dwc2_set_all_params(struct dwc2_core_params *params, int value) {}
static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
const struct dwc2_core_params *params)
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
{ return 0; }
#endif
......
......@@ -334,6 +334,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
*/
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
{
int ret;
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
......@@ -345,6 +346,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
/* Clear Remote Wakeup Signaling */
dctl &= ~DCTL_RMTWKUPSIG;
writel(dctl, hsotg->regs + DCTL);
ret = dwc2_exit_hibernation(hsotg, true);
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev, "exit hibernation failed\n");
call_gadget(hsotg, resume);
}
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
......@@ -397,6 +403,7 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
{
u32 dsts;
int ret;
dev_dbg(hsotg->dev, "USB SUSPEND\n");
......@@ -411,10 +418,43 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
!!(dsts & DSTS_SUSPSTS),
hsotg->hw_params.power_optimized);
if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
/* Ignore suspend request before enumeration */
if (!dwc2_is_device_connected(hsotg)) {
dev_dbg(hsotg->dev,
"ignore suspend request before enumeration\n");
goto clear_int;
}
ret = dwc2_enter_hibernation(hsotg);
if (ret) {
if (ret != -ENOTSUPP)
dev_err(hsotg->dev,
"enter hibernation failed\n");
goto skip_power_saving;
}
udelay(100);
/* Ask phy to be suspended */
if (!IS_ERR_OR_NULL(hsotg->uphy))
usb_phy_set_suspend(hsotg->uphy, true);
skip_power_saving:
/*
* Change to L2 (suspend) state before releasing
* spinlock
*/
hsotg->lx_state = DWC2_L2;
/* Call gadget suspend callback */
call_gadget(hsotg, suspend);
}
} else {
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
/* Clear the a_peripheral flag, back to a_host */
spin_unlock(&hsotg->lock);
dwc2_hcd_start(hsotg);
......@@ -423,9 +463,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
}
}
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
clear_int:
/* Clear interrupt */
writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
}
......@@ -522,4 +560,3 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
spin_unlock(&hsotg->lock);
return retval;
}
EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
/**
* debug.h - Designware USB2 DRD controller debug header
*
* Copyright (C) 2015 Intel Corporation
* Mian Yousaf Kaukab <yousaf.kaukab@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.
*/
#include "core.h"
#ifdef CONFIG_DEBUG_FS
extern int dwc2_debugfs_init(struct dwc2_hsotg *);
extern void dwc2_debugfs_exit(struct dwc2_hsotg *);
#else
static inline int dwc2_debugfs_init(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_debugfs_exit(struct dwc2_hsotg *hsotg)
{ }
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -357,12 +357,12 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
writel(0, hsotg->regs + HPRT0);
}
/* Caller must hold driver lock */
static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
struct dwc2_hcd_urb *urb, void **ep_handle,
gfp_t mem_flags)
{
struct dwc2_qtd *qtd;
unsigned long flags;
u32 intr_mask;
int retval;
int dev_speed;
......@@ -413,11 +413,9 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
*/
return 0;
spin_lock_irqsave(&hsotg->lock, flags);
tr_type = dwc2_hcd_select_transactions(hsotg);
if (tr_type != DWC2_TRANSACTION_NONE)
dwc2_hcd_queue_transactions(hsotg, tr_type);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
return 0;
......@@ -721,9 +719,7 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
/* 3072 = 3 max-size Isoc packets */
buf_size = 3072;
qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size,
&qh->dw_align_buf_dma,
GFP_ATOMIC);
qh->dw_align_buf = kmalloc(buf_size, GFP_ATOMIC | GFP_DMA);
if (!qh->dw_align_buf)
return -ENOMEM;
qh->dw_align_buf_size = buf_size;
......@@ -748,6 +744,15 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
}
}
qh->dw_align_buf_dma = dma_map_single(hsotg->dev,
qh->dw_align_buf, qh->dw_align_buf_size,
chan->ep_is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (dma_mapping_error(hsotg->dev, qh->dw_align_buf_dma)) {
dev_err(hsotg->dev, "can't map align_buf\n");
chan->align_buf = 0;
return -EINVAL;
}
chan->align_buf = qh->dw_align_buf_dma;
return 0;
}
......@@ -1774,6 +1779,15 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
/* Not supported */
break;
case USB_PORT_FEAT_TEST:
hprt0 = dwc2_read_hprt0(hsotg);
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_TEST\n");
hprt0 &= ~HPRT0_TSTCTL_MASK;
hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT;
writel(hprt0, hsotg->regs + HPRT0);
break;
default:
retval = -EINVAL;
dev_err(hsotg->dev,
......@@ -2313,6 +2327,22 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
usleep_range(1000, 3000);
}
static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
hsotg->lx_state = DWC2_L2;
return 0;
}
static int _dwc2_hcd_resume(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
hsotg->lx_state = DWC2_L0;
return 0;
}
/* Returns the current frame number */
static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
{
......@@ -2468,7 +2498,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
"%s: unaligned transfer with no transfer_buffer",
__func__);
retval = -EINVAL;
goto fail1;
goto fail0;
}
}
......@@ -2496,7 +2526,6 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
spin_lock_irqsave(&hsotg->lock, flags);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
spin_unlock_irqrestore(&hsotg->lock, flags);
if (retval)
goto fail1;
......@@ -2505,22 +2534,22 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
goto fail2;
if (alloc_bandwidth) {
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_allocate_bus_bandwidth(hcd,
dwc2_hcd_get_ep_bandwidth(hsotg, ep),
urb);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
fail2:
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_urb->priv = NULL;
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&hsotg->lock, flags);
fail1:
spin_unlock_irqrestore(&hsotg->lock, flags);
urb->hcpriv = NULL;
fail0:
kfree(dwc2_urb);
return retval;
......@@ -2683,6 +2712,9 @@ static struct hc_driver dwc2_hc_driver = {
.hub_status_data = _dwc2_hcd_hub_status_data,
.hub_control = _dwc2_hcd_hub_control,
.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
.bus_suspend = _dwc2_hcd_suspend,
.bus_resume = _dwc2_hcd_resume,
};
/*
......@@ -2748,8 +2780,6 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
destroy_workqueue(hsotg->wq_otg);
}
kfree(hsotg->core_params);
hsotg->core_params = NULL;
del_timer(&hsotg->wkp_timer);
}
......@@ -2761,30 +2791,13 @@ static void dwc2_hcd_release(struct dwc2_hsotg *hsotg)
dwc2_hcd_free(hsotg);
}
/*
* Sets all parameters to the given value.
*
* Assumes that the dwc2_core_params struct contains only integers.
*/
void dwc2_set_all_params(struct dwc2_core_params *params, int value)
{
int *p = (int *)params;
size_t size = sizeof(*params) / sizeof(*p);
int i;
for (i = 0; i < size; i++)
p[i] = value;
}
EXPORT_SYMBOL_GPL(dwc2_set_all_params);
/*
* Initializes the HCD. This function allocates memory for and initializes the
* static parts of the usb_hcd and dwc2_hsotg structures. It also registers the
* USB bus with the core and calls the hc_driver->start() function. It returns
* a negative error on failure.
*/
int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
const struct dwc2_core_params *params)
int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
{
struct usb_hcd *hcd;
struct dwc2_host_chan *channel;
......@@ -2797,12 +2810,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
/* Detect config values from hardware */
retval = dwc2_get_hwparams(hsotg);
if (retval)
return retval;
retval = -ENOMEM;
hcfg = readl(hsotg->regs + HCFG);
......@@ -2821,15 +2828,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
hsotg->last_frame_num = HFNUM_MAX_FRNUM;
#endif
hsotg->core_params = kzalloc(sizeof(*hsotg->core_params), GFP_KERNEL);
if (!hsotg->core_params)
goto error1;
dwc2_set_all_params(hsotg->core_params, -1);
/* Validate parameter values */
dwc2_set_parameters(hsotg, params);
/* Check if the bus driver or platform code has setup a dma_mask */
if (hsotg->core_params->dma_enable > 0 &&
hsotg->dev->dma_mask == NULL) {
......@@ -2947,6 +2945,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
/* Don't support SG list at this point */
hcd->self.sg_tablesize = 0;
if (!IS_ERR_OR_NULL(hsotg->uphy))
otg_set_host(hsotg->uphy->otg, &hcd->self);
/*
* Finish generic HCD initialization and start the HCD. This function
* allocates the DMA buffer pool, registers the USB bus, requests the
......@@ -2979,7 +2980,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval);
return retval;
}
EXPORT_SYMBOL_GPL(dwc2_hcd_init);
/*
* Removes the HCD.
......@@ -3000,6 +3000,9 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
return;
}
if (!IS_ERR_OR_NULL(hsotg->uphy))
otg_set_host(hsotg->uphy->otg, NULL);
usb_remove_hcd(hcd);
hsotg->priv = NULL;
dwc2_hcd_release(hsotg);
......@@ -3010,4 +3013,3 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
kfree(hsotg->frame_num_array);
#endif
}
EXPORT_SYMBOL_GPL(dwc2_hcd_remove);
......@@ -451,13 +451,8 @@ static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
return !dwc2_hcd_is_pipe_in(pipe);
}
extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
const struct dwc2_core_params *params);
extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq);
extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
const struct dwc2_core_params *params);
extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
/* Transaction Execution Functions */
extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
......
......@@ -350,6 +350,9 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev,
"--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
hprt0);
if (hsotg->lx_state != DWC2_L0)
usb_hcd_resume_root_hub(hsotg->priv);
hsotg->flags.b.port_connect_status_change = 1;
hsotg->flags.b.port_connect_status = 1;
hprt0_modify |= HPRT0_CONNDET;
......@@ -463,10 +466,15 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
}
/* Non DWORD-aligned buffer case handling */
if (chan->align_buf && xfer_length && chan->ep_is_in) {
if (chan->align_buf && xfer_length) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
xfer_length);
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
chan->qh->dw_align_buf_size,
chan->ep_is_in ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (chan->ep_is_in)
memcpy(urb->buf + urb->actual_length,
chan->qh->dw_align_buf, xfer_length);
}
dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
......@@ -552,13 +560,18 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
chan, chnum, qtd, halt_status, NULL);
/* Non DWORD-aligned buffer case handling */
if (chan->align_buf && frame_desc->actual_length &&
chan->ep_is_in) {
if (chan->align_buf && frame_desc->actual_length) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
__func__);
memcpy(urb->buf + frame_desc->offset +
qtd->isoc_split_offset, chan->qh->dw_align_buf,
frame_desc->actual_length);
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
chan->qh->dw_align_buf_size,
chan->ep_is_in ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (chan->ep_is_in)
memcpy(urb->buf + frame_desc->offset +
qtd->isoc_split_offset,
chan->qh->dw_align_buf,
frame_desc->actual_length);
}
break;
case DWC2_HC_XFER_FRAME_OVERRUN:
......@@ -581,13 +594,18 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state(
chan, chnum, qtd, halt_status, NULL);
/* Non DWORD-aligned buffer case handling */
if (chan->align_buf && frame_desc->actual_length &&
chan->ep_is_in) {
if (chan->align_buf && frame_desc->actual_length) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
__func__);
memcpy(urb->buf + frame_desc->offset +
qtd->isoc_split_offset, chan->qh->dw_align_buf,
frame_desc->actual_length);
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
chan->qh->dw_align_buf_size,
chan->ep_is_in ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (chan->ep_is_in)
memcpy(urb->buf + frame_desc->offset +
qtd->isoc_split_offset,
chan->qh->dw_align_buf,
frame_desc->actual_length);
}
/* Skip whole frame */
......@@ -923,6 +941,8 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
if (chan->align_buf) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
chan->qh->dw_align_buf_size, DMA_FROM_DEVICE);
memcpy(qtd->urb->buf + frame_desc->offset +
qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
}
......@@ -1152,8 +1172,14 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
/* Non DWORD-aligned buffer case handling */
if (chan->align_buf && xfer_length && chan->ep_is_in) {
dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
xfer_length);
dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma,
chan->qh->dw_align_buf_size,
chan->ep_is_in ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (chan->ep_is_in)
memcpy(urb->buf + urb->actual_length,
chan->qh->dw_align_buf,
xfer_length);
}
urb->actual_length += xfer_length;
......@@ -1182,6 +1208,16 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
struct dwc2_host_chan *chan, int chnum,
struct dwc2_qtd *qtd)
{
if (!qtd) {
dev_dbg(hsotg->dev, "%s: qtd is NULL\n", __func__);
return;
}
if (!qtd->urb) {
dev_dbg(hsotg->dev, "%s: qtd->urb is NULL\n", __func__);
return;
}
if (dbg_hc(chan))
dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n",
chnum);
......
......@@ -229,11 +229,13 @@ static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
*/
void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
if (hsotg->core_params->dma_desc_enable > 0)
if (hsotg->core_params->dma_desc_enable > 0) {
dwc2_hcd_qh_free_ddma(hsotg, qh);
else if (qh->dw_align_buf)
dma_free_coherent(hsotg->dev, qh->dw_align_buf_size,
qh->dw_align_buf, qh->dw_align_buf_dma);
} else {
/* kfree(NULL) is safe */
kfree(qh->dw_align_buf);
qh->dw_align_buf_dma = (dma_addr_t)0;
}
kfree(qh);
}
......@@ -761,6 +763,7 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
/**
* dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
* Caller must hold driver lock.
*
* @hsotg: The DWC HCD structure
* @qtd: The QTD to add
......@@ -777,7 +780,6 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
struct dwc2_qh **qh, gfp_t mem_flags)
{
struct dwc2_hcd_urb *urb = qtd->urb;
unsigned long flags;
int allocated = 0;
int retval;
......@@ -792,15 +794,12 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
allocated = 1;
}
spin_lock_irqsave(&hsotg->lock, flags);
retval = dwc2_hcd_qh_add(hsotg, *qh);
if (retval)
goto fail;
qtd->qh = *qh;
list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
......@@ -817,10 +816,7 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
qtd_list_entry)
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hcd_qh_free(hsotg, qh_tmp);
} else {
spin_unlock_irqrestore(&hsotg->lock, flags);
}
return retval;
......
......@@ -47,6 +47,7 @@
#include "core.h"
#include "hcd.h"
#include "debug.h"
static const char dwc2_driver_name[] = "dwc2";
......@@ -76,6 +77,8 @@ static const struct dwc2_core_params params_bcm2835 = {
.reload_ctl = 0,
.ahbcfg = 0x10,
.uframe_sched = 0,
.external_id_pin_ctl = -1,
.hibernation = -1,
};
static const struct dwc2_core_params params_rk3066 = {
......@@ -104,6 +107,8 @@ static const struct dwc2_core_params params_rk3066 = {
.reload_ctl = -1,
.ahbcfg = 0x7, /* INCR16 */
.uframe_sched = -1,
.external_id_pin_ctl = -1,
.hibernation = -1,
};
/**
......@@ -121,6 +126,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
{
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
dwc2_debugfs_exit(hsotg);
if (hsotg->hcd_enabled)
dwc2_hcd_remove(hsotg);
if (hsotg->gadget_enabled)
......@@ -237,6 +243,21 @@ static int dwc2_driver_probe(struct platform_device *dev)
spin_lock_init(&hsotg->lock);
mutex_init(&hsotg->init_mutex);
/* Detect config values from hardware */
retval = dwc2_get_hwparams(hsotg);
if (retval)
return retval;
hsotg->core_params = devm_kzalloc(&dev->dev,
sizeof(*hsotg->core_params), GFP_KERNEL);
if (!hsotg->core_params)
return -ENOMEM;
dwc2_set_all_params(hsotg->core_params, -1);
/* Validate parameter values */
dwc2_set_parameters(hsotg, params);
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
retval = dwc2_gadget_init(hsotg, irq);
if (retval)
......@@ -245,7 +266,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
}
if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
retval = dwc2_hcd_init(hsotg, irq, params);
retval = dwc2_hcd_init(hsotg, irq);
if (retval) {
if (hsotg->gadget_enabled)
s3c_hsotg_remove(hsotg);
......@@ -256,6 +277,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
platform_set_drvdata(dev, hsotg);
dwc2_debugfs_init(hsotg);
return retval;
}
......
......@@ -11,6 +11,13 @@ config USB_DWC3
if USB_DWC3
config USB_DWC3_ULPI
bool "Register ULPI PHY Interface"
depends on USB_ULPI_BUS=y || USB_ULPI_BUS=USB_DWC3
help
Select this if you have ULPI type PHY attached to your DWC3
controller.
choice
bool "DWC3 Mode Selection"
default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET)
......
......@@ -15,6 +15,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
dwc3-y += gadget.o ep0.o
endif
ifneq ($(CONFIG_USB_DWC3_ULPI),)
dwc3-y += ulpi.o
endif
ifneq ($(CONFIG_DEBUG_FS),)
dwc3-y += debugfs.o
endif
......
......@@ -116,6 +116,33 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
return 0;
}
/**
* dwc3_soft_reset - Issue soft reset
* @dwc: Pointer to our controller context structure
*/
static int dwc3_soft_reset(struct dwc3 *dwc)
{
unsigned long timeout;
u32 reg;
timeout = jiffies + msecs_to_jiffies(500);
dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
do {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (!(reg & DWC3_DCTL_CSFTRST))
break;
if (time_after(jiffies, timeout)) {
dev_err(dwc->dev, "Reset Timed Out\n");
return -ETIMEDOUT;
}
cpu_relax();
} while (true);
return 0;
}
/**
* dwc3_free_one_event_buffer - Frees one event buffer
* @dwc: Pointer to our controller context structure
......@@ -367,10 +394,15 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
*
* Returns 0 on success. The USB PHY interfaces are configured but not
* initialized. The PHY interfaces and the PHYs get initialized together with
* the core in dwc3_core_init.
*/
static void dwc3_phy_setup(struct dwc3 *dwc)
static int dwc3_phy_setup(struct dwc3 *dwc)
{
u32 reg;
int ret;
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
......@@ -409,10 +441,41 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
mdelay(100);
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
/* Select the HS PHY interface */
switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
case DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI:
if (!strncmp(dwc->hsphy_interface, "utmi", 4)) {
reg &= ~DWC3_GUSB2PHYCFG_ULPI_UTMI;
break;
} else if (!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
} else {
dev_warn(dwc->dev, "HSPHY Interface not defined\n");
/* Relying on default value. */
if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
break;
}
/* FALLTHROUGH */
case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
/* Making sure the interface and PHY are operational */
ret = dwc3_soft_reset(dwc);
if (ret)
return ret;
udelay(1);
ret = dwc3_ulpi_init(dwc);
if (ret)
return ret;
/* FALLTHROUGH */
default:
break;
}
/*
* Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
* '0' during coreConsultant configuration. So default value will
......@@ -427,7 +490,7 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
mdelay(100);
return 0;
}
/**
......@@ -438,7 +501,6 @@ static void dwc3_phy_setup(struct dwc3 *dwc)
*/
static int dwc3_core_init(struct dwc3 *dwc)
{
unsigned long timeout;
u32 hwparams4 = dwc->hwparams.hwparams4;
u32 reg;
int ret;
......@@ -466,21 +528,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
}
/* issue device SoftReset too */
timeout = jiffies + msecs_to_jiffies(500);
dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
do {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (!(reg & DWC3_DCTL_CSFTRST))
break;
if (time_after(jiffies, timeout)) {
dev_err(dwc->dev, "Reset Timed Out\n");
ret = -ETIMEDOUT;
goto err0;
}
cpu_relax();
} while (true);
ret = dwc3_soft_reset(dwc);
if (ret)
goto err0;
ret = dwc3_core_soft_reset(dwc);
if (ret)
......@@ -555,8 +605,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc3_phy_setup(dwc);
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err1;
......@@ -836,6 +884,8 @@ static int dwc3_probe(struct platform_device *pdev)
"snps,tx_de_emphasis_quirk");
of_property_read_u8(node, "snps,tx_de_emphasis",
&tx_de_emphasis);
of_property_read_string(node, "snps,hsphy_interface",
&dwc->hsphy_interface);
} else if (pdata) {
dwc->maximum_speed = pdata->maximum_speed;
dwc->has_lpm_erratum = pdata->has_lpm_erratum;
......@@ -863,6 +913,8 @@ static int dwc3_probe(struct platform_device *pdev)
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;
}
/* default to superspeed if no maximum_speed passed */
......@@ -875,12 +927,18 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->hird_threshold = hird_threshold
| (dwc->is_utmi_l1_suspend << 4);
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;
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
if (!dev->dma_mask) {
dev->dma_mask = dev->parent->dma_mask;
......@@ -892,8 +950,6 @@ static int dwc3_probe(struct platform_device *pdev)
pm_runtime_get_sync(dev);
pm_runtime_forbid(dev);
dwc3_cache_hwparams(dwc);
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
......@@ -964,6 +1020,7 @@ static int dwc3_probe(struct platform_device *pdev)
err1:
dwc3_free_event_buffers(dwc);
dwc3_ulpi_exit(dwc);
err0:
/*
......@@ -999,6 +1056,7 @@ static int dwc3_remove(struct platform_device *pdev)
phy_power_off(dwc->usb3_generic_phy);
dwc3_core_exit(dwc);
dwc3_ulpi_exit(dwc);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
......
......@@ -30,6 +30,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/ulpi/interface.h>
#include <linux/phy/phy.h>
......@@ -173,6 +174,15 @@
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
#define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4)
/* Global USB2 PHY Vendor Control Register */
#define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25)
#define DWC3_GUSB2PHYACC_BUSY (1 << 23)
#define DWC3_GUSB2PHYACC_WRITE (1 << 22)
#define DWC3_GUSB2PHYACC_ADDR(n) (n << 16)
#define DWC3_GUSB2PHYACC_EXTEND_ADDR(n) (n << 8)
#define DWC3_GUSB2PHYACC_DATA(n) (n & 0xff)
/* Global USB3 PIPE Control Register */
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
......@@ -652,6 +662,7 @@ struct dwc3_scratchpad_array {
* @usb3_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to USB2 PHY
* @usb3_generic_phy: pointer to USB3 PHY
* @ulpi: pointer to ulpi interface
* @dcfg: saved contents of DCFG register
* @gctl: saved contents of GCTL register
* @isoch_delay: wValue from Set Isochronous Delay request;
......@@ -673,6 +684,7 @@ struct dwc3_scratchpad_array {
* @test_mode_nr: test feature selector
* @lpm_nyet_threshold: LPM NYET response threshold
* @hird_threshold: HIRD threshold
* @hsphy_interface: "utmi" or "ulpi"
* @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
......@@ -739,6 +751,8 @@ struct dwc3 {
struct phy *usb2_generic_phy;
struct phy *usb3_generic_phy;
struct ulpi *ulpi;
void __iomem *regs;
size_t regs_size;
......@@ -800,6 +814,8 @@ struct dwc3 {
u8 lpm_nyet_threshold;
u8 hird_threshold;
const char *hsphy_interface;
unsigned delayed_status:1;
unsigned ep0_bounced:1;
unsigned ep0_expect_in:1;
......@@ -1035,4 +1051,14 @@ static inline int dwc3_gadget_resume(struct dwc3 *dwc)
}
#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
#if IS_ENABLED(CONFIG_USB_DWC3_ULPI)
int dwc3_ulpi_init(struct dwc3 *dwc);
void dwc3_ulpi_exit(struct dwc3 *dwc);
#else
static inline int dwc3_ulpi_init(struct dwc3 *dwc)
{ return 0; }
static inline void dwc3_ulpi_exit(struct dwc3 *dwc)
{ }
#endif
#endif /* __DRIVERS_USB_DWC3_CORE_H */
......@@ -21,6 +21,8 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
#include "platform_data.h"
......@@ -31,6 +33,15 @@
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
{ "reset-gpios", &reset_gpios, 1 },
{ "cs-gpios", &cs_gpios, 1 },
{ },
};
static int dwc3_pci_quirks(struct pci_dev *pdev)
{
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
......@@ -65,6 +76,30 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
sizeof(pdata));
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
struct gpio_desc *gpio;
acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
acpi_dwc3_byt_gpios);
/* These GPIOs will turn on the USB2 PHY */
gpio = gpiod_get(&pdev->dev, "cs");
if (!IS_ERR(gpio)) {
gpiod_direction_output(gpio, 0);
gpiod_set_value_cansleep(gpio, 1);
gpiod_put(gpio);
}
gpio = gpiod_get(&pdev->dev, "reset");
if (!IS_ERR(gpio)) {
gpiod_direction_output(gpio, 0);
gpiod_set_value_cansleep(gpio, 1);
gpiod_put(gpio);
usleep_range(10000, 11000);
}
}
return 0;
}
......@@ -128,6 +163,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,
static void dwc3_pci_remove(struct pci_dev *pci)
{
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pci->dev));
platform_device_unregister(pci_get_drvdata(pci));
}
......
......@@ -291,6 +291,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
dwc3_trace(trace_dwc3_gadget,
"Command Complete --> %d",
DWC3_DGCMD_STATUS(reg));
if (DWC3_DGCMD_STATUS(reg))
return -EINVAL;
return 0;
}
......@@ -328,6 +330,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
dwc3_trace(trace_dwc3_gadget,
"Command Complete --> %d",
DWC3_DEPCMD_STATUS(reg));
if (DWC3_DEPCMD_STATUS(reg))
return -EINVAL;
return 0;
}
......@@ -1902,12 +1906,16 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
{
unsigned status = 0;
int clean_busy;
u32 is_xfer_complete;
is_xfer_complete = (event->endpoint_event == DWC3_DEPEVT_XFERCOMPLETE);
if (event->status & DEPEVT_STATUS_BUSERR)
status = -ECONNRESET;
clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
if (clean_busy)
if (clean_busy && (is_xfer_complete ||
usb_endpoint_xfer_isoc(dep->endpoint.desc)))
dep->flags &= ~DWC3_EP_BUSY;
/*
......
......@@ -45,4 +45,6 @@ struct dwc3_platform_data {
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
const char *hsphy_interface;
};
/**
* ulpi.c - DesignWare USB3 Controller's ULPI PHY interface
*
* Copyright (C) 2015 Intel Corporation
*
* Author: Heikki Krogerus <heikki.krogerus@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 as
* published by the Free Software Foundation.
*/
#include <linux/ulpi/regs.h>
#include "core.h"
#include "io.h"
#define DWC3_ULPI_ADDR(a) \
((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a))
static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
{
unsigned count = 1000;
u32 reg;
while (count--) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
if (!(reg & DWC3_GUSB2PHYACC_BUSY))
return 0;
cpu_relax();
}
return -ETIMEDOUT;
}
static int dwc3_ulpi_read(struct ulpi_ops *ops, u8 addr)
{
struct dwc3 *dwc = dev_get_drvdata(ops->dev);
u32 reg;
int ret;
reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
ret = dwc3_ulpi_busyloop(dwc);
if (ret)
return ret;
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
return DWC3_GUSB2PHYACC_DATA(reg);
}
static int dwc3_ulpi_write(struct ulpi_ops *ops, u8 addr, u8 val)
{
struct dwc3 *dwc = dev_get_drvdata(ops->dev);
u32 reg;
reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
reg |= DWC3_GUSB2PHYACC_WRITE | val;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
return dwc3_ulpi_busyloop(dwc);
}
static struct ulpi_ops dwc3_ulpi_ops = {
.read = dwc3_ulpi_read,
.write = dwc3_ulpi_write,
};
int dwc3_ulpi_init(struct dwc3 *dwc)
{
/* Register the interface */
dwc->ulpi = ulpi_register_interface(dwc->dev, &dwc3_ulpi_ops);
if (IS_ERR(dwc->ulpi)) {
dev_err(dwc->dev, "failed to register ULPI interface");
return PTR_ERR(dwc->ulpi);
}
return 0;
}
void dwc3_ulpi_exit(struct dwc3 *dwc)
{
if (dwc->ulpi) {
ulpi_unregister_interface(dwc->ulpi);
dwc->ulpi = NULL;
}
}
......@@ -258,15 +258,25 @@ struct usb_ep *usb_ep_autoconfig_ss(
/* First, apply chip-specific "best usage" knowledge.
* This might make a good usb_gadget_ops hook ...
*/
if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
/* ep-e, ep-f are PIO with only 64 byte fifos */
ep = find_ep (gadget, "ep-e");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
goto found_ep;
ep = find_ep (gadget, "ep-f");
if (gadget_is_net2280(gadget)) {
char name[8];
if (type == USB_ENDPOINT_XFER_INT) {
/* ep-e, ep-f are PIO with only 64 byte fifos */
ep = find_ep(gadget, "ep-e");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
goto found_ep;
ep = find_ep(gadget, "ep-f");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
goto found_ep;
}
/* USB3380: use same address for usb and hardware endpoints */
snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc),
usb_endpoint_dir_in(desc) ? "in" : "out");
ep = find_ep(gadget, name);
if (ep && ep_matches(gadget, ep, desc, ep_comp))
goto found_ep;
} else if (gadget_is_goku (gadget)) {
if (USB_ENDPOINT_XFER_INT == type) {
/* single buffering is enough */
......
......@@ -3433,6 +3433,7 @@ static int ffs_ready(struct ffs_data *ffs)
static void ffs_closed(struct ffs_data *ffs)
{
struct ffs_dev *ffs_obj;
struct f_fs_opts *opts;
ENTER();
ffs_dev_lock();
......@@ -3446,8 +3447,13 @@ static void ffs_closed(struct ffs_data *ffs)
if (ffs_obj->ffs_closed_callback)
ffs_obj->ffs_closed_callback(ffs);
if (!ffs_obj->opts || ffs_obj->opts->no_configfs
|| !ffs_obj->opts->func_inst.group.cg_item.ci_parent)
if (ffs_obj->opts)
opts = ffs_obj->opts;
else
goto done;
if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent
|| !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount))
goto done;
unregister_gadget_item(ffs_obj->opts->
......
......@@ -76,7 +76,7 @@ struct f_rndis {
u8 ethaddr[ETH_ALEN];
u32 vendorID;
const char *manufacturer;
int config;
struct rndis_params *params;
struct usb_ep *notify;
struct usb_request *notify_req;
......@@ -453,7 +453,7 @@ static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
// spin_lock(&dev->lock);
status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
status = rndis_msg_parser(rndis->params, (u8 *) req->buf);
if (status < 0)
pr_err("RNDIS command error %d, %d/%d\n",
status, req->actual, req->length);
......@@ -499,12 +499,12 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
u32 n;
/* return the result */
buf = rndis_get_next_response(rndis->config, &n);
buf = rndis_get_next_response(rndis->params, &n);
if (buf) {
memcpy(req->buf, buf, n);
req->complete = rndis_response_complete;
req->context = rndis;
rndis_free_response(rndis->config, buf);
rndis_free_response(rndis->params, buf);
value = n;
}
/* else stalls ... spec says to avoid that */
......@@ -597,7 +597,7 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (IS_ERR(net))
return PTR_ERR(net);
rndis_set_param_dev(rndis->config, net,
rndis_set_param_dev(rndis->params, net,
&rndis->port.cdc_filter);
} else
goto fail;
......@@ -617,7 +617,7 @@ static void rndis_disable(struct usb_function *f)
DBG(cdev, "rndis deactivated\n");
rndis_uninit(rndis->config);
rndis_uninit(rndis->params);
gether_disconnect(&rndis->port);
usb_ep_disable(rndis->notify);
......@@ -640,9 +640,9 @@ static void rndis_open(struct gether *geth)
DBG(cdev, "%s\n", __func__);
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3,
rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3,
bitrate(cdev->gadget) / 100);
rndis_signal_connect(rndis->config);
rndis_signal_connect(rndis->params);
}
static void rndis_close(struct gether *geth)
......@@ -651,8 +651,8 @@ static void rndis_close(struct gether *geth)
DBG(geth->func.config->cdev, "%s\n", __func__);
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
rndis_signal_disconnect(rndis->config);
rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0);
rndis_signal_disconnect(rndis->params);
}
/*-------------------------------------------------------------------------*/
......@@ -796,11 +796,11 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
rndis->port.open = rndis_open;
rndis->port.close = rndis_close;
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
rndis_set_host_mac(rndis->config, rndis->ethaddr);
rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0);
rndis_set_host_mac(rndis->params, rndis->ethaddr);
if (rndis->manufacturer && rndis->vendorID &&
rndis_set_param_vendor(rndis->config, rndis->vendorID,
rndis_set_param_vendor(rndis->params, rndis->vendorID,
rndis->manufacturer)) {
status = -EINVAL;
goto fail_free_descs;
......@@ -944,7 +944,7 @@ static void rndis_free(struct usb_function *f)
struct f_rndis_opts *opts;
rndis = func_to_rndis(f);
rndis_deregister(rndis->config);
rndis_deregister(rndis->params);
opts = container_of(f->fi, struct f_rndis_opts, func_inst);
kfree(rndis);
mutex_lock(&opts->lock);
......@@ -968,7 +968,7 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
{
struct f_rndis *rndis;
struct f_rndis_opts *opts;
int status;
struct rndis_params *params;
/* allocate and initialize one new instance */
rndis = kzalloc(sizeof(*rndis), GFP_KERNEL);
......@@ -1002,36 +1002,16 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)
rndis->port.func.disable = rndis_disable;
rndis->port.func.free_func = rndis_free;
status = rndis_register(rndis_response_available, rndis);
if (status < 0) {
params = rndis_register(rndis_response_available, rndis);
if (IS_ERR(params)) {
kfree(rndis);
return ERR_PTR(status);
return ERR_CAST(params);
}
rndis->config = status;
rndis->params = params;
return &rndis->port.func;
}
DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc);
static int __init rndis_mod_init(void)
{
int ret;
ret = rndis_init();
if (ret)
return ret;
return usb_function_register(&rndisusb_func);
}
module_init(rndis_mod_init);
static void __exit rndis_mod_exit(void)
{
usb_function_unregister(&rndisusb_func);
rndis_exit();
}
module_exit(rndis_mod_exit);
DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Brownell");
This diff is collapsed.
......@@ -177,7 +177,7 @@ typedef struct rndis_resp_t
typedef struct rndis_params
{
u8 confignr;
int confignr;
u8 used;
u16 saved_filter;
enum rndis_state state;
......@@ -197,24 +197,25 @@ typedef struct rndis_params
} rndis_params;
/* RNDIS Message parser and other useless functions */
int rndis_msg_parser (u8 configNr, u8 *buf);
int rndis_register(void (*resp_avail)(void *v), void *v);
void rndis_deregister (int configNr);
int rndis_set_param_dev (u8 configNr, struct net_device *dev,
int rndis_msg_parser(struct rndis_params *params, u8 *buf);
struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v);
void rndis_deregister(struct rndis_params *params);
int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
u16 *cdc_filter);
int rndis_set_param_vendor (u8 configNr, u32 vendorID,
int rndis_set_param_vendor(struct rndis_params *params, u32 vendorID,
const char *vendorDescr);
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
void rndis_add_hdr (struct sk_buff *skb);
int rndis_set_param_medium(struct rndis_params *params, u32 medium,
u32 speed);
void rndis_add_hdr(struct sk_buff *skb);
int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
struct sk_buff_head *list);
u8 *rndis_get_next_response (int configNr, u32 *length);
void rndis_free_response (int configNr, u8 *buf);
void rndis_uninit (int configNr);
int rndis_signal_connect (int configNr);
int rndis_signal_disconnect (int configNr);
int rndis_state (int configNr);
extern void rndis_set_host_mac (int configNr, const u8 *addr);
u8 *rndis_get_next_response(struct rndis_params *params, u32 *length);
void rndis_free_response(struct rndis_params *params, u8 *buf);
void rndis_uninit(struct rndis_params *params);
int rndis_signal_connect(struct rndis_params *params);
int rndis_signal_disconnect(struct rndis_params *params);
int rndis_state(struct rndis_params *params);
extern void rndis_set_host_mac(struct rndis_params *params, const u8 *addr);
#endif /* _LINUX_RNDIS_H */
......@@ -39,8 +39,6 @@ struct f_rndis_opts {
int refcnt;
};
int rndis_init(void);
void rndis_exit(void);
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
#endif /* U_RNDIS_H */
......@@ -56,7 +56,6 @@ struct uvc_event
#include <linux/usb/composite.h>
#include <linux/usb/gadget.h>
#include <linux/videodev2.h>
#include <linux/version.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-device.h>
......
......@@ -704,8 +704,8 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
unsigned long flags;
int ret;
DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
ep->ep.name, req->req.length, req->req.dma,
DBG(DBG_DMA, "%s: req l/%u d/%pad %c%c%c\n",
ep->ep.name, req->req.length, &req->req.dma,
req->req.zero ? 'Z' : 'z',
req->req.short_not_ok ? 'S' : 's',
req->req.no_interrupt ? 'I' : 'i');
......@@ -2203,7 +2203,7 @@ static int usba_udc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int usba_udc_suspend(struct device *dev)
{
struct usba_udc *udc = dev_get_drvdata(dev);
......
This diff is collapsed.
......@@ -92,40 +92,38 @@ static struct s3c2410_udc_mach_info *udc_info;
static uint32_t s3c2410_ticks = 0;
static int dprintk(int level, const char *fmt, ...)
__printf(2, 3)
static void dprintk(int level, const char *fmt, ...)
{
static char printk_buf[1024];
static long prevticks;
static int invocation;
struct va_format vaf;
va_list args;
int len;
if (level > USB_S3C2410_DEBUG_LEVEL)
return 0;
return;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
if (s3c2410_ticks != prevticks) {
prevticks = s3c2410_ticks;
invocation = 0;
}
len = scnprintf(printk_buf,
sizeof(printk_buf), "%1lu.%02d USB: ",
prevticks, invocation++);
pr_debug("%1lu.%02d USB: %pV", prevticks, invocation++, &vaf);
va_start(args, fmt);
len = vscnprintf(printk_buf+len,
sizeof(printk_buf)-len, fmt, args);
va_end(args);
pr_debug("%s", printk_buf);
return len;
}
#else
static int dprintk(int level, const char *fmt, ...)
__printf(2, 3)
static void dprintk(int level, const char *fmt, ...)
{
return 0;
}
#endif
static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
{
u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg;
......
......@@ -438,11 +438,15 @@ static void am35x_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
}
static const struct musb_platform_ops am35x_ops = {
.quirks = MUSB_INDEXED_EP,
.quirks = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
.init = am35x_musb_init,
.exit = am35x_musb_exit,
.read_fifo = am35x_read_fifo,
#ifdef CONFIG_USB_INVENTRA_DMA
.dma_init = musbhs_dma_controller_create,
.dma_exit = musbhs_dma_controller_destroy,
#endif
.enable = am35x_musb_enable,
.disable = am35x_musb_disable,
......@@ -565,7 +569,7 @@ static int am35x_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int am35x_suspend(struct device *dev)
{
struct am35x_glue *glue = dev_get_drvdata(dev);
......
......@@ -465,6 +465,7 @@ static int bfin_musb_exit(struct musb *musb)
}
static const struct musb_platform_ops bfin_ops = {
.quirks = MUSB_DMA_INVENTRA,
.init = bfin_musb_init,
.exit = bfin_musb_exit,
......@@ -477,6 +478,10 @@ static const struct musb_platform_ops bfin_ops = {
.fifo_mode = 2,
.read_fifo = bfin_read_fifo,
.write_fifo = bfin_write_fifo,
#ifdef CONFIG_USB_INVENTRA_DMA
.dma_init = musbhs_dma_controller_create,
.dma_exit = musbhs_dma_controller_destroy,
#endif
.enable = bfin_musb_enable,
.disable = bfin_musb_disable,
......
......@@ -1297,7 +1297,8 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
EXPORT_SYMBOL_GPL(cppi_interrupt);
/* Instantiate a software object representing a DMA controller. */
struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mregs)
struct dma_controller *
cppi_dma_controller_create(struct musb *musb, void __iomem *mregs)
{
struct cppi *controller;
struct device *dev = musb->controller;
......@@ -1334,7 +1335,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
if (irq > 0) {
if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
dev_err(dev, "request_irq %d failed!\n", irq);
dma_controller_destroy(&controller->controller);
musb_dma_controller_destroy(&controller->controller);
return NULL;
}
controller->irq = irq;
......@@ -1343,11 +1344,12 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mr
cppi_controller_start(controller);
return &controller->controller;
}
EXPORT_SYMBOL_GPL(cppi_dma_controller_create);
/*
* Destroy a previously-instantiated DMA controller.
*/
void dma_controller_destroy(struct dma_controller *c)
void cppi_dma_controller_destroy(struct dma_controller *c)
{
struct cppi *cppi;
......@@ -1363,6 +1365,7 @@ void dma_controller_destroy(struct dma_controller *c)
kfree(cppi);
}
EXPORT_SYMBOL_GPL(cppi_dma_controller_destroy);
/*
* Context: controller irqlocked, endpoint selected
......
......@@ -458,11 +458,15 @@ static int da8xx_musb_exit(struct musb *musb)
}
static const struct musb_platform_ops da8xx_ops = {
.quirks = MUSB_INDEXED_EP,
.quirks = MUSB_DMA_CPPI | MUSB_INDEXED_EP,
.init = da8xx_musb_init,
.exit = da8xx_musb_exit,
.fifo_mode = 2,
#ifdef CONFIG_USB_TI_CPPI_DMA
.dma_init = cppi_dma_controller_create,
.dma_exit = cppi_dma_controller_destroy,
#endif
.enable = da8xx_musb_enable,
.disable = da8xx_musb_disable,
......
......@@ -284,7 +284,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
* mask, state, "vector", and EOI registers.
*/
cppi = container_of(musb->dma_controller, struct cppi, controller);
if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
if (is_cppi_enabled(musb) && musb->dma_controller && !cppi->irq)
retval = cppi_interrupt(irq, __hci);
/* ack and handle non-CPPI interrupts */
......@@ -491,9 +491,14 @@ static int davinci_musb_exit(struct musb *musb)
}
static const struct musb_platform_ops davinci_ops = {
.quirks = MUSB_DMA_CPPI,
.init = davinci_musb_init,
.exit = davinci_musb_exit,
#ifdef CONFIG_USB_TI_CPPI_DMA
.dma_init = cppi_dma_controller_create,
.dma_exit = cppi_dma_controller_destroy,
#endif
.enable = davinci_musb_enable,
.disable = davinci_musb_disable,
......
......@@ -105,8 +105,12 @@ static int jz4740_musb_exit(struct musb *musb)
return 0;
}
/*
* DMA has not been confirmed to work with CONFIG_USB_INVENTRA_DMA,
* so let's not set up the dma function pointers yet.
*/
static const struct musb_platform_ops jz4740_musb_ops = {
.quirks = MUSB_INDEXED_EP,
.quirks = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
.fifo_mode = 2,
.init = jz4740_musb_init,
.exit = jz4740_musb_exit,
......
This diff is collapsed.
This diff is collapsed.
......@@ -678,7 +678,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
return ret;
}
void dma_controller_destroy(struct dma_controller *c)
void cppi41_dma_controller_destroy(struct dma_controller *c)
{
struct cppi41_dma_controller *controller = container_of(c,
struct cppi41_dma_controller, controller);
......@@ -687,9 +687,10 @@ void dma_controller_destroy(struct dma_controller *c)
cppi41_dma_controller_stop(controller);
kfree(controller);
}
EXPORT_SYMBOL_GPL(cppi41_dma_controller_destroy);
struct dma_controller *dma_controller_create(struct musb *musb,
void __iomem *base)
struct dma_controller *
cppi41_dma_controller_create(struct musb *musb, void __iomem *base)
{
struct cppi41_dma_controller *controller;
int ret = 0;
......@@ -726,3 +727,4 @@ struct dma_controller *dma_controller_create(struct musb *musb,
return ERR_PTR(ret);
return NULL;
}
EXPORT_SYMBOL_GPL(cppi41_dma_controller_create);
This diff is collapsed.
This diff is collapsed.
......@@ -634,10 +634,14 @@ static void dsps_read_fifo32(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
}
static struct musb_platform_ops dsps_ops = {
.quirks = MUSB_INDEXED_EP,
.quirks = MUSB_DMA_CPPI41 | MUSB_INDEXED_EP,
.init = dsps_musb_init,
.exit = dsps_musb_exit,
#ifdef CONFIG_USB_TI_CPPI41_DMA
.dma_init = cppi41_dma_controller_create,
.dma_exit = cppi41_dma_controller_destroy,
#endif
.enable = dsps_musb_enable,
.disable = dsps_musb_disable,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -195,8 +195,10 @@ void musb_port_reset(struct musb *musb, bool do_reset)
msecs_to_jiffies(50));
} else {
dev_dbg(musb->controller, "root port reset stopped\n");
musb_platform_pre_root_reset_end(musb);
musb_writeb(mbase, MUSB_POWER,
power & ~MUSB_POWER_RESET);
musb_platform_post_root_reset_end(musb);
power = musb_readb(mbase, MUSB_POWER);
if (power & MUSB_POWER_HSMODE) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment