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

Pull USB / Thunderbolt updates from Greg KH:
 "Here is the big set of USB and Thunderbolt driver updates for
  6.15-rc1. Included in here are:

   - Thunderbolt driver and core api updates for new hardware and
     features

   - usb-storage const array cleanups

   - typec driver updates

   - dwc3 driver updates

   - xhci driver updates and bugfixes

   - small USB documentation updates

   - usb cdns3 driver updates

   - usb gadget driver updates

   - other small driver updates and fixes

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

* tag 'usb-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (92 commits)
  thunderbolt: Do not add non-active NVM if NVM upgrade is disabled for retimer
  thunderbolt: Scan retimers after device router has been enumerated
  usb: host: cdns3: forward lost power information to xhci
  usb: host: xhci-plat: allow upper layers to signal power loss
  usb: xhci: change xhci_resume() parameters to explicit the desired info
  usb: cdns3-ti: run HW init at resume() if HW was reset
  usb: cdns3-ti: move reg writes to separate function
  usb: cdns3: call cdns_power_is_lost() only once in cdns_resume()
  usb: cdns3: rename hibernated argument of role->resume() to lost_power
  usb: xhci: tegra: rename `runtime` boolean to `is_auto_runtime`
  usb: host: xhci-plat: mvebu: use ->quirks instead of ->init_quirk() func
  usb: dwc3: Don't use %pK through printk
  usb: core: Don't use %pK through printk
  usb: gadget: aspeed: Add NULL pointer check in ast_vhub_init_dev()
  dt-bindings: usb: qcom,dwc3: Synchronize minItems for interrupts and -names
  usb: common: usb-conn-gpio: switch psy_cfg from of_node to fwnode
  usb: xhci: Avoid Stop Endpoint retry loop if the endpoint seems Running
  usb: xhci: Don't change the status of stalled TDs on failed Stop EP
  xhci: Avoid queuing redundant Stop Endpoint command for stalled endpoint
  xhci: Handle spurious events on Etron host isoc enpoints
  ...
This commit is contained in:
Linus Torvalds
2025-04-02 18:23:31 -07:00
87 changed files with 1638 additions and 700 deletions

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# # Copyright (c) 2021 Aspeed Tehchnology Inc.
# # Copyright (c) 2021 Aspeed Technology Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/aspeed-lpc.yaml#

View File

@@ -51,6 +51,8 @@ properties:
- const: core
- const: reg
dma-coherent: true
power-domains:
maxItems: 1

View File

@@ -9,16 +9,19 @@ title: Microchip USB2514 Hub Controller
maintainers:
- Fabio Estevam <festevam@gmail.com>
allOf:
- $ref: usb-device.yaml#
properties:
compatible:
enum:
- usb424,2412
- usb424,2417
- usb424,2514
- usb424,2517
oneOf:
- enum:
- usb424,2412
- usb424,2417
- usb424,2514
- usb424,2517
- items:
- enum:
- usb424,2512
- usb424,2513
- const: usb424,2514
reg: true
@@ -28,6 +31,9 @@ properties:
vdd-supply:
description: 3.3V power supply.
vdda-supply:
description: 3.3V analog power supply.
clocks:
description: External 24MHz clock connected to the CLKIN pin.
maxItems: 1
@@ -43,6 +49,18 @@ patternProperties:
$ref: /schemas/usb/usb-device.yaml
additionalProperties: true
allOf:
- $ref: usb-device.yaml#
- if:
not:
properties:
compatible:
contains:
const: usb424,2514
then:
properties:
vdda-supply: false
unevaluatedProperties: false
examples:
@@ -60,6 +78,7 @@ examples:
clocks = <&clks IMX6QDL_CLK_CKO>;
reset-gpios = <&gpio7 12 GPIO_ACTIVE_LOW>;
vdd-supply = <&reg_3v3_hub>;
vdda-supply = <&reg_3v3a_hub>;
#address-cells = <1>;
#size-cells = <0>;

View File

@@ -0,0 +1,140 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/parade,ps8830.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Parade PS883x USB and DisplayPort Retimer
maintainers:
- Abel Vesa <abel.vesa@linaro.org>
properties:
compatible:
enum:
- parade,ps8830
reg:
maxItems: 1
clocks:
items:
- description: XO Clock
reset-gpios:
maxItems: 1
vdd-supply:
description: power supply (1.07V)
vdd33-supply:
description: power supply (3.3V)
vdd33-cap-supply:
description: power supply (3.3V)
vddar-supply:
description: power supply (1.07V)
vddat-supply:
description: power supply (1.07V)
vddio-supply:
description: power supply (1.2V or 1.8V)
orientation-switch: true
retimer-switch: true
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/properties/port
description: Super Speed (SS) Output endpoint to the Type-C connector
port@1:
$ref: /schemas/graph.yaml#/$defs/port-base
description: Super Speed (SS) Input endpoint from the Super-Speed PHY
unevaluatedProperties: false
port@2:
$ref: /schemas/graph.yaml#/properties/port
description:
Sideband Use (SBU) AUX lines endpoint to the Type-C connector for the purpose of
handling altmode muxing and orientation switching.
required:
- compatible
- reg
- clocks
- reset-gpios
- vdd-supply
- vdd33-supply
- vdd33-cap-supply
- vddat-supply
- vddio-supply
- orientation-switch
- retimer-switch
allOf:
- $ref: usb-switch.yaml#
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
typec-mux@8 {
compatible = "parade,ps8830";
reg = <0x8>;
clocks = <&clk_rtmr_xo>;
vdd-supply = <&vreg_rtmr_1p15>;
vdd33-supply = <&vreg_rtmr_3p3>;
vdd33-cap-supply = <&vreg_rtmr_3p3>;
vddar-supply = <&vreg_rtmr_1p15>;
vddat-supply = <&vreg_rtmr_1p15>;
vddio-supply = <&vreg_rtmr_1p8>;
reset-gpios = <&tlmm 10 GPIO_ACTIVE_LOW>;
retimer-switch;
orientation-switch;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
endpoint {
remote-endpoint = <&typec_con_ss>;
};
};
port@1 {
reg = <1>;
endpoint {
remote-endpoint = <&usb_phy_ss>;
};
};
port@2 {
reg = <2>;
endpoint {
remote-endpoint = <&typec_dp_aux>;
};
};
};
};
};
...

View File

@@ -404,6 +404,7 @@ allOf:
minItems: 2
maxItems: 3
interrupt-names:
minItems: 2
items:
- const: pwr_event
- const: qusb2_phy
@@ -425,6 +426,7 @@ allOf:
minItems: 3
maxItems: 4
interrupt-names:
minItems: 3
items:
- const: pwr_event
- const: qusb2_phy

View File

@@ -30,6 +30,9 @@ properties:
interrupts:
maxItems: 1
vbus-supply:
description: VBUS power supply
wakeup-source:
type: boolean

View File

@@ -26,6 +26,7 @@ select:
contains:
enum:
- rockchip,rk3328-dwc3
- rockchip,rk3562-dwc3
- rockchip,rk3568-dwc3
- rockchip,rk3576-dwc3
- rockchip,rk3588-dwc3
@@ -37,6 +38,7 @@ properties:
items:
- enum:
- rockchip,rk3328-dwc3
- rockchip,rk3562-dwc3
- rockchip,rk3568-dwc3
- rockchip,rk3576-dwc3
- rockchip,rk3588-dwc3
@@ -72,6 +74,7 @@ properties:
- enum:
- grf_clk
- utmi
- pipe
- const: pipe
power-domains:
@@ -111,6 +114,22 @@ allOf:
- const: suspend_clk
- const: bus_clk
- const: grf_clk
- if:
properties:
compatible:
contains:
const: rockchip,rk3562-dwc3
then:
properties:
clocks:
minItems: 4
maxItems: 4
clock-names:
items:
- const: ref_clk
- const: suspend_clk
- const: bus_clk
- const: pipe
- if:
properties:
compatible:

View File

@@ -11,12 +11,17 @@ maintainers:
properties:
compatible:
enum:
- google,gs101-dwusb3
- samsung,exynos5250-dwusb3
- samsung,exynos5433-dwusb3
- samsung,exynos7-dwusb3
- samsung,exynos850-dwusb3
oneOf:
- enum:
- google,gs101-dwusb3
- samsung,exynos5250-dwusb3
- samsung,exynos5433-dwusb3
- samsung,exynos7-dwusb3
- samsung,exynos7870-dwusb3
- samsung,exynos850-dwusb3
- items:
- const: samsung,exynos990-dwusb3
- const: samsung,exynos850-dwusb3
'#address-cells':
const: 1
@@ -52,7 +57,6 @@ required:
- clock-names
- ranges
- '#size-cells'
- vdd10-supply
- vdd33-supply
allOf:
@@ -72,6 +76,8 @@ allOf:
- const: susp_clk
- const: link_aclk
- const: link_pclk
required:
- vdd10-supply
- if:
properties:
@@ -86,6 +92,8 @@ allOf:
clock-names:
items:
- const: usbdrd30
required:
- vdd10-supply
- if:
properties:
@@ -103,6 +111,8 @@ allOf:
- const: susp_clk
- const: phyclk
- const: pipe_pclk
required:
- vdd10-supply
- if:
properties:
@@ -119,6 +129,24 @@ allOf:
- const: usbdrd30
- const: usbdrd30_susp_clk
- const: usbdrd30_axius_clk
required:
- vdd10-supply
- if:
properties:
compatible:
contains:
const: samsung,exynos7870-dwusb3
then:
properties:
clocks:
minItems: 3
maxItems: 3
clock-names:
items:
- const: bus_early
- const: ref
- const: ctrl
- if:
properties:
@@ -134,6 +162,8 @@ allOf:
items:
- const: bus_early
- const: ref
required:
- vdd10-supply
additionalProperties: false

View File

@@ -65,6 +65,17 @@ properties:
mode.
type: boolean
snps,reserved-endpoints:
description:
Reserve endpoints for other needs, e.g, for tracing control and output.
When set, the driver will avoid using them for the regular USB transfers.
$ref: /schemas/types.yaml#/definitions/uint8-array
minItems: 1
maxItems: 30
items:
minimum: 2
maximum: 31
snps,dis-start-transfer-quirk:
description:
When set, disable isoc START TRANSFER command failure SW work-around

View File

@@ -39,8 +39,10 @@ properties:
reg:
description: the number of the USB hub port or the USB host-controller
port to which this device is attached. The range is 1-255.
maxItems: 1
port to which this device is attached.
items:
- minimum: 1
maximum: 255
"#address-cells":
description: should be 1 for hub nodes with device nodes,

View File

@@ -613,7 +613,7 @@ endpoints configuration from the hardware, so we use line 12 instruction
to bypass reading the configuration from silicon, and rely on a
hard-coded table that describes the endpoints configuration instead::
static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
static const struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, },

View File

@@ -161,7 +161,7 @@ THANKS file in Inaky's driver):
- The people at the linux-usb mailing list, for reading so
many messages :) Ok, no more kidding; for all your advises!
- All the people at the USB Implementors Forum for their
- All the people at the USB Implementers Forum for their
help and assistance.
- Nathan Myers <ncm@cantrip.org>, for his advice! (hope you

View File

@@ -24023,7 +24023,7 @@ F: drivers/thunderbolt/dma_test.c
THUNDERBOLT DRIVER
M: Andreas Noever <andreas.noever@gmail.com>
M: Michael Jamet <michael.jamet@intel.com>
M: Mika Westerberg <mika.westerberg@linux.intel.com>
M: Mika Westerberg <westeri@kernel.org>
M: Yehezkel Bernat <YehezkelShB@gmail.com>
L: linux-usb@vger.kernel.org
S: Maintained
@@ -24034,7 +24034,7 @@ F: include/linux/thunderbolt.h
THUNDERBOLT NETWORK DRIVER
M: Michael Jamet <michael.jamet@intel.com>
M: Mika Westerberg <mika.westerberg@linux.intel.com>
M: Mika Westerberg <westeri@kernel.org>
M: Yehezkel Bernat <YehezkelShB@gmail.com>
L: netdev@vger.kernel.org
S: Maintained

View File

@@ -93,9 +93,11 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt)
if (ret)
goto err_nvm;
ret = tb_nvm_add_non_active(nvm, nvm_write);
if (ret)
goto err_nvm;
if (!rt->no_nvm_upgrade) {
ret = tb_nvm_add_non_active(nvm, nvm_write);
if (ret)
goto err_nvm;
}
rt->nvm = nvm;
dev_dbg(&rt->dev, "NVM version %x.%x\n", nvm->major, nvm->minor);

View File

