* [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch
@ 2025-08-14 23:48 Arseniy Velikanov
2025-08-14 23:48 ` [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching Arseniy Velikanov
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Arseniy Velikanov @ 2025-08-14 23:48 UTC (permalink / raw)
To: Chunfeng Yun, Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: linux-arm-kernel, linux-mediatek, linux-phy, devicetree,
linux-kernel, ~postmarketos/upstreaming, Arseniy Velikanov
Add a boolean property to enable software control of the PHY mode
switching.
Signed-off-by: Arseniy Velikanov <me@adomerle.pw>
---
Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
index b2218c151939..a90890d4a86f 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
@@ -255,6 +255,12 @@ patternProperties:
use the property "mediatek,syscon-type" for newer SoCs that support it.
type: boolean
+ mediatek,software-role-switch:
+ description:
+ Forcibly sets the phy mode. In dual-role mode, it polls
+ role switcher and manually changes mode accordingly.
+ PHY port must be linked with the role switcher via device tree graphs.
+
mediatek,syscon-type:
$ref: /schemas/types.yaml#/definitions/phandle-array
maxItems: 1
--
2.50.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching
2025-08-14 23:48 [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch Arseniy Velikanov
@ 2025-08-14 23:48 ` Arseniy Velikanov
2025-08-19 3:31 ` kernel test robot
2025-08-28 20:06 ` Igor Belwon
2025-08-15 2:29 ` [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch Rob Herring (Arm)
2025-08-15 6:28 ` Krzysztof Kozlowski
2 siblings, 2 replies; 8+ messages in thread
From: Arseniy Velikanov @ 2025-08-14 23:48 UTC (permalink / raw)
To: Chunfeng Yun, Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: linux-arm-kernel, linux-mediatek, linux-phy, devicetree,
linux-kernel, ~postmarketos/upstreaming, Arseniy Velikanov
MediaTek USB T-PHY has broken role switching on (likely) all mobile SoCs.
Known affected socs are: MT6735, MT6757, MT6761, MT6765, MT6768, MT6771,
MT6785, MT6789.
The downstream kernel manually controls the PHY mode by writing
"test mode" FORCE regs. Setting all these regs fixes device/host modes, but
breaks dual-role functionality. As a workaround we use workqueue that
periodically checks the USB role and changes the PHY mode accordingly.
To address this issue only on affected SoCs, we introduce a new
device-tree property `mediatek,software-role-switch`. This ensures
the workaround is applied only to broken hardware while leaving unaffected
devices (like Chromebooks) untouched.
Signed-off-by: Arseniy Velikanov <me@adomerle.pw>
---
drivers/phy/mediatek/phy-mtk-tphy.c | 148 ++++++++++++++++++++++++++++
1 file changed, 148 insertions(+)
diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
index f6504e0ecd1a..472859ec929c 100644
--- a/drivers/phy/mediatek/phy-mtk-tphy.c
+++ b/drivers/phy/mediatek/phy-mtk-tphy.c
@@ -18,6 +18,9 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/usb/role.h>
+#include <linux/usb/otg.h>
+#include <linux/workqueue.h>
#include "phy-mtk-io.h"
@@ -111,11 +114,18 @@
#define U3P_U2PHYDTM1 0x06C
#define P2C_RG_UART_EN BIT(16)
+#define P2C_FORCE_IDPULLUP BIT(8)
#define P2C_FORCE_IDDIG BIT(9)
+#define P2C_FORCE_AVALID BIT(10)
+#define P2C_FORCE_SESSEND BIT(12)
+#define P2C_FORCE_VBUSVALID BIT(13)
+
#define P2C_RG_VBUSVALID BIT(5)
#define P2C_RG_SESSEND BIT(4)
+#define P2C_RG_BVALID BIT(3)
#define P2C_RG_AVALID BIT(2)
#define P2C_RG_IDDIG BIT(1)
+#define P2C_RG_IDPULLUP BIT(0)
#define U3P_U2PHYBC12C 0x080
#define P2C_RG_CHGDT_EN BIT(0)
@@ -317,6 +327,8 @@ struct mtk_phy_instance {
struct u3phy_banks u3_banks;
};
struct clk_bulk_data clks[TPHY_CLKS_CNT];
+ struct delayed_work dr_work;
+ struct usb_role_switch *role_switch;
u32 index;
u32 type;
struct regmap *type_sw;
@@ -326,14 +338,17 @@ struct mtk_phy_instance {
u32 efuse_intr;
u32 efuse_tx_imp;
u32 efuse_rx_imp;
+ int current_role;
int eye_src;
int eye_vrt;
int eye_term;
int intr;
int discth;
int pre_emphasis;
+ int sw_get_retries;
bool bc12_en;
bool type_force_mode;
+ bool software_role_switch;
};
struct mtk_tphy {
@@ -818,12 +833,118 @@ static void u2_phy_pll_26m_set(struct mtk_tphy *tphy,
P2R_RG_U2PLL_FRA_EN | P2R_RG_U2PLL_REFCLK_SEL);
}
+static void u2_phy_instance_role_set(struct mtk_phy_instance *instance,
+ int role)
+{
+ struct u2phy_banks *u2_banks = &instance->u2_banks;
+ void __iomem *com = u2_banks->com;
+
+ instance->current_role = role;
+
+ /* end session before role switch */
+ mtk_phy_set_bits(com + U3P_U2PHYDTM1, P2C_RG_SESSEND);
+ mdelay(5);
+ mtk_phy_clear_bits(com + U3P_U2PHYDTM1, P2C_RG_SESSEND);
+
+ switch (role) {
+ case USB_ROLE_DEVICE:
+ dev_dbg(&instance->phy->dev, "set device role\n");
+ mtk_phy_set_bits(com + U3P_U2PHYDTM1, P2C_RG_IDDIG);
+ break;
+ case USB_ROLE_HOST:
+ dev_dbg(&instance->phy->dev, "set host role\n");
+ mtk_phy_clear_bits(com + U3P_U2PHYDTM1, P2C_RG_IDDIG);
+ break;
+ default:
+ break;
+ }
+}
+
+static void u2_phy_role_switch_work(struct work_struct *work)
+{
+ struct mtk_phy_instance *instance =
+ container_of(work, struct mtk_phy_instance, dr_work.work);
+ int role;
+
+ if (IS_ERR_OR_NULL(instance->role_switch))
+ instance->role_switch = usb_role_switch_get(&instance->phy->dev);
+
+ if (IS_ERR_OR_NULL(instance->role_switch)) {
+ if (instance->sw_get_retries >= 10) {
+ dev_warn(&instance->phy->dev, "failed to get role switch\n");
+ return;
+ }
+
+ instance->sw_get_retries += 1;
+ schedule_delayed_work(&instance->dr_work, msecs_to_jiffies(500));
+ }
+
+ role = usb_role_switch_get_role(instance->role_switch);
+
+ if (instance->current_role == role)
+ goto reschedule_work;
+
+ u2_phy_instance_role_set(instance, role);
+
+reschedule_work:
+ schedule_delayed_work(&instance->dr_work, msecs_to_jiffies(100));
+}
+
+static int u2_phy_software_role_switch_init(struct mtk_phy_instance *instance)
+{
+ struct fwnode_handle *ep, *remote_ep, *usb_fwnode;
+ struct device *usb_dev;
+ int mode;
+
+ instance->sw_get_retries = 0;
+
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(&instance->phy->dev),
+ 0,
+ 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!ep)
+ return -ENODEV;
+
+ remote_ep = fwnode_graph_get_remote_endpoint(ep);
+ fwnode_handle_put(ep);
+ if (!remote_ep)
+ return -ENODEV;
+
+ usb_fwnode = fwnode_graph_get_port_parent(remote_ep);
+ fwnode_handle_put(remote_ep);
+
+ if (!usb_fwnode)
+ return -ENODEV;
+
+ usb_dev = bus_find_device_by_fwnode(&platform_bus_type, usb_fwnode);
+ fwnode_handle_put(usb_fwnode);
+ if (!usb_dev)
+ return -ENODEV;
+
+ mode = usb_get_role_switch_default_mode(usb_dev);
+ if (mode == USB_DR_MODE_HOST)
+ u2_phy_instance_role_set(instance, USB_ROLE_HOST);
+ else
+ u2_phy_instance_role_set(instance, USB_ROLE_DEVICE);
+
+ INIT_DELAYED_WORK(&instance->dr_work, u2_phy_role_switch_work);
+
+ return 0;
+}
+
static void u2_phy_instance_init(struct mtk_tphy *tphy,
struct mtk_phy_instance *instance)
{
struct u2phy_banks *u2_banks = &instance->u2_banks;
void __iomem *com = u2_banks->com;
u32 index = instance->index;
+ int ret;
+
+ if (instance->software_role_switch) {
+ ret = u2_phy_software_role_switch_init(instance);
+ if (ret)
+ dev_warn(&instance->phy->dev, "failed to initialize role switching\n");
+ }
/* switch to USB function, and enable usb pll */
mtk_phy_clear_bits(com + U3P_U2PHYDTM0, P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM);
@@ -883,6 +1004,18 @@ static void u2_phy_instance_power_on(struct mtk_tphy *tphy,
mtk_phy_set_bits(com + U3P_U2PHYDTM0, P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM);
}
+
+ if (instance->software_role_switch) {
+ /* Set FORCE modes for manual role switching */
+ mtk_phy_set_bits(com + U3P_U2PHYDTM1, P2C_FORCE_IDPULLUP
+ | P2C_FORCE_IDDIG | P2C_FORCE_AVALID | P2C_FORCE_VBUSVALID
+ | P2C_FORCE_SESSEND);
+ mtk_phy_set_bits(com + U3P_U2PHYDTM1, P2C_RG_IDPULLUP | P2C_RG_BVALID);
+
+ if (!instance->role_switch)
+ schedule_delayed_work(&instance->dr_work, msecs_to_jiffies(100));
+ }
+
dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
}
@@ -906,6 +1039,9 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy,
mtk_phy_clear_bits(com + U3D_U2PHYDCR0, P2C_RG_SIF_U2PLL_FORCE_ON);
}
+ if (instance->role_switch)
+ cancel_delayed_work_sync(&instance->dr_work);
+
dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
}
@@ -940,6 +1076,9 @@ static void u2_phy_instance_set_mode(struct mtk_tphy *tphy,
tmp &= ~P2C_RG_IDDIG;
break;
case PHY_MODE_USB_OTG:
+ /* We are managing role in workqueue */
+ if (instance->software_role_switch)
+ return;
tmp &= ~(P2C_FORCE_IDDIG | P2C_RG_IDDIG);
break;
default:
@@ -1129,6 +1268,11 @@ static void phy_parse_property(struct mtk_tphy *tphy,
if (instance->type == PHY_TYPE_USB3)
instance->type_force_mode = device_property_read_bool(dev, "mediatek,force-mode");
+ instance->software_role_switch =
+ device_property_read_bool(dev, "mediatek,software-role-switch");
+ if (instance->software_role_switch)
+ dev_info(dev, "software role switch enabled\n");
+
if (instance->type != PHY_TYPE_USB2)
return;
@@ -1618,6 +1762,10 @@ static int mtk_tphy_probe(struct platform_device *pdev)
struct phy *phy;
int retval;
+ /* filter non-phy nodes (e.g. graphs) */
+ if (!of_find_property(child_np, "reg", NULL))
+ continue;
+
instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
if (!instance)
return -ENOMEM;
--
2.50.1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch
2025-08-14 23:48 [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch Arseniy Velikanov
2025-08-14 23:48 ` [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching Arseniy Velikanov
@ 2025-08-15 2:29 ` Rob Herring (Arm)
2025-08-15 6:28 ` Krzysztof Kozlowski
2 siblings, 0 replies; 8+ messages in thread
From: Rob Herring (Arm) @ 2025-08-15 2:29 UTC (permalink / raw)
To: Arseniy Velikanov
Cc: AngeloGioacchino Del Regno, Krzysztof Kozlowski, devicetree,
Chunfeng Yun, linux-mediatek, ~postmarketos/upstreaming,
Conor Dooley, Vinod Koul, Kishon Vijay Abraham I,
linux-arm-kernel, Matthias Brugger, linux-kernel, linux-phy
On Fri, 15 Aug 2025 03:48:24 +0400, Arseniy Velikanov wrote:
> Add a boolean property to enable software control of the PHY mode
> switching.
>
> Signed-off-by: Arseniy Velikanov <me@adomerle.pw>
> ---
> Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 6 ++++++
> 1 file changed, 6 insertions(+)
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml: mediatek,software-role-switch: missing type definition
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250814234825.810-1-me@adomerle.pw
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch
2025-08-14 23:48 [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch Arseniy Velikanov
2025-08-14 23:48 ` [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching Arseniy Velikanov
2025-08-15 2:29 ` [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch Rob Herring (Arm)
@ 2025-08-15 6:28 ` Krzysztof Kozlowski
2025-08-24 6:25 ` Arseniy Velikanov
2 siblings, 1 reply; 8+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-15 6:28 UTC (permalink / raw)
To: Arseniy Velikanov
Cc: Chunfeng Yun, Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, linux-arm-kernel, linux-mediatek,
linux-phy, devicetree, linux-kernel, ~postmarketos/upstreaming
On Fri, Aug 15, 2025 at 03:48:24AM +0400, Arseniy Velikanov wrote:
> Add a boolean property to enable software control of the PHY mode
> switching.
>
> Signed-off-by: Arseniy Velikanov <me@adomerle.pw>
> ---
> Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
> index b2218c151939..a90890d4a86f 100644
> --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
> +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
> @@ -255,6 +255,12 @@ patternProperties:
> use the property "mediatek,syscon-type" for newer SoCs that support it.
> type: boolean
>
> + mediatek,software-role-switch:
No, bindings do not describe software.
Also, never tested.
Best regards,
Krzysztof
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching
2025-08-14 23:48 ` [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching Arseniy Velikanov
@ 2025-08-19 3:31 ` kernel test robot
2025-08-28 20:06 ` Igor Belwon
1 sibling, 0 replies; 8+ messages in thread
From: kernel test robot @ 2025-08-19 3:31 UTC (permalink / raw)
To: Arseniy Velikanov, Chunfeng Yun, Vinod Koul,
Kishon Vijay Abraham I, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno
Cc: oe-kbuild-all, linux-arm-kernel, linux-mediatek, linux-phy,
devicetree, linux-kernel, ~postmarketos/upstreaming,
Arseniy Velikanov
Hi Arseniy,
kernel test robot noticed the following build errors:
[auto build test ERROR on robh/for-next]
[also build test ERROR on linus/master v6.17-rc2 next-20250818]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Arseniy-Velikanov/phy-mediatek-tphy-Add-software-role-switching/20250815-075416
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link: https://lore.kernel.org/r/20250814234825.810-2-me%40adomerle.pw
patch subject: [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching
config: arm64-randconfig-001-20250819 (https://download.01.org/0day-ci/archive/20250819/202508191054.otlyeeg5-lkp@intel.com/config)
compiler: aarch64-linux-gcc (GCC) 14.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250819/202508191054.otlyeeg5-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508191054.otlyeeg5-lkp@intel.com/
All errors (new ones prefixed by >>):
aarch64-linux-ld: Unexpected GOT/PLT entries detected!
aarch64-linux-ld: Unexpected run-time procedure linkages detected!
aarch64-linux-ld: drivers/phy/mediatek/phy-mtk-tphy.o: in function `u2_phy_software_role_switch_init':
>> phy-mtk-tphy.c:(.text+0x31d4): undefined reference to `usb_get_role_switch_default_mode'
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch
2025-08-15 6:28 ` Krzysztof Kozlowski
@ 2025-08-24 6:25 ` Arseniy Velikanov
2025-08-24 8:18 ` Krzysztof Kozlowski
0 siblings, 1 reply; 8+ messages in thread
From: Arseniy Velikanov @ 2025-08-24 6:25 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Chunfeng Yun, Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, linux-arm-kernel, linux-mediatek,
linux-phy, devicetree, linux-kernel, ~postmarketos/upstreaming
On 15.08.2025 10:28, Krzysztof Kozlowski wrote:
> On Fri, Aug 15, 2025 at 03:48:24AM +0400, Arseniy Velikanov wrote:
>> Add a boolean property to enable software control of the PHY mode
>> switching.
>>
>> Signed-off-by: Arseniy Velikanov <me@adomerle.pw>
>> ---
>> Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
>> index b2218c151939..a90890d4a86f 100644
>> --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
>> +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
>> @@ -255,6 +255,12 @@ patternProperties:
>> use the property "mediatek,syscon-type" for newer SoCs that support it.
>> type: boolean
>>
>> + mediatek,software-role-switch:
>
> No, bindings do not describe software.
Sorry, I didn't quite understand you.
With this property the driver changes phy mode manually using debug regs
instead of configuring hardware mode switching (because it's broken on
some platforms). So every time the role in usb-role-switch changes, it
has to switch phy mode. That's what I mean by "software".
I can rename this property to `mediatek,force-mode-switch` if that's a
issue.
>
> Also, never tested.
>
> Best regards,
> Krzysztof
--
Kind regards,
Arseniy.
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch
2025-08-24 6:25 ` Arseniy Velikanov
@ 2025-08-24 8:18 ` Krzysztof Kozlowski
0 siblings, 0 replies; 8+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-24 8:18 UTC (permalink / raw)
To: Arseniy Velikanov
Cc: Chunfeng Yun, Vinod Koul, Kishon Vijay Abraham I, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, linux-arm-kernel, linux-mediatek,
linux-phy, devicetree, linux-kernel, ~postmarketos/upstreaming
On 24/08/2025 08:25, Arseniy Velikanov wrote:
> On 15.08.2025 10:28, Krzysztof Kozlowski wrote:
>> On Fri, Aug 15, 2025 at 03:48:24AM +0400, Arseniy Velikanov wrote:
>>> Add a boolean property to enable software control of the PHY mode
>>> switching.
>>>
>>> Signed-off-by: Arseniy Velikanov <me@adomerle.pw>
>>> ---
>>> Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 6 ++++++
>>> 1 file changed, 6 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
>>> index b2218c151939..a90890d4a86f 100644
>>> --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
>>> +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml
>>> @@ -255,6 +255,12 @@ patternProperties:
>>> use the property "mediatek,syscon-type" for newer SoCs that support it.
>>> type: boolean
>>>
>>> + mediatek,software-role-switch:
>>
>> No, bindings do not describe software.
> Sorry, I didn't quite understand you.
>
> With this property the driver changes phy mode manually using debug regs
Here is the problem: ^^^^^^^^, driver.
> instead of configuring hardware mode switching (because it's broken on
> some platforms). So every time the role in usb-role-switch changes, it
> has to switch phy mode. That's what I mean by "software".
>
> I can rename this property to `mediatek,force-mode-switch` if that's a
> issue.
Describe the hardware problem, characteristic, wiring or whatever else,
but not the drivers and not software.
force-media-switch is the same uninformative and same underlying
instruction for the driver.
Best regards,
Krzysztof
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching
2025-08-14 23:48 ` [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching Arseniy Velikanov
2025-08-19 3:31 ` kernel test robot
@ 2025-08-28 20:06 ` Igor Belwon
1 sibling, 0 replies; 8+ messages in thread
From: Igor Belwon @ 2025-08-28 20:06 UTC (permalink / raw)
To: Arseniy Velikanov
Cc: linux-arm-kernel, linux-mediatek, linux-phy, devicetree,
linux-kernel, ~postmarketos/upstreaming
Hi Arseniy,
On Fri Aug 15, 2025 at 1:48 AM CEST, Arseniy Velikanov wrote:
> MediaTek USB T-PHY has broken role switching on (likely) all mobile SoCs.
> Known affected socs are: MT6735, MT6757, MT6761, MT6765, MT6768, MT6771,
> MT6785, MT6789.
>
> The downstream kernel manually controls the PHY mode by writing
> "test mode" FORCE regs. Setting all these regs fixes device/host modes, but
> breaks dual-role functionality. As a workaround we use workqueue that
> periodically checks the USB role and changes the PHY mode accordingly.
>
> To address this issue only on affected SoCs, we introduce a new
> device-tree property `mediatek,software-role-switch`. This ensures
> the workaround is applied only to broken hardware while leaving unaffected
> devices (like Chromebooks) untouched.
>
> Signed-off-by: Arseniy Velikanov <me@adomerle.pw>
> ---
> drivers/phy/mediatek/phy-mtk-tphy.c | 148 ++++++++++++++++++++++++++++
> 1 file changed, 148 insertions(+)
>
> diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
> index f6504e0ecd1a..472859ec929c 100644
> --- a/drivers/phy/mediatek/phy-mtk-tphy.c
> +++ b/drivers/phy/mediatek/phy-mtk-tphy.c
> @@ -18,6 +18,9 @@
> #include <linux/phy/phy.h>
> #include <linux/platform_device.h>
> #include <linux/regmap.h>
> +#include <linux/usb/role.h>
> +#include <linux/usb/otg.h>
> +#include <linux/workqueue.h>
>
> #include "phy-mtk-io.h"
>
> @@ -111,11 +114,18 @@
>
> #define U3P_U2PHYDTM1 0x06C
> #define P2C_RG_UART_EN BIT(16)
> +#define P2C_FORCE_IDPULLUP BIT(8)
> #define P2C_FORCE_IDDIG BIT(9)
> +#define P2C_FORCE_AVALID BIT(10)
> +#define P2C_FORCE_SESSEND BIT(12)
> +#define P2C_FORCE_VBUSVALID BIT(13)
> +
> #define P2C_RG_VBUSVALID BIT(5)
> #define P2C_RG_SESSEND BIT(4)
> +#define P2C_RG_BVALID BIT(3)
> #define P2C_RG_AVALID BIT(2)
> #define P2C_RG_IDDIG BIT(1)
> +#define P2C_RG_IDPULLUP BIT(0)
>
> #define U3P_U2PHYBC12C 0x080
> #define P2C_RG_CHGDT_EN BIT(0)
> @@ -317,6 +327,8 @@ struct mtk_phy_instance {
> struct u3phy_banks u3_banks;
> };
> struct clk_bulk_data clks[TPHY_CLKS_CNT];
> + struct delayed_work dr_work;
> + struct usb_role_switch *role_switch;
> u32 index;
> u32 type;
> struct regmap *type_sw;
> @@ -326,14 +338,17 @@ struct mtk_phy_instance {
> u32 efuse_intr;
> u32 efuse_tx_imp;
> u32 efuse_rx_imp;
> + int current_role;
> int eye_src;
> int eye_vrt;
> int eye_term;
> int intr;
> int discth;
> int pre_emphasis;
> + int sw_get_retries;
> bool bc12_en;
> bool type_force_mode;
> + bool software_role_switch;
> };
>
> struct mtk_tphy {
> @@ -818,12 +833,118 @@ static void u2_phy_pll_26m_set(struct mtk_tphy *tphy,
> P2R_RG_U2PLL_FRA_EN | P2R_RG_U2PLL_REFCLK_SEL);
> }
>
> +static void u2_phy_instance_role_set(struct mtk_phy_instance *instance,
> + int role)
> +{
> + struct u2phy_banks *u2_banks = &instance->u2_banks;
> + void __iomem *com = u2_banks->com;
> +
> + instance->current_role = role;
> +
> + /* end session before role switch */
> + mtk_phy_set_bits(com + U3P_U2PHYDTM1, P2C_RG_SESSEND);
> + mdelay(5);
> + mtk_phy_clear_bits(com + U3P_U2PHYDTM1, P2C_RG_SESSEND);
> +
> + switch (role) {
> + case USB_ROLE_DEVICE:
> + dev_dbg(&instance->phy->dev, "set device role\n");
> + mtk_phy_set_bits(com + U3P_U2PHYDTM1, P2C_RG_IDDIG);
> + break;
> + case USB_ROLE_HOST:
> + dev_dbg(&instance->phy->dev, "set host role\n");
> + mtk_phy_clear_bits(com + U3P_U2PHYDTM1, P2C_RG_IDDIG);
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static void u2_phy_role_switch_work(struct work_struct *work)
> +{
> + struct mtk_phy_instance *instance =
> + container_of(work, struct mtk_phy_instance, dr_work.work);
> + int role;
> +
> + if (IS_ERR_OR_NULL(instance->role_switch))
> + instance->role_switch = usb_role_switch_get(&instance->phy->dev);
> +
> + if (IS_ERR_OR_NULL(instance->role_switch)) {
> + if (instance->sw_get_retries >= 10) {
> + dev_warn(&instance->phy->dev, "failed to get role switch\n");
> + return;
> + }
> +
> + instance->sw_get_retries += 1;
> + schedule_delayed_work(&instance->dr_work, msecs_to_jiffies(500));
> + }
> +
> + role = usb_role_switch_get_role(instance->role_switch);
> +
> + if (instance->current_role == role)
> + goto reschedule_work;
> +
> + u2_phy_instance_role_set(instance, role);
> +
> +reschedule_work:
> + schedule_delayed_work(&instance->dr_work, msecs_to_jiffies(100));
> +}
> +
> +static int u2_phy_software_role_switch_init(struct mtk_phy_instance *instance)
> +{
> + struct fwnode_handle *ep, *remote_ep, *usb_fwnode;
> + struct device *usb_dev;
> + int mode;
> +
> + instance->sw_get_retries = 0;
> +
> + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(&instance->phy->dev),
> + 0,
> + 0,
> + FWNODE_GRAPH_ENDPOINT_NEXT);
> + if (!ep)
> + return -ENODEV;
> +
> + remote_ep = fwnode_graph_get_remote_endpoint(ep);
> + fwnode_handle_put(ep);
> + if (!remote_ep)
> + return -ENODEV;
> +
> + usb_fwnode = fwnode_graph_get_port_parent(remote_ep);
> + fwnode_handle_put(remote_ep);
> +
> + if (!usb_fwnode)
> + return -ENODEV;
> +
> + usb_dev = bus_find_device_by_fwnode(&platform_bus_type, usb_fwnode);
> + fwnode_handle_put(usb_fwnode);
> + if (!usb_dev)
> + return -ENODEV;
> +
> + mode = usb_get_role_switch_default_mode(usb_dev);
> + if (mode == USB_DR_MODE_HOST)
> + u2_phy_instance_role_set(instance, USB_ROLE_HOST);
> + else
> + u2_phy_instance_role_set(instance, USB_ROLE_DEVICE);
> +
> + INIT_DELAYED_WORK(&instance->dr_work, u2_phy_role_switch_work);
> +
> + return 0;
> +}
> +
> static void u2_phy_instance_init(struct mtk_tphy *tphy,
> struct mtk_phy_instance *instance)
> {
> struct u2phy_banks *u2_banks = &instance->u2_banks;
> void __iomem *com = u2_banks->com;
> u32 index = instance->index;
> + int ret;
> +
> + if (instance->software_role_switch) {
> + ret = u2_phy_software_role_switch_init(instance);
> + if (ret)
> + dev_warn(&instance->phy->dev, "failed to initialize role switching\n");
> + }
>
> /* switch to USB function, and enable usb pll */
> mtk_phy_clear_bits(com + U3P_U2PHYDTM0, P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM);
> @@ -883,6 +1004,18 @@ static void u2_phy_instance_power_on(struct mtk_tphy *tphy,
>
> mtk_phy_set_bits(com + U3P_U2PHYDTM0, P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM);
> }
> +
> + if (instance->software_role_switch) {
> + /* Set FORCE modes for manual role switching */
> + mtk_phy_set_bits(com + U3P_U2PHYDTM1, P2C_FORCE_IDPULLUP
> + | P2C_FORCE_IDDIG | P2C_FORCE_AVALID | P2C_FORCE_VBUSVALID
> + | P2C_FORCE_SESSEND);
> + mtk_phy_set_bits(com + U3P_U2PHYDTM1, P2C_RG_IDPULLUP | P2C_RG_BVALID);
> +
> + if (!instance->role_switch)
> + schedule_delayed_work(&instance->dr_work, msecs_to_jiffies(100));
> + }
> +
> dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
> }
>
> @@ -906,6 +1039,9 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy,
> mtk_phy_clear_bits(com + U3D_U2PHYDCR0, P2C_RG_SIF_U2PLL_FORCE_ON);
> }
>
> + if (instance->role_switch)
> + cancel_delayed_work_sync(&instance->dr_work);
> +
> dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);
> }
>
> @@ -940,6 +1076,9 @@ static void u2_phy_instance_set_mode(struct mtk_tphy *tphy,
> tmp &= ~P2C_RG_IDDIG;
> break;
> case PHY_MODE_USB_OTG:
> + /* We are managing role in workqueue */
> + if (instance->software_role_switch)
> + return;
> tmp &= ~(P2C_FORCE_IDDIG | P2C_RG_IDDIG);
> break;
> default:
> @@ -1129,6 +1268,11 @@ static void phy_parse_property(struct mtk_tphy *tphy,
> if (instance->type == PHY_TYPE_USB3)
> instance->type_force_mode = device_property_read_bool(dev, "mediatek,force-mode");
>
> + instance->software_role_switch =
> + device_property_read_bool(dev, "mediatek,software-role-switch");
> + if (instance->software_role_switch)
> + dev_info(dev, "software role switch enabled\n");
> +
> if (instance->type != PHY_TYPE_USB2)
> return;
>
> @@ -1618,6 +1762,10 @@ static int mtk_tphy_probe(struct platform_device *pdev)
> struct phy *phy;
> int retval;
>
> + /* filter non-phy nodes (e.g. graphs) */
> + if (!of_find_property(child_np, "reg", NULL))
> + continue;
> +
> instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
> if (!instance)
> return -ENOMEM;
This patch made USB role-switching work on the MT6878 SoC. As such:
Tested-by: Igor Belwon <igor.belwon@mentallysanemainliners.org>
Kind regards,
Igor
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-08-28 23:26 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-14 23:48 [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch Arseniy Velikanov
2025-08-14 23:48 ` [PATCH v1 2/2] phy: mediatek: tphy: Add software role switching Arseniy Velikanov
2025-08-19 3:31 ` kernel test robot
2025-08-28 20:06 ` Igor Belwon
2025-08-15 2:29 ` [PATCH v1 1/2] dt-bindings: phy: mtk-tphy: add property for software role switch Rob Herring (Arm)
2025-08-15 6:28 ` Krzysztof Kozlowski
2025-08-24 6:25 ` Arseniy Velikanov
2025-08-24 8:18 ` Krzysztof Kozlowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).