Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,25 @@ properties:
wirenboard,mux-on-id-pin:
description: On Wiren Board 7 USB0 is muxed between USB-A connector for host mode and USB-C connector for peripheral mode. The mux is controller by voltage on perihperal connector. The same signal is used as USB ID.

patternProperties:
"^allwinner,usb[0-2]-tx-amplitude$":
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 3
default: 0
description:
TX amplitude tune value for the given PHY. The default (0, the
minimum) may result in a high-speed TX signal too weak for some
link partners to receive.

"^allwinner,usb[0-2]-tx-slew-rate$":
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
default: 5
description:
TX slew rate tune value for the given PHY.

required:
- "#phy-cells"
- compatible
Expand Down
8 changes: 7 additions & 1 deletion arch/arm/boot/dts/allwinner/sun8i-r40-wirenboard72x.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,12 @@
dr_mode = "otg";
wirenboard,mux-on-id-pin;

/* Maximum TX amplitude and slew rate: with the default TX tuning
* (minimum amplitude) some hosts fail to receive high-speed data
* from us: gadget enumeration fails and bulk data gets corrupted */
allwinner,usb0-tx-amplitude = <3>;
allwinner,usb0-tx-slew-rate = <7>;

status = "okay";
};

Expand Down Expand Up @@ -980,7 +986,7 @@
&usb_otg {
dr_mode = "peripheral";
status = "okay";
maximum-speed = "full-speed";
maximum-speed = "high-speed";
};

/* CPU RTC is useless since it doesn't have separate power supply. However we must keep it on to get proper LOSC for the rest of SoC.*/
Expand Down
6 changes: 6 additions & 0 deletions arch/arm/boot/dts/allwinner/sun8i-r40-wirenboard74x.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,12 @@
dr_mode = "otg";
wirenboard,mux-on-id-pin;

/* Maximum TX amplitude and slew rate: with the default TX tuning
* (minimum amplitude) some hosts fail to receive high-speed data
* from us: gadget enumeration fails and bulk data gets corrupted */
allwinner,usb0-tx-amplitude = <3>;
allwinner,usb0-tx-slew-rate = <7>;

status = "okay";
};

Expand Down
8 changes: 8 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
linux-wb (6.18.22-wb7) stable; urgency=medium

* phy-sun4i-usb: allow tuning PHY TX amplitude/slew rate via DT;
set both to maximum on Wiren Board 7 USB0: fixes high-speed gadget
enumeration failures and bulk data corruption on some hosts

-- Evgeny Boger <boger@wirenboard.com> Fri, 10 Jul 2026 03:24:30 +0300

linux-wb (6.18.22-wb6) stable; urgency=medium

* scripts: fix wb6x-bootlet build
Expand Down
40 changes: 39 additions & 1 deletion drivers/phy/allwinner/phy-sun4i-usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
*/

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
Expand Down Expand Up @@ -78,6 +79,17 @@
#define PHY_DISCON_TH_SEL 0x2a
#define PHY_SQUELCH_DETECT 0x3c

/*
* TX tune field layout, written as 5 bits starting at
* PHY_TX_AMPLITUDE_TUNE. The default is inherited from the
* Allwinner BSP: amplitude 0 (minimum), slew rate 5.
*/
#define PHY_TX_AMPLITUDE_MASK GENMASK(1, 0)
#define PHY_TX_AMPLITUDE_MAX 3
#define PHY_TX_SLEWRATE_MASK GENMASK(4, 2)
#define PHY_TX_SLEWRATE_MAX 7
#define PHY_TX_TUNE_DEFAULT 0x14

/* A83T specific control bits for PHY0 */
#define PHY_CTL_VBUSVLDEXT BIT(5)
#define PHY_CTL_SIDDQ BIT(3)
Expand Down Expand Up @@ -127,6 +139,7 @@ struct sun4i_usb_phy_data {
struct clk *clk2;
bool regulator_on;
int index;
u32 tx_tune;
} phys[MAX_PHYS];
/* phy0 / otg related variables */
struct extcon_dev *extcon;
Expand Down Expand Up @@ -394,7 +407,7 @@ static int sun4i_usb_phy_init(struct phy *_phy)
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);

/* Adjust PHY's magnitude and rate */
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, phy->tx_tune, 5);

/* Disconnect threshold adjustment */
sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
Expand Down Expand Up @@ -915,6 +928,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
for (i = 0; i < MAX_PHYS; i++) {
struct sun4i_usb_phy *phy = data->phys + i;
char name[32];
u32 val;

if (data->cfg->missing_phys & BIT(i))
continue;
Expand All @@ -928,6 +942,30 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy->reset);
}

phy->tx_tune = PHY_TX_TUNE_DEFAULT;

snprintf(name, sizeof(name), "allwinner,usb%d-tx-amplitude", i);
if (!of_property_read_u32(np, name, &val)) {
if (val > PHY_TX_AMPLITUDE_MAX) {
dev_warn(dev, "%s out of range, clamping to %d\n",
name, PHY_TX_AMPLITUDE_MAX);
val = PHY_TX_AMPLITUDE_MAX;
}
phy->tx_tune &= ~PHY_TX_AMPLITUDE_MASK;
phy->tx_tune |= FIELD_PREP(PHY_TX_AMPLITUDE_MASK, val);
}

snprintf(name, sizeof(name), "allwinner,usb%d-tx-slew-rate", i);
if (!of_property_read_u32(np, name, &val)) {
if (val > PHY_TX_SLEWRATE_MAX) {
dev_warn(dev, "%s out of range, clamping to %d\n",
name, PHY_TX_SLEWRATE_MAX);
val = PHY_TX_SLEWRATE_MAX;
}
phy->tx_tune &= ~PHY_TX_SLEWRATE_MASK;
phy->tx_tune |= FIELD_PREP(PHY_TX_SLEWRATE_MASK, val);
}

snprintf(name, sizeof(name), "usb%d_vbus", i);
phy->vbus = devm_regulator_get_optional(dev, name);
if (IS_ERR(phy->vbus)) {
Expand Down