@@ -1305,11 +1305,15 @@ static void tb_scan_port(struct tb_port *port)
goto out_rpm_put;
}
tb_retimer_scan(port, true);
sw = tb_switch_alloc(port->sw->tb, &port->sw->dev,
tb_downstream_route(port));
if (IS_ERR(sw)) {
/*
* Make the downstream retimers available even if there
* is no router connected.
*/
tb_retimer_scan(port, true);
/*
* If there is an error accessing the connected switch
* it may be connected to another domain. Also we allow
@@ -1359,6 +1363,14 @@ static void tb_scan_port(struct tb_port *port)
upstream_port = tb_upstream_port(sw);
tb_configure_link(port, upstream_port, sw);
/*
* Scan for downstream retimers. We only scan them after the
* router has been enumerated to avoid issues with certain
* Pluggable devices that expect the host to enumerate them
* within certain timeout.
*/
tb_retimer_scan(port, true);
/*
* CL0s and CL1 are enabled and supported together.
* Silently ignore CLx enabling in case CLx is not supported.

View File

@@ -2229,19 +2229,15 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up,
path = tb_path_alloc(tb, down, TB_USB3_HOPID, up, TB_USB3_HOPID, 0,
"USB3 Down");
if (!path) {
tb_tunnel_put(tunnel);
return NULL;
}
if (!path)
goto err_free;
tb_usb3_init_path(path);
tunnel->paths[TB_USB3_PATH_DOWN] = path;
path = tb_path_alloc(tb, up, TB_USB3_HOPID, down, TB_USB3_HOPID, 0,
"USB3 Up");
if (!path) {
tb_tunnel_put(tunnel);
return NULL;
}
if (!path)
goto err_free;
tb_usb3_init_path(path);
tunnel->paths[TB_USB3_PATH_UP] = path;
@@ -2258,6 +2254,10 @@ struct tb_tunnel *tb_tunnel_alloc_usb3(struct tb *tb, struct tb_port *up,
}
return tunnel;
err_free:
tb_tunnel_put(tunnel);
return NULL;
}
/**

View File

@@ -3468,7 +3468,7 @@ __must_hold(&cdns->lock)
return 0;
}
static int cdns3_gadget_resume(struct cdns *cdns, bool hibernated)
static int cdns3_gadget_resume(struct cdns *cdns, bool lost_power)
{
struct cdns3_device *priv_dev = cdns->gadget_dev;
@@ -3476,7 +3476,7 @@ static int cdns3_gadget_resume(struct cdns *cdns, bool hibernated)
return 0;
cdns3_gadget_config(priv_dev);
if (hibernated)
if (lost_power)
writel(USB_CONF_DEVEN, &priv_dev->regs->usb_conf);
return 0;

View File

@@ -58,6 +58,7 @@ struct cdns_ti {
unsigned vbus_divider:1;
struct clk *usb2_refclk;
struct clk *lpm_clk;
int usb2_refclk_rate_code;
};
static const int cdns_ti_rate_table[] = { /* in KHZ */
@@ -98,15 +99,50 @@ static const struct of_dev_auxdata cdns_ti_auxdata[] = {
{},
};
static void cdns_ti_reset_and_init_hw(struct cdns_ti *data)
{
u32 reg;
/* assert RESET */
reg = cdns_ti_readl(data, USBSS_W1);
reg &= ~USBSS_W1_PWRUP_RST;
cdns_ti_writel(data, USBSS_W1, reg);
/* set static config */
reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
reg |= data->usb2_refclk_rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;
reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
if (data->vbus_divider)
reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;
cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
/* set USB2_ONLY mode if requested */
reg = cdns_ti_readl(data, USBSS_W1);
if (data->usb2_only)
reg |= USBSS_W1_USB2_ONLY;
/* set default modestrap */
reg |= USBSS_W1_MODESTRAP_SEL;
reg &= ~USBSS_W1_MODESTRAP_MASK;
reg |= USBSS_MODESTRAP_MODE_NONE << USBSS_W1_MODESTRAP_SHIFT;
cdns_ti_writel(data, USBSS_W1, reg);
/* de-assert RESET */
reg |= USBSS_W1_PWRUP_RST;
cdns_ti_writel(data, USBSS_W1, reg);
}
static int cdns_ti_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = pdev->dev.of_node;
struct cdns_ti *data;
int error;
u32 reg;
int rate_code, i;
unsigned long rate;
int error, i;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -146,7 +182,17 @@ static int cdns_ti_probe(struct platform_device *pdev)
return -EINVAL;
}
rate_code = i;
data->usb2_refclk_rate_code = i;
data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
data->usb2_only = device_property_read_bool(dev, "ti,usb2-only");
/*
* The call below to pm_runtime_get_sync() MIGHT reset hardware, if it
* detects it as uninitialised. We want to enforce a reset at probe,
* and so do it manually here. This means the first runtime_resume()
* will be a no-op.
*/
cdns_ti_reset_and_init_hw(data);
pm_runtime_enable(dev);
error = pm_runtime_get_sync(dev);
@@ -155,40 +201,6 @@ static int cdns_ti_probe(struct platform_device *pdev)
goto err;
}
/* assert RESET */
reg = cdns_ti_readl(data, USBSS_W1);
reg &= ~USBSS_W1_PWRUP_RST;
cdns_ti_writel(data, USBSS_W1, reg);
/* set static config */
reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
reg |= rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;
reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
if (data->vbus_divider)
reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;
cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
/* set USB2_ONLY mode if requested */
reg = cdns_ti_readl(data, USBSS_W1);
data->usb2_only = device_property_read_bool(dev, "ti,usb2-only");
if (data->usb2_only)
reg |= USBSS_W1_USB2_ONLY;
/* set default modestrap */
reg |= USBSS_W1_MODESTRAP_SEL;
reg &= ~USBSS_W1_MODESTRAP_MASK;
reg |= USBSS_MODESTRAP_MODE_NONE << USBSS_W1_MODESTRAP_SHIFT;
cdns_ti_writel(data, USBSS_W1, reg);
/* de-assert RESET */
reg |= USBSS_W1_PWRUP_RST;
cdns_ti_writel(data, USBSS_W1, reg);
error = of_platform_populate(node, NULL, cdns_ti_auxdata, dev);
if (error) {
dev_err(dev, "failed to create children: %d\n", error);
@@ -224,6 +236,24 @@ static void cdns_ti_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
}
static int cdns_ti_runtime_resume(struct device *dev)
{
const u32 mask = USBSS_W1_PWRUP_RST | USBSS_W1_MODESTRAP_SEL;
struct cdns_ti *data = dev_get_drvdata(dev);
u32 w1;
w1 = cdns_ti_readl(data, USBSS_W1);
if ((w1 & mask) != mask)
cdns_ti_reset_and_init_hw(data);
return 0;
}
static const struct dev_pm_ops cdns_ti_pm_ops = {
RUNTIME_PM_OPS(NULL, cdns_ti_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct of_device_id cdns_ti_of_match[] = {
{ .compatible = "ti,j721e-usb", },
{ .compatible = "ti,am64-usb", },
@@ -237,6 +267,7 @@ static struct platform_driver cdns_ti_driver = {
.driver = {
.name = "cdns3-ti",
.of_match_table = cdns_ti_of_match,
.pm = pm_ptr(&cdns_ti_pm_ops),
},
};

View File

@@ -1974,7 +1974,7 @@ static int cdnsp_gadget_suspend(struct cdns *cdns, bool do_wakeup)
return 0;
}
static int cdnsp_gadget_resume(struct cdns *cdns, bool hibernated)
static int cdnsp_gadget_resume(struct cdns *cdns, bool lost_power)
{
struct cdnsp_device *pdev = cdns->gadget_dev;
enum usb_device_speed max_speed;

View File

@@ -524,11 +524,12 @@ EXPORT_SYMBOL_GPL(cdns_suspend);
int cdns_resume(struct cdns *cdns)
{
bool power_lost = cdns_power_is_lost(cdns);
enum usb_role real_role;
bool role_changed = false;
int ret = 0;
if (cdns_power_is_lost(cdns)) {
if (power_lost) {
if (!cdns->role_sw) {
real_role = cdns_hw_role_state_machine(cdns);
if (real_role != cdns->role) {
@@ -551,7 +552,7 @@ int cdns_resume(struct cdns *cdns)
}
if (cdns->roles[cdns->role]->resume)
cdns->roles[cdns->role]->resume(cdns, cdns_power_is_lost(cdns));
cdns->roles[cdns->role]->resume(cdns, power_lost);
return 0;
}

View File

@@ -30,7 +30,7 @@ struct cdns_role_driver {
int (*start)(struct cdns *cdns);
void (*stop)(struct cdns *cdns);
int (*suspend)(struct cdns *cdns, bool do_wakeup);
int (*resume)(struct cdns *cdns, bool hibernated);
int (*resume)(struct cdns *cdns, bool lost_power);
const char *name;
#define CDNS_ROLE_STATE_INACTIVE 0
#define CDNS_ROLE_STATE_ACTIVE 1

View File

@@ -138,6 +138,16 @@ static void cdns_host_exit(struct cdns *cdns)
cdns_drd_host_off(cdns);
}
static int cdns_host_resume(struct cdns *cdns, bool power_lost)
{
struct usb_hcd *hcd = platform_get_drvdata(cdns->host_dev);
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
priv->power_lost = power_lost;
return 0;
}
int cdns_host_init(struct cdns *cdns)
{
struct cdns_role_driver *rdrv;
@@ -148,6 +158,7 @@ int cdns_host_init(struct cdns *cdns)
rdrv->start = __cdns_host_init;
rdrv->stop = cdns_host_exit;
rdrv->resume = cdns_host_resume;
rdrv->state = CDNS_ROLE_STATE_INACTIVE;
rdrv->name = "host";

View File

@@ -440,7 +440,7 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
else if (data->oc_pol_configured)
reg &= ~MX6_BM_OVER_CUR_POLARITY;
}
/* If the polarity is not set keep it as setup by the bootlader */
/* If the polarity is not set keep it as setup by the bootloader */
if (data->pwr_pol == 1)
reg |= MX6_BM_PWR_POLARITY;
writel(reg, usbmisc->base + data->index * 4);
@@ -645,7 +645,7 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
else if (data->oc_pol_configured)
reg &= ~MX6_BM_OVER_CUR_POLARITY;
}
/* If the polarity is not set keep it as setup by the bootlader */
/* If the polarity is not set keep it as setup by the bootloader */
if (data->pwr_pol == 1)
reg |= MX6_BM_PWR_POLARITY;
writel(reg, usbmisc->base);
@@ -939,7 +939,7 @@ static int usbmisc_imx7ulp_init(struct imx_usbmisc_data *data)
else if (data->oc_pol_configured)
reg &= ~MX6_BM_OVER_CUR_POLARITY;
}
/* If the polarity is not set keep it as setup by the bootlader */
/* If the polarity is not set keep it as setup by the bootloader */
if (data->pwr_pol == 1)
reg |= MX6_BM_PWR_POLARITY;
@@ -1185,7 +1185,7 @@ int imx_usbmisc_suspend(struct imx_usbmisc_data *data, bool wakeup)
if (usbmisc->ops->hsic_set_clk && data->hsic)
ret = usbmisc->ops->hsic_set_clk(data, false);
if (ret) {
dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
dev_err(data->dev, "hsic_set_clk failed, ret=%d\n", ret);
return ret;
}
@@ -1224,7 +1224,7 @@ int imx_usbmisc_resume(struct imx_usbmisc_data *data, bool wakeup)
if (usbmisc->ops->hsic_set_clk && data->hsic)
ret = usbmisc->ops->hsic_set_clk(data, true);
if (ret) {
dev_err(data->dev, "set_wakeup failed, ret=%d\n", ret);
dev_err(data->dev, "hsic_set_clk failed, ret=%d\n", ret);
goto hsic_set_clk_fail;
}

View File

@@ -158,7 +158,7 @@ static int usb_conn_psy_register(struct usb_conn_info *info)
struct device *dev = info->dev;
struct power_supply_desc *desc = &info->desc;
struct power_supply_config cfg = {
.of_node = dev->of_node,
.fwnode = dev_fwnode(dev),
};
desc->name = "usb-charger";

View File

@@ -64,6 +64,37 @@ static void usb_parse_ssp_isoc_endpoint_companion(struct device *ddev,
memcpy(&ep->ssp_isoc_ep_comp, desc, USB_DT_SSP_ISOC_EP_COMP_SIZE);
}
static void usb_parse_eusb2_isoc_endpoint_companion(struct device *ddev,
int cfgno, int inum, int asnum, struct usb_host_endpoint *ep,
unsigned char *buffer, int size)
{
struct usb_eusb2_isoc_ep_comp_descriptor *desc;
struct usb_descriptor_header *h;
/*
* eUSB2 isochronous endpoint companion descriptor for this endpoint
* shall be declared before the next endpoint or interface descriptor
*/
while (size >= USB_DT_EUSB2_ISOC_EP_COMP_SIZE) {
h = (struct usb_descriptor_header *)buffer;
if (h->bDescriptorType == USB_DT_EUSB2_ISOC_ENDPOINT_COMP) {
desc = (struct usb_eusb2_isoc_ep_comp_descriptor *)buffer;
ep->eusb2_isoc_ep_comp = *desc;
return;
}
if (h->bDescriptorType == USB_DT_ENDPOINT ||
h->bDescriptorType == USB_DT_INTERFACE)
break;
buffer += h->bLength;
size -= h->bLength;
}
dev_notice(ddev, "No eUSB2 isoc ep %d companion for config %d interface %d altsetting %d\n",
ep->desc.bEndpointAddress, cfgno, inum, asnum);
}
static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
int inum, int asnum, struct usb_host_endpoint *ep,
unsigned char *buffer, int size)
@@ -258,8 +289,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
int n, i, j, retval;
unsigned int maxp;
const unsigned short *maxpacket_maxes;
u16 bcdUSB;
d = (struct usb_endpoint_descriptor *) buffer;
bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB);
buffer += d->bLength;
size -= d->bLength;
@@ -409,15 +442,17 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
/*
* Validate the wMaxPacketSize field.
* Some devices have isochronous endpoints in altsetting 0;
* the USB-2 spec requires such endpoints to have wMaxPacketSize = 0
* (see the end of section 5.6.3), so don't warn about them.
* eUSB2 devices (see USB 2.0 Double Isochronous IN ECN 9.6.6 Endpoint)
* and devices with isochronous endpoints in altsetting 0 (see USB 2.0
* end of section 5.6.3) have wMaxPacketSize = 0.
* So don't warn about those.
*/
maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize);
if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) {
if (maxp == 0 && bcdUSB != 0x0220 &&
!(usb_endpoint_xfer_isoc(d) && asnum == 0))
dev_notice(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
cfgno, inum, asnum, d->bEndpointAddress);
}
/* Find the highest legal maxpacket size for this endpoint */
i = 0; /* additional transactions per microframe */
@@ -465,6 +500,12 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
maxp);
}
/* Parse a possible eUSB2 periodic endpoint companion descriptor */
if (bcdUSB == 0x0220 && d->wMaxPacketSize == 0 &&
(usb_endpoint_xfer_isoc(d) || usb_endpoint_xfer_int(d)))
usb_parse_eusb2_isoc_endpoint_companion(ddev, cfgno, inum, asnum,
endpoint, buffer, size);
/* Parse a possible SuperSpeed endpoint companion descriptor */
if (udev->speed >= USB_SPEED_SUPER)
usb_parse_ss_endpoint_companion(ddev, cfgno,

View File

@@ -1609,7 +1609,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
if (retval == 0)
retval = -EINPROGRESS;
else if (retval != -EIDRM && retval != -EBUSY)
dev_dbg(&udev->dev, "hcd_unlink_urb %pK fail %d\n",
dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n",
urb, retval);
usb_put_dev(udev);
}
@@ -1786,7 +1786,7 @@ void usb_hcd_flush_endpoint(struct usb_device *udev,
/* kick hcd */
unlink1(hcd, urb, -ESHUTDOWN);
dev_dbg (hcd->self.controller,
"shutdown urb %pK ep%d%s-%s\n",
"shutdown urb %p ep%d%s-%s\n",
urb, usb_endpoint_num(&ep->desc),
is_in ? "in" : "out",
usb_ep_type_string(usb_endpoint_type(&ep->desc)));

View File

@@ -4708,8 +4708,6 @@ void usb_ep0_reinit(struct usb_device *udev)
}
EXPORT_SYMBOL_GPL(usb_ep0_reinit);
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
static int hub_set_address(struct usb_device *udev, int devnum)
{
int retval;
@@ -4733,7 +4731,7 @@ static int hub_set_address(struct usb_device *udev, int devnum)
if (hcd->driver->address_device)
retval = hcd->driver->address_device(hcd, udev, timeout_ms);
else
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, timeout_ms);
if (retval == 0) {

View File

@@ -376,7 +376,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (!urb || !urb->complete)
return -EINVAL;
if (urb->hcpriv) {
WARN_ONCE(1, "URB %pK submitted while active\n", urb);
WARN_ONCE(1, "URB %p submitted while active\n", urb);
return -EBUSY;
}

View File

@@ -43,6 +43,7 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
/* Backup global regs */
gr = &hsotg->gr_backup;
gr->gintsts = dwc2_readl(hsotg, GINTSTS);
gr->gotgctl = dwc2_readl(hsotg, GOTGCTL);
gr->gintmsk = dwc2_readl(hsotg, GINTMSK);
gr->gahbcfg = dwc2_readl(hsotg, GAHBCFG);

View File

@@ -667,6 +667,7 @@ struct dwc2_hw_params {
/**
* struct dwc2_gregs_backup - Holds global registers state before
* entering partial power down
* @gintsts: Backup of GINTSTS register
* @gotgctl: Backup of GOTGCTL register
* @gintmsk: Backup of GINTMSK register
* @gahbcfg: Backup of GAHBCFG register
@@ -683,6 +684,7 @@ struct dwc2_hw_params {
* @valid: True if registers values backuped.
*/
struct dwc2_gregs_backup {
u32 gintsts;
u32 gotgctl;
u32 gintmsk;
u32 gahbcfg;
@@ -1127,6 +1129,9 @@ struct dwc2_hsotg {
#define DWC2_FS_IOT_ID 0x55310000
#define DWC2_HS_IOT_ID 0x55320000
#define DWC2_RESTORE_DCTL BIT(0)
#define DWC2_RESTORE_DCFG BIT(1)
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
union dwc2_hcd_internal_flags {
u32 d32;
@@ -1420,7 +1425,7 @@ int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
#define dwc2_is_device_connected(hsotg) (hsotg->connected)
#define dwc2_is_device_enabled(hsotg) (hsotg->enabled)
int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg);
int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup);
int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, unsigned int flags);
int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg);
int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
int rem_wakeup, int reset);
@@ -1435,6 +1440,9 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg);
void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg);
int dwc2_gadget_backup_critical_registers(struct dwc2_hsotg *hsotg);
int dwc2_gadget_restore_critical_registers(struct dwc2_hsotg *hsotg,
unsigned int flags);
static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg)
{ hsotg->fifo_map = 0; }
#else
@@ -1459,7 +1467,7 @@ static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg,
int remote_wakeup)
unsigned int flags)
{ return 0; }
static inline int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
{ return 0; }
@@ -1482,6 +1490,11 @@ static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg) {}
static inline int dwc2_gadget_backup_critical_registers(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline int dwc2_gadget_restore_critical_registers(struct dwc2_hsotg *hsotg,
unsigned int flags)
{ return 0; }
static inline void dwc2_clear_fifo_map(struct dwc2_hsotg *hsotg) {}
#endif
@@ -1505,6 +1518,8 @@ int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
void dwc2_host_enter_clock_gating(struct dwc2_hsotg *hsotg);
void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg, int rem_wakeup);
bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2);
int dwc2_host_backup_critical_registers(struct dwc2_hsotg *hsotg);
int dwc2_host_restore_critical_registers(struct dwc2_hsotg *hsotg);
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg)
{ schedule_work(&hsotg->phy_reset_work); }
#else
@@ -1544,6 +1559,10 @@ static inline void dwc2_host_exit_clock_gating(struct dwc2_hsotg *hsotg,
int rem_wakeup) {}
static inline bool dwc2_host_can_poweroff_phy(struct dwc2_hsotg *dwc2)
{ return false; }
static inline int dwc2_host_backup_critical_registers(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline int dwc2_host_restore_critical_registers(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {}
#endif

View File

@@ -5204,11 +5204,11 @@ int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
* if controller power were disabled.
*
* @hsotg: Programming view of the DWC_otg controller
* @remote_wakeup: Indicates whether resume is initiated by Device or Host.
* @flags: Defines which registers should be restored.
*
* Return: 0 if successful, negative error code otherwise
*/
int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup)
int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, unsigned int flags)
{
struct dwc2_dregs_backup *dr;
int i;
@@ -5224,7 +5224,10 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup)
}
dr->valid = false;
if (!remote_wakeup)
if (flags & DWC2_RESTORE_DCFG)
dwc2_writel(hsotg, dr->dcfg, DCFG);
if (flags & DWC2_RESTORE_DCTL)
dwc2_writel(hsotg, dr->dctl, DCTL);
dwc2_writel(hsotg, dr->daintmsk, DAINTMSK);
@@ -5310,6 +5313,49 @@ void dwc2_gadget_program_ref_clk(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "GREFCLK=0x%08x\n", dwc2_readl(hsotg, GREFCLK));
}
int dwc2_gadget_backup_critical_registers(struct dwc2_hsotg *hsotg)
{
int ret;
/* Backup all registers */
ret = dwc2_backup_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
__func__);
return ret;
}
ret = dwc2_backup_device_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup device registers\n",
__func__);
return ret;
}
return 0;
}
int dwc2_gadget_restore_critical_registers(struct dwc2_hsotg *hsotg,
unsigned int flags)
{
int ret;
ret = dwc2_restore_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore registers\n",
__func__);
return ret;
}
ret = dwc2_restore_device_registers(hsotg, flags);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
__func__);
return ret;
}
return 0;
}
/**
* dwc2_gadget_enter_hibernation() - Put controller in Hibernation.
*
@@ -5327,18 +5373,9 @@ int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
/* Change to L2(suspend) state */
hsotg->lx_state = DWC2_L2;
dev_dbg(hsotg->dev, "Start of hibernation completed\n");
ret = dwc2_backup_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
__func__);
ret = dwc2_gadget_backup_critical_registers(hsotg);
if (ret)
return ret;
}
ret = dwc2_backup_device_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup device registers\n",
__func__);
return ret;
}
gpwrdn = GPWRDN_PWRDNRSTN;
udelay(10);
@@ -5415,6 +5452,7 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
u32 gpwrdn;
u32 dctl;
int ret = 0;
unsigned int flags = 0;
struct dwc2_gregs_backup *gr;
struct dwc2_dregs_backup *dr;
@@ -5477,6 +5515,7 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
dctl = dwc2_readl(hsotg, DCTL);
dctl |= DCTL_PWRONPRGDONE;
dwc2_writel(hsotg, dctl, DCTL);
flags |= DWC2_RESTORE_DCTL;
}
/* Wait for interrupts which must be cleared */
mdelay(2);
@@ -5484,20 +5523,9 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
dwc2_writel(hsotg, 0xffffffff, GINTSTS);
/* Restore global registers */
ret = dwc2_restore_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore registers\n",
__func__);
ret = dwc2_gadget_restore_critical_registers(hsotg, flags);
if (ret)
return ret;
}
/* Restore device registers */
ret = dwc2_restore_device_registers(hsotg, rem_wakeup);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
__func__);
return ret;
}
if (rem_wakeup) {
mdelay(10);
@@ -5531,19 +5559,9 @@ int dwc2_gadget_enter_partial_power_down(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "Entering device partial power down started.\n");
/* Backup all registers */
ret = dwc2_backup_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
__func__);
ret = dwc2_gadget_backup_critical_registers(hsotg);
if (ret)
return ret;
}
ret = dwc2_backup_device_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup device registers\n",
__func__);
return ret;
}
/*
* Clear any pending interrupts since dwc2 will not be able to
@@ -5590,11 +5608,8 @@ int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
{
u32 pcgcctl;
u32 dctl;
struct dwc2_dregs_backup *dr;
int ret = 0;
dr = &hsotg->dr_backup;
dev_dbg(hsotg->dev, "Exiting device partial Power Down started.\n");
pcgcctl = dwc2_readl(hsotg, PCGCTL);
@@ -5611,21 +5626,10 @@ int dwc2_gadget_exit_partial_power_down(struct dwc2_hsotg *hsotg,
udelay(100);
if (restore) {
ret = dwc2_restore_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore registers\n",
__func__);
ret = dwc2_gadget_restore_critical_registers(hsotg, DWC2_RESTORE_DCTL |
DWC2_RESTORE_DCFG);
if (ret)
return ret;
}
/* Restore DCFG */
dwc2_writel(hsotg, dr->dcfg, DCFG);
ret = dwc2_restore_device_registers(hsotg, 0);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore device registers\n",
__func__);
return ret;
}
}
/* Set the Power-On Programming done bit */

View File

@@ -5474,6 +5474,49 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
return 0;
}
int dwc2_host_backup_critical_registers(struct dwc2_hsotg *hsotg)
{
int ret;
/* Backup all registers */
ret = dwc2_backup_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
__func__);
return ret;
}
ret = dwc2_backup_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
__func__);
return ret;
}
return 0;
}
int dwc2_host_restore_critical_registers(struct dwc2_hsotg *hsotg)
{
int ret;
ret = dwc2_restore_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore registers\n",
__func__);
return ret;
}
ret = dwc2_restore_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
__func__);
return ret;
}
return 0;
}
/**
* dwc2_host_enter_hibernation() - Put controller in Hibernation.
*
@@ -5489,18 +5532,9 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
u32 gpwrdn;
dev_dbg(hsotg->dev, "Preparing host for hibernation\n");
ret = dwc2_backup_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
__func__);
ret = dwc2_host_backup_critical_registers(hsotg);
if (ret)
return ret;
}
ret = dwc2_backup_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
__func__);
return ret;
}
/* Enter USB Suspend Mode */
hprt0 = dwc2_readl(hsotg, HPRT0);
@@ -5694,20 +5728,9 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
dwc2_writel(hsotg, 0xffffffff, GINTSTS);
/* Restore global registers */
ret = dwc2_restore_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore registers\n",
__func__);
ret = dwc2_host_restore_critical_registers(hsotg);
if (ret)
return ret;
}
/* Restore host registers */
ret = dwc2_restore_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
__func__);
return ret;
}
if (rem_wakeup) {
dwc2_hcd_rem_wakeup(hsotg);
@@ -5774,19 +5797,9 @@ int dwc2_host_enter_partial_power_down(struct dwc2_hsotg *hsotg)
dev_warn(hsotg->dev, "Suspend wasn't generated\n");
/* Backup all registers */
ret = dwc2_backup_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup global registers\n",
__func__);
ret = dwc2_host_backup_critical_registers(hsotg);
if (ret)
return ret;
}
ret = dwc2_backup_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to backup host registers\n",
__func__);
return ret;
}
/*
* Clear any pending interrupts since dwc2 will not be able to
@@ -5855,19 +5868,9 @@ int dwc2_host_exit_partial_power_down(struct dwc2_hsotg *hsotg,
udelay(100);
if (restore) {
ret = dwc2_restore_global_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore registers\n",
__func__);
ret = dwc2_host_restore_critical_registers(hsotg);
if (ret)
return ret;
}
ret = dwc2_restore_host_registers(hsotg);
if (ret) {
dev_err(hsotg->dev, "%s: failed to restore host registers\n",
__func__);
return ret;
}
}
/* Drive resume signaling and exit suspend mode on the port. */

View File

@@ -685,6 +685,14 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
regulator_disable(dwc2->usb33d);
}
if (is_device_mode)
ret = dwc2_gadget_backup_critical_registers(dwc2);
else
ret = dwc2_host_backup_critical_registers(dwc2);
if (ret)
return ret;
if (dwc2->ll_hw_enabled &&
(is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
ret = __dwc2_lowlevel_hw_disable(dwc2);
@@ -694,6 +702,24 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
return ret;
}
static int dwc2_restore_critical_registers(struct dwc2_hsotg *hsotg)
{
struct dwc2_gregs_backup *gr;
gr = &hsotg->gr_backup;
if (!gr->valid) {
dev_err(hsotg->dev, "No valid register backup, failed to restore\n");
return -EINVAL;
}
if (gr->gintsts & GINTSTS_CURMODE_HOST)
return dwc2_host_restore_critical_registers(hsotg);
return dwc2_gadget_restore_critical_registers(hsotg, DWC2_RESTORE_DCTL |
DWC2_RESTORE_DCFG);
}
static int __maybe_unused dwc2_resume(struct device *dev)
{
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
@@ -706,6 +732,18 @@ static int __maybe_unused dwc2_resume(struct device *dev)
}
dwc2->phy_off_for_suspend = false;
/*
* During suspend it's possible that the power domain for the
* DWC2 controller is disabled and all register values get lost.
* In case the GUSBCFG register is not initialized, it's clear the
* registers must be restored.
*/
if (!(dwc2_readl(dwc2, GUSBCFG) & GUSBCFG_TOUTCAL_MASK)) {
ret = dwc2_restore_critical_registers(dwc2);
if (ret)
return ret;
}
if (dwc2->params.activate_stm_id_vb_detection) {
unsigned long flags;
u32 ggpio, gotgctl;

View File

@@ -153,11 +153,11 @@ static int phy_syscon_pll_refclk(struct dwc3_am62 *am62)
{
struct device *dev = am62->dev;
struct device_node *node = dev->of_node;
struct of_phandle_args args;
struct regmap *syscon;
int ret;
syscon = syscon_regmap_lookup_by_phandle(node, "ti,syscon-phy-pll-refclk");
syscon = syscon_regmap_lookup_by_phandle_args(node, "ti,syscon-phy-pll-refclk",
1, &am62->offset);
if (IS_ERR(syscon)) {
dev_err(dev, "unable to get ti,syscon-phy-pll-refclk regmap\n");
return PTR_ERR(syscon);
@@ -165,14 +165,6 @@ static int phy_syscon_pll_refclk(struct dwc3_am62 *am62)
am62->syscon = syscon;
ret = of_parse_phandle_with_fixed_args(node, "ti,syscon-phy-pll-refclk", 1,
0, &args);
if (ret)
return ret;
of_node_put(args.np);
am62->offset = args.args[0];
/* Core voltage. PHY_CORE_VOLTAGE bit Recommended to be 0 always */
ret = regmap_update_bits(am62->syscon, am62->offset, PHY_CORE_VOLTAGE_MASK, 0);
if (ret) {

View File

@@ -163,6 +163,12 @@ static const struct dwc3_exynos_driverdata exynos7_drvdata = {
.suspend_clk_idx = 1,
};
static const struct dwc3_exynos_driverdata exynos7870_drvdata = {
.clk_names = { "bus_early", "ref", "ctrl" },
.num_clks = 3,
.suspend_clk_idx = -1,
};
static const struct dwc3_exynos_driverdata exynos850_drvdata = {
.clk_names = { "bus_early", "ref" },
.num_clks = 2,
@@ -185,6 +191,9 @@ static const struct of_device_id exynos_dwc3_match[] = {
}, {
.compatible = "samsung,exynos7-dwusb3",
.data = &exynos7_drvdata,
}, {
.compatible = "samsung,exynos7870-dwusb3",
.data = &exynos7870_drvdata,
}, {
.compatible = "samsung,exynos850-dwusb3",
.data = &exynos850_drvdata,

View File

@@ -148,11 +148,21 @@ static const struct property_entry dwc3_pci_intel_byt_properties[] = {
{}
};
/*
* Intel Merrifield SoC uses these endpoints for tracing and they cannot
* be re-allocated if being used because the side band flow control signals
* are hard wired to certain endpoints:
* - 1 High BW Bulk IN (IN#1) (RTIT)
* - 1 1KB BW Bulk IN (IN#8) + 1 1KB BW Bulk OUT (Run Control) (OUT#8)
*/
static const u8 dwc3_pci_mrfld_reserved_endpoints[] = { 3, 16, 17 };
static const struct property_entry dwc3_pci_mrfld_properties[] = {
PROPERTY_ENTRY_STRING("dr_mode", "otg"),
PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
PROPERTY_ENTRY_U8_ARRAY("snps,reserved-endpoints", dwc3_pci_mrfld_reserved_endpoints),
PROPERTY_ENTRY_BOOL("snps,usb2-gadget-lpm-disable"),
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
{}

View File

@@ -225,7 +225,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
dwc3_data->syscfg_reg_off = res->start;
dev_vdbg(dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n",
dev_vdbg(dev, "glue-logic addr 0x%p, syscfg-reg offset 0x%x\n",
dwc3_data->glue_base, dwc3_data->syscfg_reg_off);
struct device_node *child __free(device_node) = of_get_compatible_child(node,

View File

@@ -547,6 +547,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep)
int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_ep *dep;
u32 cmd;
int i;
int ret;
@@ -563,8 +564,13 @@ int dwc3_gadget_start_config(struct dwc3 *dwc, unsigned int resource_index)
return ret;
/* Reset resource allocation flags */
for (i = resource_index; i < dwc->num_eps && dwc->eps[i]; i++)
dwc->eps[i]->flags &= ~DWC3_EP_RESOURCE_ALLOCATED;
for (i = resource_index; i < dwc->num_eps; i++) {
dep = dwc->eps[i];
if (!dep)
continue;
dep->flags &= ~DWC3_EP_RESOURCE_ALLOCATED;
}
return 0;
}
@@ -751,9 +757,11 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc)
dwc->last_fifo_depth = fifo_depth;
/* Clear existing TXFIFO for all IN eps except ep0 */
for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM);
num += 2) {
for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); num += 2) {
dep = dwc->eps[num];
if (!dep)
continue;
/* Don't change TXFRAMNUM on usb31 version */
size = DWC3_IP_IS(DWC3) ? 0 :
dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) &
@@ -1971,12 +1979,12 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
return -ESHUTDOWN;
}
if (WARN(req->dep != dep, "request %pK belongs to '%s'\n",
if (WARN(req->dep != dep, "request %p belongs to '%s'\n",
&req->request, req->dep->name))
return -EINVAL;
if (WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED,
"%s: request %pK already in flight\n",
"%s: request %p already in flight\n",
dep->name, &req->request))
return -EINVAL;
@@ -2165,7 +2173,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
}
}
dev_err(dwc->dev, "request %pK was not queued to %s\n",
dev_err(dwc->dev, "request %p was not queued to %s\n",
request, ep->name);
ret = -EINVAL;
out:
@@ -3429,14 +3437,53 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
return 0;
}
static int dwc3_gadget_get_reserved_endpoints(struct dwc3 *dwc, const char *propname,
u8 *eps, u8 num)
{
u8 count;
int ret;
if (!device_property_present(dwc->dev, propname))
return 0;
ret = device_property_count_u8(dwc->dev, propname);
if (ret < 0)
return ret;
count = ret;
ret = device_property_read_u8_array(dwc->dev, propname, eps, min(num, count));
if (ret)
return ret;
return count;
}
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total)
{
const char *propname = "snps,reserved-endpoints";
u8 epnum;
u8 reserved_eps[DWC3_ENDPOINTS_NUM];
u8 count;
u8 num;
int ret;
INIT_LIST_HEAD(&dwc->gadget->ep_list);
ret = dwc3_gadget_get_reserved_endpoints(dwc, propname,
reserved_eps, ARRAY_SIZE(reserved_eps));
if (ret < 0) {
dev_err(dwc->dev, "failed to read %s\n", propname);
return ret;
}
count = ret;
for (epnum = 0; epnum < total; epnum++) {
int ret;
for (num = 0; num < count; num++) {
if (epnum == reserved_eps[num])
break;
}
if (num < count)
continue;
ret = dwc3_gadget_init_endpoint(dwc, epnum);
if (ret)
@@ -3703,6 +3750,8 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep,
for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
dep = dwc->eps[i];
if (!dep)
continue;
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
@@ -3852,6 +3901,10 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
u8 epnum = event->endpoint_number;
dep = dwc->eps[epnum];
if (!dep) {
dev_warn(dwc->dev, "spurious event, endpoint %u is not allocated\n", epnum);
return;
}
if (!(dep->flags & DWC3_EP_ENABLED)) {
if ((epnum > 1) && !(dep->flags & DWC3_EP_TRANSFER_STARTED))

View File

@@ -122,8 +122,6 @@ static const struct vb2_ops uvc_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
int uvcg_queue_init(struct uvc_video_queue *queue, struct device *dev, enum v4l2_buf_type type,

View File

@@ -548,6 +548,9 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
d->vhub = vhub;
d->index = idx;
d->name = devm_kasprintf(parent, GFP_KERNEL, "port%d", idx+1);
if (!d->name)
return -ENOMEM;
d->regs = vhub->regs + 0x100 + 0x10 * idx;
ast_vhub_init_ep0(vhub, &d->ep0, d);

View File

@@ -1946,6 +1946,12 @@ max3421_remove(struct spi_device *spi)
usb_put_hcd(hcd);
}
static const struct spi_device_id max3421_spi_ids[] = {
{ "max3421" },
{ },
};
MODULE_DEVICE_TABLE(spi, max3421_spi_ids);
static const struct of_device_id max3421_of_match_table[] = {
{ .compatible = "maxim,max3421", },
{},
@@ -1955,6 +1961,7 @@ MODULE_DEVICE_TABLE(of, max3421_of_match_table);
static struct spi_driver max3421_driver = {
.probe = max3421_probe,
.remove = max3421_remove,
.id_table = max3421_spi_ids,
.driver = {
.name = "max3421-hcd",
.of_match_table = max3421_of_match_table,

View File

@@ -355,7 +355,7 @@ static int __maybe_unused xhci_histb_resume(struct device *dev)
if (!device_may_wakeup(dev))
xhci_histb_host_enable(histb);
return xhci_resume(xhci, PMSG_RESUME);
return xhci_resume(xhci, false, false);
}
static const struct dev_pm_ops xhci_histb_pm_ops = {

View File

@@ -1953,7 +1953,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->interrupters = NULL;
xhci->page_size = 0;
xhci->page_shift = 0;
xhci->usb2_rhub.bus_state.bus_suspended = 0;
xhci->usb3_rhub.bus_state.bus_suspended = 0;
}
@@ -2372,6 +2371,22 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
}
EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
static void xhci_hcd_page_size(struct xhci_hcd *xhci)
{
u32 page_size;
page_size = readl(&xhci->op_regs->page_size) & XHCI_PAGE_SIZE_MASK;
if (!is_power_of_2(page_size)) {
xhci_warn(xhci, "Invalid page size register = 0x%x\n", page_size);
/* Fallback to 4K page size, since that's common */
page_size = 1;
}
xhci->page_size = page_size << 12;
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "HCD page size set to %iK",
xhci->page_size >> 10);
}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
struct xhci_interrupter *ir;
@@ -2379,7 +2394,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
dma_addr_t dma;
unsigned int val, val2;
u64 val_64;
u32 page_size, temp;
u32 temp;
int i;
INIT_LIST_HEAD(&xhci->cmd_list);
@@ -2388,20 +2403,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout);
init_completion(&xhci->cmd_ring_stop_completion);
page_size = readl(&xhci->op_regs->page_size);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Supported page size register = 0x%x", page_size);
i = ffs(page_size);
if (i < 16)
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Supported page size of %iK", (1 << (i+12)) / 1024);
else
xhci_warn(xhci, "WARN: no supported page size\n");
/* Use 4K pages, since that's common and the minimum the HC supports */
xhci->page_shift = 12;
xhci->page_size = 1 << xhci->page_shift;
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"HCD page size set to %iK", xhci->page_size / 1024);
xhci_hcd_page_size(xhci);
/*
* Program the Number of Device Slots Enabled field in the CONFIG

View File

@@ -73,13 +73,3 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
return 0;
}
int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
/* Without reset on resume, the HC won't work at all */
xhci->quirks |= XHCI_RESET_ON_RESUME;
return 0;
}

View File

@@ -12,16 +12,10 @@ struct usb_hcd;
#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd);
#else
static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
{
return 0;
}
static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
{
return 0;
}
#endif
#endif /* __LINUX_XHCI_MVEBU_H */

View File

@@ -807,8 +807,10 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
static int xhci_pci_resume(struct usb_hcd *hcd, pm_message_t msg)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
bool power_lost = msg.event == PM_EVENT_RESTORE;
bool is_auto_resume = msg.event == PM_EVENT_AUTO_RESUME;
reset_control_reset(xhci->reset);
@@ -839,7 +841,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, pm_message_t msg)
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
xhci_pme_quirk(hcd);
return xhci_resume(xhci, msg);
return xhci_resume(xhci, power_lost, is_auto_resume);
}
static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup)

View File

@@ -106,7 +106,7 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = {
};
static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
.init_quirk = xhci_mvebu_a3700_init_quirk,
.quirks = XHCI_RESET_ON_RESUME,
};
static const struct xhci_plat_priv xhci_plat_brcm = {
@@ -479,9 +479,10 @@ static int xhci_plat_suspend(struct device *dev)
return 0;
}
static int xhci_plat_resume_common(struct device *dev, struct pm_message pmsg)
static int xhci_plat_resume_common(struct device *dev, bool power_lost)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int ret;
@@ -501,7 +502,7 @@ static int xhci_plat_resume_common(struct device *dev, struct pm_message pmsg)
if (ret)
goto disable_clks;
ret = xhci_resume(xhci, pmsg);
ret = xhci_resume(xhci, power_lost || priv->power_lost, false);
if (ret)
goto disable_clks;
@@ -522,12 +523,12 @@ static int xhci_plat_resume_common(struct device *dev, struct pm_message pmsg)
static int xhci_plat_resume(struct device *dev)
{
return xhci_plat_resume_common(dev, PMSG_RESUME);
return xhci_plat_resume_common(dev, false);
}
static int xhci_plat_restore(struct device *dev)
{
return xhci_plat_resume_common(dev, PMSG_RESTORE);
return xhci_plat_resume_common(dev, true);
}
static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev)
@@ -548,7 +549,7 @@ static int __maybe_unused xhci_plat_runtime_resume(struct device *dev)
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
return xhci_resume(xhci, PMSG_AUTO_RESUME);
return xhci_resume(xhci, false, true);
}
const struct dev_pm_ops xhci_plat_pm_ops = {

View File

@@ -15,6 +15,7 @@ struct usb_hcd;
struct xhci_plat_priv {
const char *firmware_name;
unsigned long long quirks;
bool power_lost;
void (*plat_start)(struct usb_hcd *);
int (*init_quirk)(struct usb_hcd *);
int (*suspend_quirk)(struct usb_hcd *);

View File

@@ -203,6 +203,50 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
return;
}
/*
* If enqueue points at a link TRB, follow links until an ordinary TRB is reached.
* Toggle the cycle bit of passed link TRBs and optionally chain them.
*/
static void inc_enq_past_link(struct xhci_hcd *xhci, struct xhci_ring *ring, u32 chain)
{
unsigned int link_trb_count = 0;
while (trb_is_link(ring->enqueue)) {
/*
* Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
* set, but other sections talk about dealing with the chain bit set. This was
* fixed in the 0.96 specification errata, but we have to assume that all 0.95
* xHCI hardware can't handle the chain bit being cleared on a link TRB.
*
* On 0.95 and some 0.96 HCs the chain bit is set once at segment initalization
* and never changed here. On all others, modify it as requested by the caller.
*/
if (!xhci_link_chain_quirk(xhci, ring->type)) {
ring->enqueue->link.control &= cpu_to_le32(~TRB_CHAIN);
ring->enqueue->link.control |= cpu_to_le32(chain);
}
/* Give this link TRB to the hardware */
wmb();
ring->enqueue->link.control ^= cpu_to_le32(TRB_CYCLE);
/* Toggle the cycle bit after the last ring segment. */
if (link_trb_toggles_cycle(ring->enqueue))
ring->cycle_state ^= 1;
ring->enq_seg = ring->enq_seg->next;
ring->enqueue = ring->enq_seg->trbs;
trace_xhci_inc_enq(ring);
if (link_trb_count++ > ring->num_segs) {
xhci_warn(xhci, "Link TRB loop at enqueue\n");
break;
}
}
}
/*
* See Cycle bit rules. SW is the consumer for the event ring only.
*
@@ -211,11 +255,6 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
* If we've enqueued the last TRB in a TD, make sure the following link TRBs
* have their chain bit cleared (so that each Link TRB is a separate TD).
*
* Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
* set, but other sections talk about dealing with the chain bit set. This was
* fixed in the 0.96 specification errata, but we have to assume that all 0.95
* xHCI hardware can't handle the chain bit being cleared on a link TRB.
*
* @more_trbs_coming: Will you enqueue more TRBs before calling
* prepare_transfer()?
*/
@@ -223,8 +262,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
bool more_trbs_coming)
{
u32 chain;
union xhci_trb *next;
unsigned int link_trb_count = 0;
chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
@@ -233,48 +270,67 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
return;
}
next = ++(ring->enqueue);
ring->enqueue++;
/* Update the dequeue pointer further if that was a link TRB */
while (trb_is_link(next)) {
/*
* If we are in the middle of a TD or the caller plans to enqueue more
* TDs as one transfer (eg. control), traverse any link TRBs right now.
* Otherwise, enqueue can stay on a link until the next prepare_ring().
* This avoids enqueue entering deq_seg and simplifies ring expansion.
*/
if (trb_is_link(ring->enqueue) && (chain || more_trbs_coming))
inc_enq_past_link(xhci, ring, chain);
}
/*
* 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;
/*
* If the suspect DMA address is a TRB in this TD, this function returns that
* TRB's segment. Otherwise it returns 0.
*/
static struct xhci_segment *trb_in_td(struct xhci_td *td, dma_addr_t suspect_dma)
{
dma_addr_t start_dma;
dma_addr_t end_seg_dma;
dma_addr_t end_trb_dma;
struct xhci_segment *cur_seg;
/* 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 (!xhci_link_chain_quirk(xhci, ring->type)) {
next->link.control &= cpu_to_le32(~TRB_CHAIN);
next->link.control |= cpu_to_le32(chain);
start_dma = xhci_trb_virt_to_dma(td->start_seg, td->start_trb);
cur_seg = td->start_seg;
do {
if (start_dma == 0)
return NULL;
/* We may get an event for a Link TRB in the middle of a TD */
end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
&cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
/* If the end TRB isn't in this segment, this is set to 0 */
end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->end_trb);
if (end_trb_dma > 0) {
/* The end TRB is in this segment, so suspect should be here */
if (start_dma <= end_trb_dma) {
if (suspect_dma >= start_dma && suspect_dma <= end_trb_dma)
return cur_seg;
} else {
/* Case for one segment with
* a TD wrapped around to the top
*/
if ((suspect_dma >= start_dma &&
suspect_dma <= end_seg_dma) ||
(suspect_dma >= cur_seg->dma &&
suspect_dma <= end_trb_dma))
return cur_seg;
}
return NULL;
}
/* Give this link TRB to the hardware */
wmb();
next->link.control ^= cpu_to_le32(TRB_CYCLE);
/* Might still be somewhere in this segment */
if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma)
return cur_seg;
/* Toggle the cycle bit after the last ring segment. */
if (link_trb_toggles_cycle(next))
ring->cycle_state ^= 1;
cur_seg = cur_seg->next;
start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
} while (cur_seg != td->start_seg);
ring->enq_seg = ring->enq_seg->next;
ring->enqueue = ring->enq_seg->trbs;
next = ring->enqueue;
trace_xhci_inc_enq(ring);
if (link_trb_count++ > ring->num_segs) {
xhci_warn(xhci, "%s: Ring link TRB loop\n", __func__);
break;
}
}
return NULL;
}
/*
@@ -505,8 +561,8 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
* pointer command pending because the device can choose to start any
* stream once the endpoint is on the HW schedule.
*/
if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) ||
(ep_state & EP_HALTED) || (ep_state & EP_CLEARING_TT))
if (ep_state & (EP_STOP_CMD_PENDING | SET_DEQ_PENDING | EP_HALTED |
EP_CLEARING_TT | EP_STALLED))
return;
trace_xhci_ring_ep_doorbell(slot_id, DB_VALUE(ep_index, stream_id));
@@ -1014,7 +1070,7 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep)
td->urb->stream_id);
hw_deq &= ~0xf;
if (td->cancel_status == TD_HALTED || trb_in_td(xhci, td, hw_deq, false)) {
if (td->cancel_status == TD_HALTED || trb_in_td(td, hw_deq)) {
switch (td->cancel_status) {
case TD_CLEARED: /* TD is already no-op */
case TD_CLEARING_CACHE: /* set TR deq command already queued */
@@ -1104,7 +1160,7 @@ static struct xhci_td *find_halted_td(struct xhci_virt_ep *ep)
hw_deq = xhci_get_hw_deq(ep->xhci, ep->vdev, ep->ep_index, 0);
hw_deq &= ~0xf;
td = list_first_entry(&ep->ring->td_list, struct xhci_td, td_list);
if (trb_in_td(ep->xhci, td, hw_deq, false))
if (trb_in_td(td, hw_deq))
return td;
}
return NULL;
@@ -1164,7 +1220,14 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
*/
switch (GET_EP_CTX_STATE(ep_ctx)) {
case EP_STATE_HALTED:
xhci_dbg(xhci, "Stop ep completion raced with stall, reset ep\n");
xhci_dbg(xhci, "Stop ep completion raced with stall\n");
/*
* If the halt happened before Stop Endpoint failed, its transfer event
* should have already been handled and Reset Endpoint should be pending.
*/
if (ep->ep_state & EP_HALTED)
goto reset_done;
if (ep->ep_state & EP_HAS_STREAMS) {
reset_type = EP_SOFT_RESET;
} else {
@@ -1175,8 +1238,11 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
}
/* reset ep, reset handler cleans up cancelled tds */
err = xhci_handle_halted_endpoint(xhci, ep, td, reset_type);
xhci_dbg(xhci, "Stop ep completion resetting ep, status %d\n", err);
if (err)
break;
reset_done:
/* Reset EP handler will clean up cancelled TDs */
ep->ep_state &= ~EP_STOP_CMD_PENDING;
return;
case EP_STATE_STOPPED:
@@ -1198,16 +1264,19 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,
* Stopped state, but it will soon change to Running.
*
* Assume this bug on unexpected Stop Endpoint failures.
* Keep retrying until the EP starts and stops again, on
* chips where this is known to help. Wait for 100ms.
* Keep retrying until the EP starts and stops again.
*/
if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100)))
break;
fallthrough;
case EP_STATE_RUNNING:
/* Race, HW handled stop ep cmd before ep was running */
xhci_dbg(xhci, "Stop ep completion ctx error, ctx_state %d\n",
GET_EP_CTX_STATE(ep_ctx));
/*
* Don't retry forever if we guessed wrong or a defective HC never starts
* the EP or says 'Running' but fails the command. We must give back TDs.
*/
if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100)))
break;
command = xhci_alloc_command(xhci, false, GFP_ATOMIC);
if (!command) {
@@ -1332,43 +1401,6 @@ void xhci_hc_died(struct xhci_hcd *xhci)
usb_hc_died(xhci_to_hcd(xhci));
}
static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
struct xhci_virt_device *dev,
struct xhci_ring *ep_ring,
unsigned int ep_index)
{
union xhci_trb *dequeue_temp;
dequeue_temp = ep_ring->dequeue;
/* If we get two back-to-back stalls, and the first stalled transfer
* ends just before a link TRB, the dequeue pointer will be left on
* the link TRB by the code in the while loop. So we have to update
* the dequeue pointer one segment further, or we'll jump off
* the segment into la-la-land.
*/
if (trb_is_link(ep_ring->dequeue)) {
ep_ring->deq_seg = ep_ring->deq_seg->next;
ep_ring->dequeue = ep_ring->deq_seg->trbs;
}
while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
/* We have more usable TRBs */
ep_ring->dequeue++;
if (trb_is_link(ep_ring->dequeue)) {
if (ep_ring->dequeue ==
dev->eps[ep_index].queued_deq_ptr)
break;
ep_ring->deq_seg = ep_ring->deq_seg->next;
ep_ring->dequeue = ep_ring->deq_seg->trbs;
}
if (ep_ring->dequeue == dequeue_temp) {
xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
break;
}
}
}
/*
* When we get a completion for a Set Transfer Ring Dequeue Pointer command,
* we need to clear the set deq pending flag in the endpoint ring state, so that
@@ -1473,8 +1505,8 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
/* Update the ring's dequeue segment and dequeue pointer
* to reflect the new position.
*/
update_ring_for_set_deq_completion(xhci, ep->vdev,
ep_ring, ep_index);
ep_ring->deq_seg = ep->queued_deq_seg;
ep_ring->dequeue = ep->queued_deq_ptr;
} else {
xhci_warn(xhci, "Mismatch between completed Set TR Deq Ptr command & xHCI internal state.\n");
xhci_warn(xhci, "ep deq seg = %p, deq ptr = %p\n",
@@ -2116,67 +2148,6 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event)
spin_lock(&xhci->lock);
}
/*
* If the suspect DMA address is a TRB in this TD, this function returns that
* TRB's segment. Otherwise it returns 0.
*/
struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, dma_addr_t suspect_dma,
bool debug)
{
dma_addr_t start_dma;
dma_addr_t end_seg_dma;
dma_addr_t end_trb_dma;
struct xhci_segment *cur_seg;
start_dma = xhci_trb_virt_to_dma(td->start_seg, td->start_trb);
cur_seg = td->start_seg;
do {
if (start_dma == 0)
return NULL;
/* We may get an event for a Link TRB in the middle of a TD */
end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
&cur_seg->trbs[TRBS_PER_SEGMENT - 1]);
/* If the end TRB isn't in this segment, this is set to 0 */
end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->end_trb);
if (debug)
xhci_warn(xhci,
"Looking for event-dma %016llx trb-start %016llx trb-end %016llx seg-start %016llx seg-end %016llx\n",
(unsigned long long)suspect_dma,
(unsigned long long)start_dma,
(unsigned long long)end_trb_dma,
(unsigned long long)cur_seg->dma,
(unsigned long long)end_seg_dma);
if (end_trb_dma > 0) {
/* The end TRB is in this segment, so suspect should be here */
if (start_dma <= end_trb_dma) {
if (suspect_dma >= start_dma && suspect_dma <= end_trb_dma)
return cur_seg;
} else {
/* Case for one segment with
* a TD wrapped around to the top
*/
if ((suspect_dma >= start_dma &&
suspect_dma <= end_seg_dma) ||
(suspect_dma >= cur_seg->dma &&
suspect_dma <= end_trb_dma))
return cur_seg;
}
return NULL;
} else {
/* Might still be somewhere in this segment */
if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma)
return cur_seg;
}
cur_seg = cur_seg->next;
start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
} while (cur_seg != td->start_seg);
return NULL;
}
static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td,
struct xhci_virt_ep *ep)
{
@@ -2476,6 +2447,12 @@ static void process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
if (ep_trb != td->end_trb)
td->error_mid_td = true;
break;
case COMP_MISSED_SERVICE_ERROR:
frame->status = -EXDEV;
sum_trbs_for_length = true;
if (ep_trb != td->end_trb)
td->error_mid_td = true;
break;
case COMP_INCOMPATIBLE_DEVICE_ERROR:
case COMP_STALL_ERROR:
frame->status = -EPROTO;
@@ -2596,6 +2573,9 @@ static void process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep,
xhci_handle_halted_endpoint(xhci, ep, td, EP_SOFT_RESET);
return;
case COMP_STALL_ERROR:
ep->ep_state |= EP_STALLED;
break;
default:
/* do nothing */
break;
@@ -2644,6 +2624,22 @@ static int handle_transferless_tx_event(struct xhci_hcd *xhci, struct xhci_virt_
return 0;
}
static bool xhci_spurious_success_tx_event(struct xhci_hcd *xhci,
struct xhci_ring *ring)
{
switch (ring->old_trb_comp_code) {
case COMP_SHORT_PACKET:
return xhci->quirks & XHCI_SPURIOUS_SUCCESS;
case COMP_USB_TRANSACTION_ERROR:
case COMP_BABBLE_DETECTED_ERROR:
case COMP_ISOCH_BUFFER_OVERRUN:
return xhci->quirks & XHCI_ETRON_HOST &&
ring->type == TYPE_ISOC;
default:
return false;
}
}
/*
* If this function returns an error condition, it means it got a Transfer
* event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
@@ -2664,6 +2660,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
int status = -EINPROGRESS;
struct xhci_ep_ctx *ep_ctx;
u32 trb_comp_code;
bool ring_xrun_event = false;
slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));
ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1;
@@ -2697,8 +2694,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
case COMP_SUCCESS:
if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
trb_comp_code = COMP_SHORT_PACKET;
xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td short %d\n",
slot_id, ep_index, ep_ring->last_td_was_short);
xhci_dbg(xhci, "Successful completion on short TX for slot %u ep %u with last td comp code %d\n",
slot_id, ep_index, ep_ring->old_trb_comp_code);
}
break;
case COMP_SHORT_PACKET:
@@ -2770,14 +2767,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* Underrun Event for OUT Isoch endpoint.
*/
xhci_dbg(xhci, "Underrun event on slot %u ep %u\n", slot_id, ep_index);
if (ep->skip)
break;
return 0;
ring_xrun_event = true;
break;
case COMP_RING_OVERRUN:
xhci_dbg(xhci, "Overrun event on slot %u ep %u\n", slot_id, ep_index);
if (ep->skip)
break;
return 0;
ring_xrun_event = true;
break;
case COMP_MISSED_SERVICE_ERROR:
/*
* When encounter missed service error, one or more isoc tds
@@ -2787,9 +2782,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
*/
ep->skip = true;
xhci_dbg(xhci,
"Miss service interval error for slot %u ep %u, set skip flag\n",
slot_id, ep_index);
return 0;
"Miss service interval error for slot %u ep %u, set skip flag%s\n",
slot_id, ep_index, ep_trb_dma ? ", skip now" : "");
break;
case COMP_NO_PING_RESPONSE_ERROR:
ep->skip = true;
xhci_dbg(xhci,
@@ -2832,11 +2827,15 @@ static int handle_tx_event(struct xhci_hcd *xhci,
*/
td = list_first_entry_or_null(&ep_ring->td_list, struct xhci_td, td_list);
if (td && td->error_mid_td && !trb_in_td(xhci, td, ep_trb_dma, false)) {
if (td && td->error_mid_td && !trb_in_td(td, ep_trb_dma)) {
xhci_dbg(xhci, "Missing TD completion event after mid TD error\n");
xhci_dequeue_td(xhci, td, ep_ring, td->status);
}
/* If the TRB pointer is NULL, missed TDs will be skipped on the next event */
if (trb_comp_code == COMP_MISSED_SERVICE_ERROR && !ep_trb_dma)
return 0;
if (list_empty(&ep_ring->td_list)) {
/*
* Don't print wanings if ring is empty due to a stopped endpoint generating an
@@ -2846,7 +2845,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
*/
if (trb_comp_code != COMP_STOPPED &&
trb_comp_code != COMP_STOPPED_LENGTH_INVALID &&
!ep_ring->last_td_was_short) {
!ring_xrun_event &&
!xhci_spurious_success_tx_event(xhci, ep_ring)) {
xhci_warn(xhci, "Event TRB for slot %u ep %u with no TDs queued\n",
slot_id, ep_index);
}
@@ -2860,14 +2860,31 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td_list);
/* Is this a TRB in the currently executing TD? */
ep_seg = trb_in_td(xhci, td, ep_trb_dma, false);
ep_seg = trb_in_td(td, ep_trb_dma);
if (!ep_seg) {
if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
/* this event is unlikely to match any TD, don't skip them all */
if (trb_comp_code == COMP_STOPPED_LENGTH_INVALID)
return 0;
skip_isoc_td(xhci, td, ep, status);
if (!list_empty(&ep_ring->td_list))
if (!list_empty(&ep_ring->td_list)) {
if (ring_xrun_event) {
/*
* If we are here, we are on xHCI 1.0 host with no
* idea how many TDs were missed or where the xrun
* occurred. New TDs may have been added after the
* xrun, so skip only one TD to be safe.
*/
xhci_dbg(xhci, "Skipped one TD for slot %u ep %u",
slot_id, ep_index);
return 0;
}
continue;
}
xhci_dbg(xhci, "All TDs skipped for slot %u ep %u. Clear skip flag.\n",
slot_id, ep_index);
@@ -2876,6 +2893,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
goto check_endpoint_halted;
}
/* TD was queued after xrun, maybe xrun was on a link, don't panic yet */
if (ring_xrun_event)
return 0;
/*
* Skip the Force Stopped Event. The 'ep_trb' of FSE is not in the current
* TD pointed by 'ep_ring->dequeue' because that the hardware dequeue
@@ -2890,21 +2911,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/*
* Some hosts give a spurious success event after a short
* transfer. Ignore it.
* transfer or error on last TRB. Ignore it.
*/
if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&
ep_ring->last_td_was_short) {
ep_ring->last_td_was_short = false;
if (xhci_spurious_success_tx_event(xhci, ep_ring)) {
xhci_dbg(xhci, "Spurious event dma %pad, comp_code %u after %u\n",
&ep_trb_dma, trb_comp_code, ep_ring->old_trb_comp_code);
ep_ring->old_trb_comp_code = trb_comp_code;
return 0;
}
/* HC is busted, give up! */
xhci_err(xhci,
"ERROR Transfer event TRB DMA ptr not part of current TD ep_index %d comp_code %u\n",
ep_index, trb_comp_code);
trb_in_td(xhci, td, ep_trb_dma, true);
return -ESHUTDOWN;
goto debug_finding_td;
}
if (ep->skip) {
@@ -2922,10 +2939,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
*/
} while (ep->skip);
if (trb_comp_code == COMP_SHORT_PACKET)
ep_ring->last_td_was_short = true;
else
ep_ring->last_td_was_short = false;
ep_ring->old_trb_comp_code = trb_comp_code;
/* Get out if a TD was queued at enqueue after the xrun occurred */
if (ring_xrun_event)
return 0;
ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb, ep_trb_dma);
@@ -2957,6 +2975,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
return 0;
debug_finding_td:
xhci_err(xhci, "Event dma %pad for ep %d status %d not part of TD at %016llx - %016llx\n",
&ep_trb_dma, ep_index, trb_comp_code,
(unsigned long long)xhci_trb_virt_to_dma(td->start_seg, td->start_trb),
(unsigned long long)xhci_trb_virt_to_dma(td->end_seg, td->end_trb));
xhci_for_each_ring_seg(ep_ring->first_seg, ep_seg)
xhci_warn(xhci, "Ring seg %u dma %pad\n", ep_seg->num, &ep_seg->dma);
return -ESHUTDOWN;
err_out:
xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
(unsigned long long) xhci_trb_virt_to_dma(
@@ -3216,7 +3245,6 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
{
unsigned int link_trb_count = 0;
unsigned int new_segs = 0;
/* Make sure the endpoint has been added to xHC schedule */
@@ -3264,33 +3292,9 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
}
}
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_chain_quirk(xhci, ep_ring->type))
ep_ring->enqueue->link.control &=
cpu_to_le32(~TRB_CHAIN);
else
ep_ring->enqueue->link.control |=
cpu_to_le32(TRB_CHAIN);
wmb();
ep_ring->enqueue->link.control ^= cpu_to_le32(TRB_CYCLE);
/* Toggle the cycle bit after the last ring segment. */
if (link_trb_toggles_cycle(ep_ring->enqueue))
ep_ring->cycle_state ^= 1;
ep_ring->enq_seg = ep_ring->enq_seg->next;
ep_ring->enqueue = ep_ring->enq_seg->trbs;
/* prevent infinite loop if all first trbs are link trbs */
if (link_trb_count++ > ep_ring->num_segs) {
xhci_warn(xhci, "Ring is an endless link TRB loop\n");
return -EINVAL;
}
}
/* Ensure that new TRBs won't overwrite a link */
if (trb_is_link(ep_ring->enqueue))
inc_enq_past_link(xhci, ep_ring, 0);
if (last_trb_on_seg(ep_ring->enq_seg, ep_ring->enqueue)) {
xhci_warn(xhci, "Missing link TRB at end of ring segment\n");

View File

@@ -2162,11 +2162,11 @@ static void tegra_xhci_program_utmi_power_lp0_exit(struct tegra_xusb *tegra)
}
}
static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime)
static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool is_auto_resume)
{
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
struct device *dev = tegra->dev;
bool wakeup = runtime ? true : device_may_wakeup(dev);
bool wakeup = is_auto_resume ? true : device_may_wakeup(dev);
unsigned int i;
int err;
u32 usbcmd;
@@ -2232,11 +2232,11 @@ static int tegra_xusb_enter_elpg(struct tegra_xusb *tegra, bool runtime)
return err;
}
static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool runtime)
static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool is_auto_resume)
{
struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
struct device *dev = tegra->dev;
bool wakeup = runtime ? true : device_may_wakeup(dev);
bool wakeup = is_auto_resume ? true : device_may_wakeup(dev);
unsigned int i;
u32 usbcmd;
int err;
@@ -2287,7 +2287,7 @@ static int tegra_xusb_exit_elpg(struct tegra_xusb *tegra, bool runtime)
if (wakeup)
tegra_xhci_disable_phy_sleepwalk(tegra);
err = xhci_resume(xhci, runtime ? PMSG_AUTO_RESUME : PMSG_RESUME);
err = xhci_resume(xhci, false, is_auto_resume);
if (err < 0) {
dev_err(tegra->dev, "failed to resume XHCI: %d\n", err);
goto disable_phy;

View File

@@ -994,16 +994,14 @@ EXPORT_SYMBOL_GPL(xhci_suspend);
* This is called when the machine transition from S3/S4 mode.
*
*/
int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg)
int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume)
{
bool hibernated = (msg.event == PM_EVENT_RESTORE);
u32 command, temp = 0;
struct usb_hcd *hcd = xhci_to_hcd(xhci);
int retval = 0;
bool comp_timer_running = false;
bool pending_portevent = false;
bool suspended_usb3_devs = false;
bool reinit_xhc = false;
if (!hcd->state)
return 0;
@@ -1022,10 +1020,10 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg)
spin_lock_irq(&xhci->lock);
if (hibernated || xhci->quirks & XHCI_RESET_ON_RESUME || xhci->broken_suspend)
reinit_xhc = true;
if (xhci->quirks & XHCI_RESET_ON_RESUME || xhci->broken_suspend)
power_lost = true;
if (!reinit_xhc) {
if (!power_lost) {
/*
* Some controllers might lose power during suspend, so wait
* for controller not ready bit to clear, just as in xHC init.
@@ -1065,12 +1063,12 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg)
/* re-initialize the HC on Restore Error, or Host Controller Error */
if ((temp & (STS_SRE | STS_HCE)) &&
!(xhci->xhc_state & XHCI_STATE_REMOVING)) {
reinit_xhc = true;
if (!xhci->broken_suspend)
if (!power_lost)
xhci_warn(xhci, "xHC error in resume, USBSTS 0x%x, Reinit\n", temp);
power_lost = true;
}
if (reinit_xhc) {
if (power_lost) {
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
!(xhci_all_ports_seen_u0(xhci))) {
del_timer_sync(&xhci->comp_mode_recovery_timer);
@@ -1168,8 +1166,7 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg)
pending_portevent = xhci_pending_portevent(xhci);
if (suspended_usb3_devs && !pending_portevent &&
msg.event == PM_EVENT_AUTO_RESUME) {
if (suspended_usb3_devs && !pending_portevent && is_auto_resume) {
msleep(120);
pending_portevent = xhci_pending_portevent(xhci);
}
@@ -1608,6 +1605,11 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
goto free_priv;
}
/* Class driver might not be aware ep halted due to async URB giveback */
if (*ep_state & EP_STALLED)
dev_dbg(&urb->dev->dev, "URB %p queued before clearing halt\n",
urb);
switch (usb_endpoint_type(&urb->ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
@@ -1768,8 +1770,8 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
goto done;
}
/* In this case no commands are pending but the endpoint is stopped */
if (ep->ep_state & EP_CLEARING_TT) {
/* In these cases no commands are pending but the endpoint is stopped */
if (ep->ep_state & (EP_CLEARING_TT | EP_STALLED)) {
/* and cancelled TDs can be given back right away */
xhci_dbg(xhci, "Invalidating TDs instantly on slot %d ep %d in state 0x%x\n",
urb->dev->slot_id, ep_index, ep->ep_state);
@@ -3207,8 +3209,11 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
ep = &vdev->eps[ep_index];
/* Bail out if toggle is already being cleared by a endpoint reset */
spin_lock_irqsave(&xhci->lock, flags);
ep->ep_state &= ~EP_STALLED;
/* Bail out if toggle is already being cleared by a endpoint reset */
if (ep->ep_state & EP_HARD_CLEAR_TOGGLE) {
ep->ep_state &= ~EP_HARD_CLEAR_TOGGLE;
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -4759,8 +4764,8 @@ static u16 xhci_calculate_u1_timeout(struct xhci_hcd *xhci,
*/
if (timeout_ns <= USB3_LPM_U1_MAX_TIMEOUT)
return timeout_ns;
dev_dbg(&udev->dev, "Hub-initiated U1 disabled "
"due to long timeout %llu ms\n", timeout_ns);
dev_dbg(&udev->dev, "Hub-initiated U1 disabled due to long timeout %lluus\n",
timeout_ns);
return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1);
}
@@ -4817,8 +4822,8 @@ static u16 xhci_calculate_u2_timeout(struct xhci_hcd *xhci,
*/
if (timeout_ns <= USB3_LPM_U2_MAX_TIMEOUT)
return timeout_ns;
dev_dbg(&udev->dev, "Hub-initiated U2 disabled "
"due to long timeout %llu ms\n", timeout_ns);
dev_dbg(&udev->dev, "Hub-initiated U2 disabled due to long timeout %lluus\n",
timeout_ns * 256);
return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U2);
}

View File

@@ -211,6 +211,9 @@ struct xhci_op_regs {
#define CONFIG_CIE (1 << 9)
/* bits 10:31 - reserved and should be preserved */
/* bits 15:0 - HCD page shift bit */
#define XHCI_PAGE_SIZE_MASK 0xffff
/**
* struct xhci_intr_reg - Interrupt Register Set
* @irq_pending: IMAN - Interrupt Management Register. Used to enable
@@ -661,7 +664,7 @@ struct xhci_virt_ep {
unsigned int err_count;
unsigned int ep_state;
#define SET_DEQ_PENDING (1 << 0)
#define EP_HALTED (1 << 1) /* For stall handling */
#define EP_HALTED (1 << 1) /* Halted host ep handling */
#define EP_STOP_CMD_PENDING (1 << 2) /* For URB cancellation */
/* Transitioning the endpoint to using streams, don't enqueue URBs */
#define EP_GETTING_STREAMS (1 << 3)
@@ -672,6 +675,7 @@ struct xhci_virt_ep {
#define EP_SOFT_CLEAR_TOGGLE (1 << 7)
/* usb_hub_clear_tt_buffer is in progress */
#define EP_CLEARING_TT (1 << 8)
#define EP_STALLED (1 << 9) /* For stall handling */
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
struct xhci_hcd *xhci;
@@ -1371,7 +1375,7 @@ struct xhci_ring {
unsigned int num_trbs_free; /* used only by xhci DbC */
unsigned int bounce_buf_len;
enum xhci_ring_type type;
bool last_td_was_short;
u32 old_trb_comp_code;
struct radix_tree_root *trb_address_map;
};
@@ -1514,10 +1518,7 @@ struct xhci_hcd {
u16 max_interrupters;
/* imod_interval in ns (I * 250ns) */
u32 imod_interval;
/* 4KB min, 128MB max */
int page_size;
/* Valid values are 12 to 20, inclusive */
int page_shift;
u32 page_size;
/* MSI-X/MSI vectors */
int nvecs;
/* optional clocks */
@@ -1759,11 +1760,20 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
}
/* Link TRB chain should always be set on 0.95 hosts, and AMD 0.96 ISOC rings */
/*
* Reportedly, some chapters of v0.95 spec said that Link TRB always has its chain bit set.
* Other chapters and later specs say that it should only be set if the link is inside a TD
* which continues from the end of one segment to the next segment.
*
* Some 0.95 hardware was found to misbehave if any link TRB doesn't have the chain bit set.
*
* 0.96 hardware from AMD and NEC was found to ignore unchained isochronous link TRBs when
* "resynchronizing the pipe" after a Missed Service Error.
*/
static inline bool xhci_link_chain_quirk(struct xhci_hcd *xhci, enum xhci_ring_type type)
{
return (xhci->quirks & XHCI_LINK_TRB_QUIRK) ||
(type == TYPE_ISOC && (xhci->quirks & XHCI_AMD_0x96_HOST));
(type == TYPE_ISOC && (xhci->quirks & (XHCI_AMD_0x96_HOST | XHCI_NEC_HOST)));
}
/* xHCI debugging */
@@ -1870,7 +1880,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
int xhci_ext_cap_init(struct xhci_hcd *xhci);
int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg);
int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume);
irqreturn_t xhci_irq(struct usb_hcd *hcd);
irqreturn_t xhci_msi_irq(int irq, void *hcd);
@@ -1884,8 +1894,6 @@ int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
/* xHCI ring, segment, TRB, and TD functions */
dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td,
dma_addr_t suspect_dma, bool debug);
int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
void xhci_ring_cmd_db(struct xhci_hcd *xhci);
int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd,

View File

@@ -23,6 +23,13 @@ static const struct onboard_dev_pdata microchip_usb424_data = {
.is_hub = true,
};
static const struct onboard_dev_pdata microchip_usb2514_data = {
.reset_us = 1,
.num_supplies = 2,
.supply_names = { "vdd", "vdda" },
.is_hub = true,
};
static const struct onboard_dev_pdata microchip_usb5744_data = {
.reset_us = 0,
.power_on_delay_us = 10000,
@@ -96,7 +103,7 @@ static const struct onboard_dev_pdata xmos_xvf3500_data = {
static const struct of_device_id onboard_dev_match[] = {
{ .compatible = "usb424,2412", .data = &microchip_usb424_data, },
{ .compatible = "usb424,2514", .data = &microchip_usb424_data, },
{ .compatible = "usb424,2514", .data = &microchip_usb2514_data, },
{ .compatible = "usb424,2517", .data = &microchip_usb424_data, },
{ .compatible = "usb424,2744", .data = &microchip_usb5744_data, },
{ .compatible = "usb424,5744", .data = &microchip_usb5744_data, },

View File

@@ -636,10 +636,8 @@ static int usb251xb_probe(struct usb251xb *hub)
if (np && usb_data) {
err = usb251xb_get_ofdata(hub, usb_data);
if (err) {
dev_err(dev, "failed to get ofdata: %d\n", err);
return err;
}
if (err)
return dev_err_probe(dev, err, "failed to get ofdata\n");
}
/*

View File

@@ -59,7 +59,7 @@ static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
return IRQ_NONE;
}
static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
static const struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, },
@@ -205,7 +205,7 @@ static const struct musb_hdrc_platform_data jz4740_musb_pdata = {
.platform_ops = &jz4740_musb_ops,
};
static struct musb_fifo_cfg jz4770_musb_fifo_cfg[] = {
static const struct musb_fifo_cfg jz4770_musb_fifo_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },

View File

@@ -365,7 +365,7 @@ static const struct musb_platform_ops mtk_musb_ops = {
#define MTK_MUSB_MAX_EP_NUM 8
#define MTK_MUSB_RAM_BITS 11
static struct musb_fifo_cfg mtk_musb_mode_cfg[] = {
static const struct musb_fifo_cfg mtk_musb_mode_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },

View File

@@ -29,7 +29,7 @@ struct mpfs_glue {
struct clk *clk;
};
static struct musb_fifo_cfg mpfs_musb_mode_cfg[] = {
static const struct musb_fifo_cfg mpfs_musb_mode_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },

View File

@@ -1271,7 +1271,7 @@ MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");
*/
/* mode 0 - fits in 2KB */
static struct musb_fifo_cfg mode_0_cfg[] = {
static const struct musb_fifo_cfg mode_0_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },
@@ -1280,7 +1280,7 @@ static struct musb_fifo_cfg mode_0_cfg[] = {
};
/* mode 1 - fits in 4KB */
static struct musb_fifo_cfg mode_1_cfg[] = {
static const struct musb_fifo_cfg mode_1_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
@@ -1289,7 +1289,7 @@ static struct musb_fifo_cfg mode_1_cfg[] = {
};
/* mode 2 - fits in 4KB */
static struct musb_fifo_cfg mode_2_cfg[] = {
static const struct musb_fifo_cfg mode_2_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1299,7 +1299,7 @@ static struct musb_fifo_cfg mode_2_cfg[] = {
};
/* mode 3 - fits in 4KB */
static struct musb_fifo_cfg mode_3_cfg[] = {
static const struct musb_fifo_cfg mode_3_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1309,7 +1309,7 @@ static struct musb_fifo_cfg mode_3_cfg[] = {
};
/* mode 4 - fits in 16KB */
static struct musb_fifo_cfg mode_4_cfg[] = {
static const struct musb_fifo_cfg mode_4_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1340,7 +1340,7 @@ static struct musb_fifo_cfg mode_4_cfg[] = {
};
/* mode 5 - fits in 8KB */
static struct musb_fifo_cfg mode_5_cfg[] = {
static const struct musb_fifo_cfg mode_5_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1447,7 +1447,7 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0));
}
static struct musb_fifo_cfg ep0_cfg = {
static const struct musb_fifo_cfg ep0_cfg = {
.style = FIFO_RXTX, .maxpacket = 64,
};

View File

@@ -629,7 +629,7 @@ static const struct musb_platform_ops sunxi_musb_ops = {
#define SUNXI_MUSB_RAM_BITS 11
/* Allwinner OTG supports up to 5 endpoints */
static struct musb_fifo_cfg sunxi_musb_mode_cfg_5eps[] = {
static const struct musb_fifo_cfg sunxi_musb_mode_cfg_5eps[] = {
MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
@@ -643,7 +643,7 @@ static struct musb_fifo_cfg sunxi_musb_mode_cfg_5eps[] = {
};
/* H3/V3s OTG supports only 4 endpoints */
static struct musb_fifo_cfg sunxi_musb_mode_cfg_4eps[] = {
static const struct musb_fifo_cfg sunxi_musb_mode_cfg_4eps[] = {
MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),

View File

@@ -769,11 +769,9 @@ static int mxs_phy_probe(struct platform_device *pdev)
return PTR_ERR(base);
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev,
"can't get the clock, err=%ld", PTR_ERR(clk));
return PTR_ERR(clk);
}
if (IS_ERR(clk))
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
"can't get the clock\n");
mxs_phy = devm_kzalloc(&pdev->dev, sizeof(*mxs_phy), GFP_KERNEL);
if (!mxs_phy)

View File

@@ -255,29 +255,6 @@ static void otg_ulpi_init(struct usb_phy *phy, struct usb_otg *otg,
otg->set_vbus = ulpi_set_vbus;
}
struct usb_phy *
otg_ulpi_create(struct usb_phy_io_ops *ops,
unsigned int flags)
{
struct usb_phy *phy;
struct usb_otg *otg;
phy = kzalloc(sizeof(*phy), GFP_KERNEL);
if (!phy)
return NULL;
otg = kzalloc(sizeof(*otg), GFP_KERNEL);
if (!otg) {
kfree(phy);
return NULL;
}
otg_ulpi_init(phy, otg, ops, flags);
return phy;
}
EXPORT_SYMBOL_GPL(otg_ulpi_create);
struct usb_phy *
devm_otg_ulpi_create(struct device *dev,
struct usb_phy_io_ops *ops,

View File

@@ -66,29 +66,16 @@
#define MOS_WDR_TIMEOUT 5000 /* default urb timeout */
#define MOS_PORT1 0x0200
#define MOS_PORT2 0x0300
#define MOS_VENREG 0x0000
#define MOS_MAX_PORT 0x02
#define MOS_WRITE 0x0E
#define MOS_READ 0x0D
/* Requests */
#define MCS_RD_RTYPE 0xC0
#define MCS_WR_RTYPE 0x40
#define MCS_RDREQ 0x0D
#define MCS_WRREQ 0x0E
#define MCS_CTRL_TIMEOUT 500
#define VENDOR_READ_LENGTH (0x01)
#define MAX_NAME_LEN 64
#define ZLP_REG1 0x3A /* Zero_Flag_Reg1 58 */
#define ZLP_REG5 0x3E /* Zero_Flag_Reg5 62 */
/* For higher baud Rates use TIOCEXBAUD */
#define TIOCEXBAUD 0x5462
/*
* Vendor id and device id defines
*

View File

@@ -174,7 +174,7 @@ struct alauda_card_info {
unsigned char zoneshift; /* 1<<zs blocks per zone */
};
static struct alauda_card_info alauda_card_ids[] = {
static const struct alauda_card_info alauda_card_ids[] = {
/* NAND flash */
{ 0x6e, 20, 8, 4, 8}, /* 1 MB */
{ 0xe8, 20, 8, 4, 8}, /* 1 MB */
@@ -200,7 +200,7 @@ static struct alauda_card_info alauda_card_ids[] = {
{ 0,}
};
static struct alauda_card_info *alauda_card_find_id(unsigned char id)
static const struct alauda_card_info *alauda_card_find_id(unsigned char id)
{
int i;
@@ -383,7 +383,7 @@ static int alauda_init_media(struct us_data *us)
{
unsigned char *data = us->iobuf;
int ready = 0;
struct alauda_card_info *media_info;
const struct alauda_card_info *media_info;
unsigned int num_zones;
while (ready == 0) {
@@ -1132,7 +1132,7 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
int rc;
struct alauda_info *info = (struct alauda_info *) us->extra;
unsigned char *ptr = us->iobuf;
static unsigned char inquiry_response[36] = {
static const unsigned char inquiry_response[36] = {
0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
};

View File

@@ -319,7 +319,7 @@ static int datafab_determine_lun(struct us_data *us,
//
// There might be a better way of doing this?
static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
static const unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
unsigned char *command = us->iobuf;
unsigned char *buf;
int count = 0, rc;
@@ -384,7 +384,7 @@ static int datafab_id_device(struct us_data *us,
// to the ATA spec, 'Sector Count' isn't used but the Windows driver
// sets this bit so we do too...
//
static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
static const unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
unsigned char *command = us->iobuf;
unsigned char *reply;
int rc;
@@ -437,16 +437,16 @@ static int datafab_handle_mode_sense(struct us_data *us,
struct scsi_cmnd * srb,
int sense_6)
{
static unsigned char rw_err_page[12] = {
static const unsigned char rw_err_page[12] = {
0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
};
static unsigned char cache_page[12] = {
static const unsigned char cache_page[12] = {
0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static unsigned char rbac_page[12] = {
static const unsigned char rbac_page[12] = {
0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
};
static unsigned char timer_page[8] = {
static const unsigned char timer_page[8] = {
0x1C, 0x6, 0, 0, 0, 0
};
unsigned char pc, page_code;
@@ -550,7 +550,7 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
int rc;
unsigned long block, blocks;
unsigned char *ptr = us->iobuf;
static unsigned char inquiry_reply[8] = {
static const unsigned char inquiry_reply[8] = {
0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
};

View File

@@ -54,7 +54,7 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf;
int res;
unsigned int partial;
static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
static const char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
usb_stor_dbg(us, "Sending UCR-61S2B initialization packet...\n");

View File

@@ -367,16 +367,16 @@ static int jumpshot_handle_mode_sense(struct us_data *us,
struct scsi_cmnd * srb,
int sense_6)
{
static unsigned char rw_err_page[12] = {
static const unsigned char rw_err_page[12] = {
0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
};
static unsigned char cache_page[12] = {
static const unsigned char cache_page[12] = {
0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static unsigned char rbac_page[12] = {
static const unsigned char rbac_page[12] = {
0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
};
static unsigned char timer_page[8] = {
static const unsigned char timer_page[8] = {
0x1C, 0x6, 0, 0, 0, 0
};
unsigned char pc, page_code;
@@ -477,7 +477,7 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
int rc;
unsigned long block, blocks;
unsigned char *ptr = us->iobuf;
static unsigned char inquiry_response[8] = {
static const unsigned char inquiry_response[8] = {
0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
};

View File

@@ -191,7 +191,7 @@ MODULE_DEVICE_TABLE(usb, realtek_cr_ids);
.initFunction = init_function, \
}
static struct us_unusual_dev realtek_cr_unusual_dev_list[] = {
static const struct us_unusual_dev realtek_cr_unusual_dev_list[] = {
# include "unusual_realtek.h"
{} /* Terminating entry */
};
@@ -797,10 +797,10 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
{
struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
static int card_first_show = 1;
static u8 media_not_present[] = { 0x70, 0, 0x02, 0, 0, 0, 0,
static const u8 media_not_present[] = { 0x70, 0, 0x02, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0x3A, 0, 0, 0, 0, 0
};
static u8 invalid_cmd_field[] = { 0x70, 0, 0x05, 0, 0, 0, 0,
static const u8 invalid_cmd_field[] = { 0x70, 0, 0x05, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0x24, 0, 0, 0, 0, 0
};
int ret;

View File

@@ -144,7 +144,7 @@ static inline char *nand_flash_manufacturer(int manuf_id) {
* 256 MB NAND flash has a 5-byte ID with 2nd byte 0xaa, 0xba, 0xca or 0xda.
*/
static struct nand_flash_dev nand_flash_ids[] = {
static const struct nand_flash_dev nand_flash_ids[] = {
/* NAND flash */
{ 0x6e, 20, 8, 4, 8, 2}, /* 1 MB */
{ 0xe8, 20, 8, 4, 8, 2}, /* 1 MB */
@@ -169,7 +169,7 @@ static struct nand_flash_dev nand_flash_ids[] = {
{ 0,}
};
static struct nand_flash_dev *
static const struct nand_flash_dev *
nand_find_id(unsigned char id) {
int i;
@@ -1133,9 +1133,9 @@ sddr09_reset(struct us_data *us) {
}
#endif
static struct nand_flash_dev *
static const struct nand_flash_dev *
sddr09_get_cardinfo(struct us_data *us, unsigned char flags) {
struct nand_flash_dev *cardinfo;
const struct nand_flash_dev *cardinfo;
unsigned char deviceID[4];
char blurbtxt[256];
int result;
@@ -1545,12 +1545,12 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
struct sddr09_card_info *info;
static unsigned char inquiry_response[8] = {
static const unsigned char inquiry_response[8] = {
0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
};
/* note: no block descriptor support */
static unsigned char mode_page_01[19] = {
static const unsigned char mode_page_01[19] = {
0x00, 0x0F, 0x00, 0x0, 0x0, 0x0, 0x00,
0x01, 0x0A,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
@@ -1584,7 +1584,7 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
}
if (srb->cmnd[0] == READ_CAPACITY) {
struct nand_flash_dev *cardinfo;
const struct nand_flash_dev *cardinfo;
sddr09_get_wp(us, info); /* read WP bit */

View File

@@ -775,11 +775,11 @@ static void sddr55_card_info_destructor(void *extra) {
static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int result;
static unsigned char inquiry_response[8] = {
static const unsigned char inquiry_response[8] = {
0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
};
// write-protected for now, no block descriptor support
static unsigned char mode_page_01[20] = {
static const unsigned char mode_page_01[20] = {
0x0, 0x12, 0x00, 0x80, 0x0, 0x0, 0x0, 0x0,
0x01, 0x0A,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

View File

@@ -1683,7 +1683,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
struct usbat_info *info = (struct usbat_info *) (us->extra);
unsigned long block, blocks;
unsigned char *ptr = us->iobuf;
static unsigned char inquiry_response[36] = {
static const unsigned char inquiry_response[36] = {
0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
};

View File

@@ -528,7 +528,7 @@ static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb)
u32 sector;
/* To Report "Medium Error: Record Not Found */
static unsigned char record_not_found[18] = {
static const unsigned char record_not_found[18] = {
[0] = 0x70, /* current error */
[2] = MEDIUM_ERROR, /* = 0x03 */
[7] = 0x0a, /* additional length */

View File

@@ -112,7 +112,7 @@ static void tbt_altmode_work(struct work_struct *work)
return;
disable_plugs:
for (int i = TYPEC_PLUG_SOP_PP; i > 0; --i) {
for (int i = TYPEC_PLUG_SOP_PP; i >= 0; --i) {
if (tbt->plug[i])
typec_altmode_put_plug(tbt->plug[i]);
@@ -143,7 +143,7 @@ static int tbt_enter_modes_ordered(struct typec_altmode *alt)
if (tbt->plug[TYPEC_PLUG_SOP_P]) {
ret = typec_cable_altmode_enter(alt, TYPEC_PLUG_SOP_P, NULL);
if (ret < 0) {
for (int i = TYPEC_PLUG_SOP_PP; i > 0; --i) {
for (int i = TYPEC_PLUG_SOP_PP; i >= 0; --i) {
if (tbt->plug[i])
typec_altmode_put_plug(tbt->plug[i]);
@@ -324,7 +324,7 @@ static void tbt_altmode_remove(struct typec_altmode *alt)
{
struct tbt_altmode *tbt = typec_altmode_get_drvdata(alt);
for (int i = TYPEC_PLUG_SOP_PP; i > 0; --i) {
for (int i = TYPEC_PLUG_SOP_PP; i >= 0; --i) {
if (tbt->plug[i])
typec_altmode_put_plug(tbt->plug[i]);
}
@@ -351,10 +351,10 @@ static bool tbt_ready(struct typec_altmode *alt)
*/
for (int i = 0; i < TYPEC_PLUG_SOP_PP + 1; i++) {
plug = typec_altmode_get_plug(tbt->alt, i);
if (IS_ERR(plug))
if (!plug)
continue;
if (!plug || plug->svid != USB_TYPEC_TBT_SID)
if (plug->svid != USB_TYPEC_TBT_SID)
break;
plug->desc = "Thunderbolt3";

View File

@@ -56,6 +56,16 @@ config TYPEC_MUX_NB7VPQ904M
Say Y or M if your system has a On Semiconductor NB7VPQ904M Type-C
redriver chip found on some devices with a Type-C port.
config TYPEC_MUX_PS883X
tristate "Parade PS883x Type-C retimer driver"
depends on I2C
depends on DRM || DRM=n
select DRM_AUX_BRIDGE if DRM_BRIDGE && OF
select REGMAP_I2C
help
Say Y or M if your system has a Parade PS883x Type-C retimer chip
found on some devices with a Type-C port.
config TYPEC_MUX_PTN36502
tristate "NXP PTN36502 Type-C redriver driver"
depends on I2C

View File

@@ -6,6 +6,7 @@ obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o
obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o
obj-$(CONFIG_TYPEC_MUX_IT5205) += it5205.o
obj-$(CONFIG_TYPEC_MUX_NB7VPQ904M) += nb7vpq904m.o
obj-$(CONFIG_TYPEC_MUX_PS883X) += ps883x.o
obj-$(CONFIG_TYPEC_MUX_PTN36502) += ptn36502.o
obj-$(CONFIG_TYPEC_MUX_TUSB1046) += tusb1046.o
obj-$(CONFIG_TYPEC_MUX_WCD939X_USBSS) += wcd939x-usbss.o

View File

@@ -0,0 +1,466 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Parade ps883x usb retimer driver
*
* Copyright (C) 2024 Linaro Ltd.
*/
#include <drm/bridge/aux-bridge.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/usb/typec_altmode.h>
#include <linux/usb/typec_dp.h>
#include <linux/usb/typec_mux.h>
#include <linux/usb/typec_retimer.h>
#define REG_USB_PORT_CONN_STATUS_0 0x00
#define CONN_STATUS_0_CONNECTION_PRESENT BIT(0)
#define CONN_STATUS_0_ORIENTATION_REVERSED BIT(1)
#define CONN_STATUS_0_USB_3_1_CONNECTED BIT(5)
#define REG_USB_PORT_CONN_STATUS_1 0x01
#define CONN_STATUS_1_DP_CONNECTED BIT(0)
#define CONN_STATUS_1_DP_SINK_REQUESTED BIT(1)
#define CONN_STATUS_1_DP_PIN_ASSIGNMENT_C_D BIT(2)
#define CONN_STATUS_1_DP_HPD_LEVEL BIT(7)
#define REG_USB_PORT_CONN_STATUS_2 0x02
struct ps883x_retimer {
struct i2c_client *client;
struct gpio_desc *reset_gpio;
struct regmap *regmap;
struct typec_switch_dev *sw;
struct typec_retimer *retimer;
struct clk *xo_clk;
struct regulator *vdd_supply;
struct regulator *vdd33_supply;
struct regulator *vdd33_cap_supply;
struct regulator *vddat_supply;
struct regulator *vddar_supply;
struct regulator *vddio_supply;
struct typec_switch *typec_switch;
struct typec_mux *typec_mux;
struct mutex lock; /* protect non-concurrent retimer & switch */
enum typec_orientation orientation;
unsigned long mode;
unsigned int svid;
};
static int ps883x_configure(struct ps883x_retimer *retimer, int cfg0,
int cfg1, int cfg2)
{
struct device *dev = &retimer->client->dev;
int ret;
ret = regmap_write(retimer->regmap, REG_USB_PORT_CONN_STATUS_0, cfg0);
if (ret) {
dev_err(dev, "failed to write conn_status_0: %d\n", ret);
return ret;
}
ret = regmap_write(retimer->regmap, REG_USB_PORT_CONN_STATUS_1, cfg1);
if (ret) {
dev_err(dev, "failed to write conn_status_1: %d\n", ret);
return ret;
}
ret = regmap_write(retimer->regmap, REG_USB_PORT_CONN_STATUS_2, cfg2);
if (ret) {
dev_err(dev, "failed to write conn_status_2: %d\n", ret);
return ret;
}
return 0;
}
static int ps883x_set(struct ps883x_retimer *retimer)
{
int cfg0 = CONN_STATUS_0_CONNECTION_PRESENT;
int cfg1 = 0x00;
int cfg2 = 0x00;
if (retimer->orientation == TYPEC_ORIENTATION_NONE ||
retimer->mode == TYPEC_STATE_SAFE) {
return ps883x_configure(retimer, cfg0, cfg1, cfg2);
}
if (retimer->mode != TYPEC_STATE_USB && retimer->svid != USB_TYPEC_DP_SID)
return -EINVAL;
if (retimer->orientation == TYPEC_ORIENTATION_REVERSE)
cfg0 |= CONN_STATUS_0_ORIENTATION_REVERSED;
switch (retimer->mode) {
case TYPEC_STATE_USB:
cfg0 |= CONN_STATUS_0_USB_3_1_CONNECTED;
break;
case TYPEC_DP_STATE_C:
cfg1 = CONN_STATUS_1_DP_CONNECTED |
CONN_STATUS_1_DP_SINK_REQUESTED |
CONN_STATUS_1_DP_PIN_ASSIGNMENT_C_D |
CONN_STATUS_1_DP_HPD_LEVEL;
break;
case TYPEC_DP_STATE_D:
cfg0 |= CONN_STATUS_0_USB_3_1_CONNECTED;
cfg1 = CONN_STATUS_1_DP_CONNECTED |
CONN_STATUS_1_DP_SINK_REQUESTED |
CONN_STATUS_1_DP_PIN_ASSIGNMENT_C_D |
CONN_STATUS_1_DP_HPD_LEVEL;
break;
case TYPEC_DP_STATE_E:
cfg1 = CONN_STATUS_1_DP_CONNECTED |
CONN_STATUS_1_DP_HPD_LEVEL;
break;
default:
return -EOPNOTSUPP;
}
return ps883x_configure(retimer, cfg0, cfg1, cfg2);
}
static int ps883x_sw_set(struct typec_switch_dev *sw,
enum typec_orientation orientation)
{
struct ps883x_retimer *retimer = typec_switch_get_drvdata(sw);
int ret = 0;
ret = typec_switch_set(retimer->typec_switch, orientation);
if (ret)
return ret;
mutex_lock(&retimer->lock);
if (retimer->orientation != orientation) {
retimer->orientation = orientation;
ret = ps883x_set(retimer);
}
mutex_unlock(&retimer->lock);
return ret;
}
static int ps883x_retimer_set(struct typec_retimer *rtmr,
struct typec_retimer_state *state)
{
struct ps883x_retimer *retimer = typec_retimer_get_drvdata(rtmr);
struct typec_mux_state mux_state;
int ret = 0;
mutex_lock(&retimer->lock);
if (state->mode != retimer->mode) {
retimer->mode = state->mode;
if (state->alt)
retimer->svid = state->alt->svid;
else
retimer->svid = 0;
ret = ps883x_set(retimer);
}
mutex_unlock(&retimer->lock);
if (ret)
return ret;
mux_state.alt = state->alt;
mux_state.data = state->data;
mux_state.mode = state->mode;
return typec_mux_set(retimer->typec_mux, &mux_state);
}
static int ps883x_enable_vregs(struct ps883x_retimer *retimer)
{
struct device *dev = &retimer->client->dev;
int ret;
ret = regulator_enable(retimer->vdd33_supply);
if (ret) {
dev_err(dev, "cannot enable VDD 3.3V regulator: %d\n", ret);
return ret;
}
ret = regulator_enable(retimer->vdd33_cap_supply);
if (ret) {
dev_err(dev, "cannot enable VDD 3.3V CAP regulator: %d\n", ret);
goto err_vdd33_disable;
}
usleep_range(4000, 10000);
ret = regulator_enable(retimer->vdd_supply);
if (ret) {
dev_err(dev, "cannot enable VDD regulator: %d\n", ret);
goto err_vdd33_cap_disable;
}
ret = regulator_enable(retimer->vddar_supply);
if (ret) {
dev_err(dev, "cannot enable VDD AR regulator: %d\n", ret);
goto err_vdd_disable;
}
ret = regulator_enable(retimer->vddat_supply);
if (ret) {
dev_err(dev, "cannot enable VDD AT regulator: %d\n", ret);
goto err_vddar_disable;
}
ret = regulator_enable(retimer->vddio_supply);
if (ret) {
dev_err(dev, "cannot enable VDD IO regulator: %d\n", ret);
goto err_vddat_disable;
}
return 0;
err_vddat_disable:
regulator_disable(retimer->vddat_supply);
err_vddar_disable:
regulator_disable(retimer->vddar_supply);
err_vdd_disable:
regulator_disable(retimer->vdd_supply);
err_vdd33_cap_disable:
regulator_disable(retimer->vdd33_cap_supply);
err_vdd33_disable:
regulator_disable(retimer->vdd33_supply);
return ret;
}
static void ps883x_disable_vregs(struct ps883x_retimer *retimer)
{
regulator_disable(retimer->vddio_supply);
regulator_disable(retimer->vddat_supply);
regulator_disable(retimer->vddar_supply);
regulator_disable(retimer->vdd_supply);
regulator_disable(retimer->vdd33_cap_supply);
regulator_disable(retimer->vdd33_supply);
}
static int ps883x_get_vregs(struct ps883x_retimer *retimer)
{
struct device *dev = &retimer->client->dev;
retimer->vdd_supply = devm_regulator_get(dev, "vdd");
if (IS_ERR(retimer->vdd_supply))
return dev_err_probe(dev, PTR_ERR(retimer->vdd_supply),
"failed to get VDD\n");
retimer->vdd33_supply = devm_regulator_get(dev, "vdd33");
if (IS_ERR(retimer->vdd33_supply))
return dev_err_probe(dev, PTR_ERR(retimer->vdd33_supply),
"failed to get VDD 3.3V\n");
retimer->vdd33_cap_supply = devm_regulator_get(dev, "vdd33-cap");
if (IS_ERR(retimer->vdd33_cap_supply))
return dev_err_probe(dev, PTR_ERR(retimer->vdd33_cap_supply),
"failed to get VDD CAP 3.3V\n");
retimer->vddat_supply = devm_regulator_get(dev, "vddat");
if (IS_ERR(retimer->vddat_supply))
return dev_err_probe(dev, PTR_ERR(retimer->vddat_supply),
"failed to get VDD AT\n");
retimer->vddar_supply = devm_regulator_get(dev, "vddar");
if (IS_ERR(retimer->vddar_supply))
return dev_err_probe(dev, PTR_ERR(retimer->vddar_supply),
"failed to get VDD AR\n");
retimer->vddio_supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(retimer->vddio_supply))
return dev_err_probe(dev, PTR_ERR(retimer->vddio_supply),
"failed to get VDD IO\n");
return 0;
}
static const struct regmap_config ps883x_retimer_regmap = {
.max_register = 0x1f,
.reg_bits = 8,
.val_bits = 8,
};
static int ps883x_retimer_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct typec_switch_desc sw_desc = { };
struct typec_retimer_desc rtmr_desc = { };
struct ps883x_retimer *retimer;
unsigned int val;
int ret;
retimer = devm_kzalloc(dev, sizeof(*retimer), GFP_KERNEL);
if (!retimer)
return -ENOMEM;
retimer->client = client;
mutex_init(&retimer->lock);
retimer->regmap = devm_regmap_init_i2c(client, &ps883x_retimer_regmap);
if (IS_ERR(retimer->regmap))
return dev_err_probe(dev, PTR_ERR(retimer->regmap),
"failed to allocate register map\n");
ret = ps883x_get_vregs(retimer);
if (ret)
return ret;
retimer->xo_clk = devm_clk_get(dev, NULL);
if (IS_ERR(retimer->xo_clk))
return dev_err_probe(dev, PTR_ERR(retimer->xo_clk),
"failed to get xo clock\n");
retimer->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
if (IS_ERR(retimer->reset_gpio))
return dev_err_probe(dev, PTR_ERR(retimer->reset_gpio),
"failed to get reset gpio\n");
retimer->typec_switch = typec_switch_get(dev);
if (IS_ERR(retimer->typec_switch))
return dev_err_probe(dev, PTR_ERR(retimer->typec_switch),
"failed to acquire orientation-switch\n");
retimer->typec_mux = typec_mux_get(dev);
if (IS_ERR(retimer->typec_mux)) {
ret = dev_err_probe(dev, PTR_ERR(retimer->typec_mux),
"failed to acquire mode-mux\n");
goto err_switch_put;
}
ret = drm_aux_bridge_register(dev);
if (ret)
goto err_mux_put;
ret = ps883x_enable_vregs(retimer);
if (ret)
goto err_mux_put;
ret = clk_prepare_enable(retimer->xo_clk);
if (ret) {
dev_err(dev, "failed to enable XO: %d\n", ret);
goto err_vregs_disable;
}
/* skip resetting if already configured */
if (regmap_test_bits(retimer->regmap, REG_USB_PORT_CONN_STATUS_0,
CONN_STATUS_0_CONNECTION_PRESENT) == 1) {
gpiod_direction_output(retimer->reset_gpio, 0);
} else {
gpiod_direction_output(retimer->reset_gpio, 1);
/* VDD IO supply enable to reset release delay */
usleep_range(4000, 14000);
gpiod_set_value(retimer->reset_gpio, 0);
/* firmware initialization delay */
msleep(60);
/* make sure device is accessible */
ret = regmap_read(retimer->regmap, REG_USB_PORT_CONN_STATUS_0,
&val);
if (ret) {
dev_err(dev, "failed to read conn_status_0: %d\n", ret);
if (ret == -ENXIO)
ret = -EIO;
goto err_clk_disable;
}
}
sw_desc.drvdata = retimer;
sw_desc.fwnode = dev_fwnode(dev);
sw_desc.set = ps883x_sw_set;
retimer->sw = typec_switch_register(dev, &sw_desc);
if (IS_ERR(retimer->sw)) {
ret = PTR_ERR(retimer->sw);
dev_err(dev, "failed to register typec switch: %d\n", ret);
goto err_clk_disable;
}
rtmr_desc.drvdata = retimer;
rtmr_desc.fwnode = dev_fwnode(dev);
rtmr_desc.set = ps883x_retimer_set;
retimer->retimer = typec_retimer_register(dev, &rtmr_desc);
if (IS_ERR(retimer->retimer)) {
ret = PTR_ERR(retimer->retimer);
dev_err(dev, "failed to register typec retimer: %d\n", ret);
goto err_switch_unregister;
}
return 0;
err_switch_unregister:
typec_switch_unregister(retimer->sw);
err_clk_disable:
clk_disable_unprepare(retimer->xo_clk);
err_vregs_disable:
gpiod_set_value(retimer->reset_gpio, 1);
ps883x_disable_vregs(retimer);
err_mux_put:
typec_mux_put(retimer->typec_mux);
err_switch_put:
typec_switch_put(retimer->typec_switch);
return ret;
}
static void ps883x_retimer_remove(struct i2c_client *client)
{
struct ps883x_retimer *retimer = i2c_get_clientdata(client);
typec_retimer_unregister(retimer->retimer);
typec_switch_unregister(retimer->sw);
gpiod_set_value(retimer->reset_gpio, 1);
clk_disable_unprepare(retimer->xo_clk);
ps883x_disable_vregs(retimer);
typec_mux_put(retimer->typec_mux);
typec_switch_put(retimer->typec_switch);
}
static const struct of_device_id ps883x_retimer_of_table[] = {
{ .compatible = "parade,ps8830" },
{ }
};
MODULE_DEVICE_TABLE(of, ps883x_retimer_of_table);
static struct i2c_driver ps883x_retimer_driver = {
.driver = {
.name = "ps883x_retimer",
.of_match_table = ps883x_retimer_of_table,
},
.probe = ps883x_retimer_probe,
.remove = ps883x_retimer_remove,
};
module_i2c_driver(ps883x_retimer_driver);
MODULE_DESCRIPTION("Parade ps883x Type-C Retimer driver");
MODULE_LICENSE("GPL");

View File

@@ -105,12 +105,13 @@ static int cros_ucsi_async_control(struct ucsi *ucsi, u64 cmd)
return 0;
}
static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd)
static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci,
void *data, size_t size)
{
struct cros_ucsi_data *udata = ucsi_get_drvdata(ucsi);
int ret;
ret = ucsi_sync_control_common(ucsi, cmd);
ret = ucsi_sync_control_common(ucsi, cmd, cci, data, size);
switch (ret) {
case -EBUSY:
/* EC may return -EBUSY if CCI.busy is set.
@@ -205,12 +206,19 @@ static int cros_ucsi_event(struct notifier_block *nb,
{
struct cros_ucsi_data *udata = container_of(nb, struct cros_ucsi_data, nb);
if (!(host_event & PD_EVENT_PPM))
return NOTIFY_OK;
if (host_event & PD_EVENT_INIT) {
/* Late init event received from ChromeOS EC. Treat this as a
* system resume to re-enable communication with the PPM.
*/
dev_dbg(udata->dev, "Late PD init received\n");
ucsi_resume(udata->ucsi);
}
dev_dbg(udata->dev, "UCSI notification received\n");
flush_work(&udata->work);
schedule_work(&udata->work);
if (host_event & PD_EVENT_PPM) {
dev_dbg(udata->dev, "UCSI notification received\n");
flush_work(&udata->work);
schedule_work(&udata->work);
}
return NOTIFY_OK;
}

View File

@@ -28,11 +28,12 @@ static int ucsi_cmd(void *data, u64 val)
ucsi->debugfs->status = 0;
switch (UCSI_COMMAND(val)) {
case UCSI_SET_UOM:
case UCSI_SET_CCOM:
case UCSI_SET_UOR:
case UCSI_SET_PDR:
case UCSI_CONNECTOR_RESET:
case UCSI_SET_SINK_PATH:
case UCSI_SET_NEW_CAM:
ret = ucsi_send_command(ucsi, val, NULL, 0);
break;
case UCSI_GET_CAPABILITY:
@@ -42,6 +43,9 @@ static int ucsi_cmd(void *data, u64 val)
case UCSI_GET_PDOS:
case UCSI_GET_CABLE_PROPERTY:
case UCSI_GET_CONNECTOR_STATUS:
case UCSI_GET_ERROR_STATUS:
case UCSI_GET_CAM_CS:
case UCSI_GET_LPM_PPM_INFO:
ret = ucsi_send_command(ucsi, val,
&ucsi->debugfs->response,
sizeof(ucsi->debugfs->response));

View File

@@ -12,7 +12,7 @@ static const char * const ucsi_cmd_strs[] = {
[UCSI_SET_NOTIFICATION_ENABLE] = "SET_NOTIFICATION_ENABLE",
[UCSI_GET_CAPABILITY] = "GET_CAPABILITY",
[UCSI_GET_CONNECTOR_CAPABILITY] = "GET_CONNECTOR_CAPABILITY",
[UCSI_SET_UOM] = "SET_UOM",
[UCSI_SET_CCOM] = "SET_CCOM",
[UCSI_SET_UOR] = "SET_UOR",
[UCSI_SET_PDM] = "SET_PDM",
[UCSI_SET_PDR] = "SET_PDR",

View File

@@ -55,7 +55,8 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci)
}
EXPORT_SYMBOL_GPL(ucsi_notify_common);
int ucsi_sync_control_common(struct ucsi *ucsi, u64 command)
int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci,
void *data, size_t size)
{
bool ack = UCSI_COMMAND(command) == UCSI_ACK_CC_CI;
int ret;
@@ -80,6 +81,13 @@ int ucsi_sync_control_common(struct ucsi *ucsi, u64 command)
else
clear_bit(COMMAND_PENDING, &ucsi->flags);
if (!ret && cci)
ret = ucsi->ops->read_cci(ucsi, cci);
if (!ret && data &&
(*cci & UCSI_CCI_COMMAND_COMPLETE))
ret = ucsi->ops->read_message_in(ucsi, data, size);
return ret;
}
EXPORT_SYMBOL_GPL(ucsi_sync_control_common);
@@ -95,7 +103,7 @@ static int ucsi_acknowledge(struct ucsi *ucsi, bool conn_ack)
ctrl |= UCSI_ACK_CONNECTOR_CHANGE;
}
return ucsi->ops->sync_control(ucsi, ctrl);
return ucsi->ops->sync_control(ucsi, ctrl, NULL, NULL, 0);
}
static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci,
@@ -108,9 +116,7 @@ static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci,
if (size > UCSI_MAX_DATA_LENGTH(ucsi))
return -EINVAL;
ret = ucsi->ops->sync_control(ucsi, command);
if (ucsi->ops->read_cci(ucsi, cci))
return -EIO;
ret = ucsi->ops->sync_control(ucsi, command, cci, data, size);
if (*cci & UCSI_CCI_BUSY)
return ucsi_run_command(ucsi, UCSI_CANCEL, cci, NULL, 0, false) ?: -EBUSY;
@@ -127,9 +133,6 @@ static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci,
else
err = 0;
if (!err && data && UCSI_CCI_LENGTH(*cci))
err = ucsi->ops->read_message_in(ucsi, data, size);
/*
* Don't ACK connection change if there was an error.
*/

View File

@@ -79,7 +79,8 @@ struct ucsi_operations {
int (*read_cci)(struct ucsi *ucsi, u32 *cci);
int (*poll_cci)(struct ucsi *ucsi, u32 *cci);
int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len);
int (*sync_control)(struct ucsi *ucsi, u64 command);
int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci,
void *data, size_t size);
int (*async_control)(struct ucsi *ucsi, u64 command);
bool (*update_altmodes)(struct ucsi *ucsi, struct ucsi_altmode *orig,
struct ucsi_altmode *updated);
@@ -108,7 +109,7 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
#define UCSI_GET_CAPABILITY_SIZE 128
#define UCSI_GET_CONNECTOR_CAPABILITY 0x07
#define UCSI_GET_CONNECTOR_CAPABILITY_SIZE 32
#define UCSI_SET_UOM 0x08
#define UCSI_SET_CCOM 0x08
#define UCSI_SET_UOR 0x09
#define UCSI_SET_PDM 0x0a
#define UCSI_SET_PDR 0x0b
@@ -123,7 +124,9 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
#define UCSI_GET_CONNECTOR_STATUS_SIZE 152
#define UCSI_GET_ERROR_STATUS 0x13
#define UCSI_GET_PD_MESSAGE 0x15
#define UCSI_GET_CAM_CS 0x18
#define UCSI_SET_SINK_PATH 0x1c
#define UCSI_GET_LPM_PPM_INFO 0x22
#define UCSI_CONNECTOR_NUMBER(_num_) ((u64)(_num_) << 16)
#define UCSI_COMMAND(_cmd_) ((_cmd_) & 0xff)
@@ -531,7 +534,8 @@ void ucsi_altmode_update_active(struct ucsi_connector *con);
int ucsi_resume(struct ucsi *ucsi);
void ucsi_notify_common(struct ucsi *ucsi, u32 cci);
int ucsi_sync_control_common(struct ucsi *ucsi, u64 command);
int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci,
void *data, size_t size);
#if IS_ENABLED(CONFIG_POWER_SUPPLY)
int ucsi_register_port_psy(struct ucsi_connector *con);

View File

@@ -105,17 +105,23 @@ static const struct ucsi_operations ucsi_acpi_ops = {
.async_control = ucsi_acpi_async_control
};
static int ucsi_gram_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci,
void *val, size_t len)
{
u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE |
UCSI_CONSTAT_PDOS_CHANGE;
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
int ret;
ret = ucsi_acpi_read_message_in(ucsi, val, val_len);
ret = ucsi_sync_control_common(ucsi, command, cci, val, len);
if (ret < 0)
return ret;
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_PDOS &&
ua->cmd & UCSI_GET_PDOS_PARTNER_PDO(1) &&
ua->cmd & UCSI_GET_PDOS_SRC_PDOS)
ua->check_bogus_event = true;
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS &&
ua->check_bogus_event) {
/* Clear the bogus change */
@@ -128,28 +134,11 @@ static int ucsi_gram_read_message_in(struct ucsi *ucsi, void *val, size_t val_le
return ret;
}
static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command)
{
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
int ret;
ret = ucsi_sync_control_common(ucsi, command);
if (ret < 0)
return ret;
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_PDOS &&
ua->cmd & UCSI_GET_PDOS_PARTNER_PDO(1) &&
ua->cmd & UCSI_GET_PDOS_SRC_PDOS)
ua->check_bogus_event = true;
return ret;
}
static const struct ucsi_operations ucsi_gram_ops = {
.read_version = ucsi_acpi_read_version,
.read_cci = ucsi_acpi_read_cci,
.poll_cci = ucsi_acpi_poll_cci,
.read_message_in = ucsi_gram_read_message_in,
.read_message_in = ucsi_acpi_read_message_in,
.sync_control = ucsi_gram_sync_control,
.async_control = ucsi_acpi_async_control
};

View File

@@ -222,7 +222,6 @@ struct ucsi_ccg {
u16 fw_build;
struct work_struct pm_work;
u64 last_cmd_sent;
bool has_multiple_dp;
struct ucsi_ccg_altmode orig[UCSI_MAX_ALTMODES];
struct ucsi_ccg_altmode updated[UCSI_MAX_ALTMODES];
@@ -538,9 +537,10 @@ static void ucsi_ccg_update_set_new_cam_cmd(struct ucsi_ccg *uc,
* first and then vdo=0x3
*/
static void ucsi_ccg_nvidia_altmode(struct ucsi_ccg *uc,
struct ucsi_altmode *alt)
struct ucsi_altmode *alt,
u64 command)
{
switch (UCSI_ALTMODE_OFFSET(uc->last_cmd_sent)) {
switch (UCSI_ALTMODE_OFFSET(command)) {
case NVIDIA_FTB_DP_OFFSET:
if (alt[0].mid == USB_TYPEC_NVIDIA_VLINK_DBG_VDO)
alt[0].mid = USB_TYPEC_NVIDIA_VLINK_DP_VDO |
@@ -578,37 +578,11 @@ static int ucsi_ccg_read_cci(struct ucsi *ucsi, u32 *cci)
static int ucsi_ccg_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
{
struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi);
struct ucsi_capability *cap;
struct ucsi_altmode *alt;
spin_lock(&uc->op_lock);
memcpy(val, uc->op_data.message_in, val_len);
spin_unlock(&uc->op_lock);
switch (UCSI_COMMAND(uc->last_cmd_sent)) {
case UCSI_GET_CURRENT_CAM:
if (uc->has_multiple_dp)
ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)val);
break;
case UCSI_GET_ALTERNATE_MODES:
if (UCSI_ALTMODE_RECIPIENT(uc->last_cmd_sent) ==
UCSI_RECIPIENT_SOP) {
alt = val;
if (alt[0].svid == USB_TYPEC_NVIDIA_VLINK_SID)
ucsi_ccg_nvidia_altmode(uc, alt);
}
break;
case UCSI_GET_CAPABILITY:
if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) {
cap = val;
cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS;
}
break;
default:
break;
}
uc->last_cmd_sent = 0;
return 0;
}
@@ -628,7 +602,8 @@ static int ucsi_ccg_async_control(struct ucsi *ucsi, u64 command)
return ccg_write(uc, reg, (u8 *)&command, sizeof(command));
}
static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command)
static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci,
void *data, size_t size)
{
struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi);
struct ucsi_connector *con;
@@ -638,11 +613,9 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command)
mutex_lock(&uc->lock);
pm_runtime_get_sync(uc->dev);
uc->last_cmd_sent = command;
if (UCSI_COMMAND(uc->last_cmd_sent) == UCSI_SET_NEW_CAM &&
if (UCSI_COMMAND(command) == UCSI_SET_NEW_CAM &&
uc->has_multiple_dp) {
con_index = (uc->last_cmd_sent >> 16) &
con_index = (command >> 16) &
UCSI_CMD_CONNECTOR_MASK;
if (con_index == 0) {
ret = -EINVAL;
@@ -652,7 +625,31 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command)
ucsi_ccg_update_set_new_cam_cmd(uc, con, &command);
}
ret = ucsi_sync_control_common(ucsi, command);
ret = ucsi_sync_control_common(ucsi, command, cci, data, size);
switch (UCSI_COMMAND(command)) {
case UCSI_GET_CURRENT_CAM:
if (uc->has_multiple_dp)
ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)data);
break;
case UCSI_GET_ALTERNATE_MODES:
if (UCSI_ALTMODE_RECIPIENT(command) == UCSI_RECIPIENT_SOP) {
struct ucsi_altmode *alt = data;
if (alt[0].svid == USB_TYPEC_NVIDIA_VLINK_SID)
ucsi_ccg_nvidia_altmode(uc, alt, command);
}
break;
case UCSI_GET_CAPABILITY:
if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) {
struct ucsi_capability *cap = data;
cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS;
}
break;
default:
break;
}
err_put:
pm_runtime_put_sync(uc->dev);
@@ -1391,22 +1388,35 @@ static ssize_t do_flash_store(struct device *dev,
if (!flash)
return n;
if (uc->fw_build == 0x0) {
dev_err(dev, "fail to flash FW due to missing FW build info\n");
return -EINVAL;
}
schedule_work(&uc->work);
return n;
}
static umode_t ucsi_ccg_attrs_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
{
struct device *dev = kobj_to_dev(kobj);
struct ucsi_ccg *uc = i2c_get_clientdata(to_i2c_client(dev));
if (!uc->fw_build)
return 0;
return attr->mode;
}
static DEVICE_ATTR_WO(do_flash);
static struct attribute *ucsi_ccg_attrs[] = {
&dev_attr_do_flash.attr,
NULL,
};
ATTRIBUTE_GROUPS(ucsi_ccg);
static struct attribute_group ucsi_ccg_attr_group = {
.attrs = ucsi_ccg_attrs,
.is_visible = ucsi_ccg_attrs_is_visible,
};
static const struct attribute_group *ucsi_ccg_groups[] = {
&ucsi_ccg_attr_group,
NULL,
};
static int ucsi_ccg_probe(struct i2c_client *client)
{
@@ -1433,11 +1443,10 @@ static int ucsi_ccg_probe(struct i2c_client *client)
uc->fw_build = CCG_FW_BUILD_NVIDIA_TEGRA;
else if (!strcmp(fw_name, "nvidia,gpu"))
uc->fw_build = CCG_FW_BUILD_NVIDIA;
if (!uc->fw_build)
dev_err(uc->dev, "failed to get FW build information\n");
}
if (!uc->fw_build)
dev_err(uc->dev, "failed to get FW build information\n");
/* reset ccg device and initialize ucsi */
status = ucsi_ccg_init(uc);
if (status < 0) {

View File

@@ -5046,6 +5046,7 @@ struct ec_response_pd_status {
#define PD_EVENT_DATA_SWAP BIT(3)
#define PD_EVENT_TYPEC BIT(4)
#define PD_EVENT_PPM BIT(5)
#define PD_EVENT_INIT BIT(6)
struct ec_response_host_event_status {
uint32_t status; /* PD MCU host event status */

View File

@@ -51,6 +51,7 @@ struct ep_device;
* @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
* @ss_ep_comp: SuperSpeed companion descriptor for this endpoint
* @ssp_isoc_ep_comp: SuperSpeedPlus isoc companion descriptor for this endpoint
* @eusb2_isoc_ep_comp: eUSB2 isoc companion descriptor for this endpoint
* @urb_list: urbs queued to this endpoint; maintained by usbcore
* @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
* with one or more transfer descriptors (TDs) per urb
@@ -64,9 +65,10 @@ struct ep_device;
* descriptor within an active interface in a given USB configuration.
*/
struct usb_host_endpoint {
struct usb_endpoint_descriptor desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp;
struct usb_endpoint_descriptor desc;
struct usb_ss_ep_comp_descriptor ss_ep_comp;
struct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp;
struct usb_eusb2_isoc_ep_comp_descriptor eusb2_isoc_ep_comp;
struct list_head urb_list;
void *hcpriv;
struct ep_device *ep_dev; /* For sysfs info */

View File

@@ -61,7 +61,7 @@ struct musb_hdrc_eps_bits {
};
struct musb_hdrc_config {
struct musb_fifo_cfg *fifo_cfg; /* board fifo configuration */
const struct musb_fifo_cfg *fifo_cfg; /* board fifo configuration */
unsigned fifo_cfg_size; /* size of the fifo configuration */
/* MUSB configuration-specific details */

View File

@@ -49,19 +49,10 @@
/*-------------------------------------------------------------------------*/
#if IS_ENABLED(CONFIG_USB_ULPI)
struct usb_phy *otg_ulpi_create(struct usb_phy_io_ops *ops,
unsigned int flags);
struct usb_phy *devm_otg_ulpi_create(struct device *dev,
struct usb_phy_io_ops *ops,
unsigned int flags);
#else
static inline struct usb_phy *otg_ulpi_create(struct usb_phy_io_ops *ops,
unsigned int flags)
{
return NULL;
}
static inline struct usb_phy *devm_otg_ulpi_create(struct device *dev,
struct usb_phy_io_ops *ops,
unsigned int flags)

View File

@@ -253,6 +253,9 @@ struct usb_ctrlrequest {
#define USB_DT_BOS 0x0f
#define USB_DT_DEVICE_CAPABILITY 0x10
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
/* From the eUSB2 spec */
#define USB_DT_EUSB2_ISOC_ENDPOINT_COMP 0x12
/* From Wireless USB spec */
#define USB_DT_WIRE_ADAPTER 0x21
/* From USB Device Firmware Upgrade Specification, Revision 1.1 */
#define USB_DT_DFU_FUNCTIONAL 0x21
@@ -676,6 +679,18 @@ static inline int usb_endpoint_interrupt_type(
/*-------------------------------------------------------------------------*/
/* USB_DT_EUSB2_ISOC_ENDPOINT_COMP: eUSB2 Isoch Endpoint Companion descriptor */
struct usb_eusb2_isoc_ep_comp_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wMaxPacketSize;
__le32 dwBytesPerInterval;
} __attribute__ ((packed));
#define USB_DT_EUSB2_ISOC_EP_COMP_SIZE 8
/*-------------------------------------------------------------------------*/
/* USB_DT_SSP_ISOC_ENDPOINT_COMP: SuperSpeedPlus Isochronous Endpoint Companion
* descriptor
*/