Rockpi 4b: Uppper USB3 port is not functioning in Manjaro arm 20.02

I flashed the 20.02 xfce image into emmc, and installed it on a rockpi4b board, system can be booted and the desktop is working, but the higher USB3 port is not working no matter the hardware switch is in host mode or device mode. The rest USB2 ports and lower USB3 port (host only) is working.
I tried the rockpi4 official debian 9 image (with a 4.4.154-105 kernel) in radax website, the higher USB3 port can properly work in both host mode and device mode (hardware switch in device side, modprobe g_mass_storage proves to work in dmesg).
I am thinking is it because of the dtb board file configuration issue? So I use dtc to de-compile the rk3399-rockpi-4.dtb in /boot/dtbs/rockchip folder into dts format, and cannot find the problem:

dtc -I dtb -O dts -o rk3399-rockpi-4.dts rk3399-rockpi-4.dtb

usb@fe800000 {
compatible = “rockchip,rk3399-dwc3”;
#address-cells = <0x02>;
#size-cells = <0x02>;
ranges;
clocks = <0x08 0x81 0x08 0x83 0x08 0xf6 0x08 0xf8 0x08 0xf4 0x08 0xf9>;
clock-names = “ref_clk\0suspend_clk\0bus_clk\0aclk_usb3_rksoc_axi_perf\0aclk_usb3\0grf_clk”;
resets = <0x08 0x125>;
reset-names = “usb3-otg”;
status = “okay”;
phandle = <0xc4>;

  dwc3 {
  	compatible = "snps,dwc3";
  	reg = <0x00 0xfe800000 0x00 0x100000>;
  	interrupts = <0x00 0x69 0x04 0x00>;
  	clocks = <0x08 0x81 0x08 0xf6 0x08 0x83>;
  	clock-names = "ref\0bus_early\0suspend";
  	dr_mode = "otg";
  	phys = <0x2b 0x2c>;
  	phy-names = "usb2-phy\0usb3-phy";
  	phy_type = "utmi_wide";
  	snps,dis_enblslpm_quirk;
  	snps,dis-u2-freeclk-exists-quirk;
  	snps,dis_u2_susphy_quirk;
  	snps,dis-del-phy-power-chg-quirk;
  	snps,dis-tx-ipgap-linecheck-quirk;
  	power-domains = <0x16 0x18>;
  	status = "okay";
  	phandle = <0xc5>;
  };

};

usb@fe900000 {
compatible = “rockchip,rk3399-dwc3”;
#address-cells = <0x02>;
#size-cells = <0x02>;
ranges;
clocks = <0x08 0x82 0x08 0x84 0x08 0xf7 0x08 0xf8 0x08 0xf4 0x08 0xf9>;
clock-names = “ref_clk\0suspend_clk\0bus_clk\0aclk_usb3_rksoc_axi_perf\0aclk_usb3\0grf_clk”;
resets = <0x08 0x126>;
reset-names = “usb3-otg”;
status = “okay”;
phandle = <0xc6>;

  dwc3 {
  	compatible = "snps,dwc3";
  	reg = <0x00 0xfe900000 0x00 0x100000>;
  	interrupts = <0x00 0x6e 0x04 0x00>;
  	clocks = <0x08 0x82 0x08 0xf7 0x08 0x84>;
  	clock-names = "ref\0bus_early\0suspend";
  	dr_mode = "host";
  	phys = <0x2d 0x2e>;
  	phy-names = "usb2-phy\0usb3-phy";
  	phy_type = "utmi_wide";
  	snps,dis_enblslpm_quirk;
  	snps,dis-u2-freeclk-exists-quirk;
  	snps,dis_u2_susphy_quirk;
  	snps,dis-del-phy-power-chg-quirk;
  	snps,dis-tx-ipgap-linecheck-quirk;
  	power-domains = <0x16 0x18>;
  	status = "okay";
  	phandle = <0xc7>;
  };

};

I extracted the dtb file (working one) from debian 9 image as well for comparison, cannot figure out what to do:

dtc -I dtb -O dts -o rockpi-4b-linux.dts rockpi-4b-linux.dtb

usb0 {
compatible = “rockchip,rk3399-dwc3”;
clocks = <0x08 0x81 0x08 0x83 0x08 0xf6 0x08 0xf9>;
clock-names = “ref_clk\0suspend_clk\0bus_clk\0grf_clk”;
power-domains = <0x15 0x18>;
resets = <0x08 0x125>;
reset-names = “usb3-otg”;
#address-cells = <0x02>;
#size-cells = <0x02>;
ranges;
status = “okay”;
extcon = <0x28>;
phandle = <0xe8>;

  dwc3@fe800000 {
  	compatible = "snps,dwc3";
  	reg = <0x00 0xfe800000 0x00 0x100000>;
  	interrupts = <0x00 0x69 0x04 0x00>;
  	dr_mode = "otg";
  	phys = <0x29 0x2a>;
  	phy-names = "usb2-phy\0usb3-phy";
  	phy_type = "utmi_wide";
  	snps,dis_enblslpm_quirk;
  	snps,dis-u2-freeclk-exists-quirk;
  	snps,dis_u2_susphy_quirk;
  	snps,dis-del-phy-power-chg-quirk;
  	snps,tx-ipgap-linecheck-dis-quirk;
  	snps,xhci-slow-suspend-quirk;
  	snps,usb3-warm-reset-on-resume-quirk;
  	status = "okay";
  	phandle = <0xe9>;
  };

};

usb1 {
compatible = “rockchip,rk3399-dwc3”;
clocks = <0x08 0x82 0x08 0x84 0x08 0xf7 0x08 0xf9>;
clock-names = “ref_clk\0suspend_clk\0bus_clk\0grf_clk”;
power-domains = <0x15 0x18>;
resets = <0x08 0x126>;
reset-names = “usb3-otg”;
#address-cells = <0x02>;
#size-cells = <0x02>;
ranges;
status = “okay”;
phandle = <0xea>;

  dwc3@fe900000 {
  	compatible = "snps,dwc3";
  	reg = <0x00 0xfe900000 0x00 0x100000>;
  	interrupts = <0x00 0x6e 0x04 0x00>;
  	dr_mode = "host";
  	phys = <0x2b 0x2c>;
  	phy-names = "usb2-phy\0usb3-phy";
  	phy_type = "utmi_wide";
  	snps,dis_enblslpm_quirk;
  	snps,dis-u2-freeclk-exists-quirk;
  	snps,dis_u2_susphy_quirk;
  	snps,dis-del-phy-power-chg-quirk;
  	snps,tx-ipgap-linecheck-dis-quirk;
  	snps,xhci-slow-suspend-quirk;
  	snps,usb3-warm-reset-on-resume-quirk;
  	status = "okay";
  	phandle = <0xeb>;
  };

};

I tried to rename the debian 9 extracted dtb file and replace the one used in manjaro 20.02 in /boot folder, it results in not being able to boot the system completely.
Modifying the rk3399-rockpi-4.dts for manjaro:
“dr_mode” from “otg” to “host” in dts file then re-compiled dtb and replace the file in /boot/dtbs/rockchip folder, the upper USB3 port can work in host mode, but the hardware switch is not working to switch it into device mode, meaning in current manjaro there is no way to get the upper port working in device mode.
And I noticed that the disk reading LED working under debian 9 will not work manjaro as well, so I assume it is all about the dts definition issue in mainline kernel which needs to be updated?
Any clue how to fix that?

The same topic raised in Manjaro arm forum as well:
https://forum.manjaro.org/t/rockpi-4b-one-of-the-usb3-port-is-not-functioning-in-20-02/128896/4

1 Like

Hi,I have a patch only just for debug,you can refer to this.

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts
index d02d053..ed2e44d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dts
@@ -93,7 +93,7 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&vcc5v0_typec_en>;
 		regulator-name = "vcc5v0_typec";
-		regulator-always-on;
+	//	regulator-always-on;
 		vin-supply = <&vcc5v0_sys>;
 	};
 
@@ -631,6 +631,7 @@
 	status = "okay";
 
 	u2phy0_otg: otg-port {
+		vbus-supply = <&vcc5v0_typec>;
 		status = "okay";
 	};
 
@@ -696,6 +697,7 @@
 
 &usbdrd_dwc3_0 {
 	status = "okay";
+	extcon = <&u2phy0>;
 	dr_mode = "otg";
 };
 

diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index eae865f..20d79232 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -69,6 +69,7 @@ enum usb_chg_state {
 static const unsigned int rockchip_usb2phy_extcon_cable[] = {
 	EXTCON_USB,
 	EXTCON_USB_HOST,
+	EXTCON_USB_VBUS_EN,
 	EXTCON_CHG_USB_SDP,
 	EXTCON_CHG_USB_CDP,
 	EXTCON_CHG_USB_DCP,
@@ -129,13 +130,29 @@ struct rockchip_usb2phy_port_cfg {
 	struct usb2phy_reg	bvalid_det_en;
 	struct usb2phy_reg	bvalid_det_st;
 	struct usb2phy_reg	bvalid_det_clr;
+	struct usb2phy_reg	bypass_dm_en;
+	struct usb2phy_reg	bypass_sel;
+	struct usb2phy_reg	bypass_iomux;
+	struct usb2phy_reg	bypass_bc;
+	struct usb2phy_reg	bypass_otg;
+	struct usb2phy_reg	bypass_host;
 	struct usb2phy_reg	ls_det_en;
 	struct usb2phy_reg	ls_det_st;
 	struct usb2phy_reg	ls_det_clr;
+	struct usb2phy_reg	iddig_output;
+	struct usb2phy_reg	iddig_en;
+	struct usb2phy_reg	idfall_det_en;
+	struct usb2phy_reg	idfall_det_st;
+	struct usb2phy_reg	idfall_det_clr;
+	struct usb2phy_reg	idrise_det_en;
+	struct usb2phy_reg	idrise_det_st;
+	struct usb2phy_reg	idrise_det_clr;
 	struct usb2phy_reg	utmi_avalid;
 	struct usb2phy_reg	utmi_bvalid;
+	struct usb2phy_reg	utmi_iddig;
 	struct usb2phy_reg	utmi_ls;
 	struct usb2phy_reg	utmi_hstdet;
+	struct usb2phy_reg	vbus_det_en;
 };
 

@@ -178,13 +195,16 @@ struct rockchip_usb2phy_port {
 	unsigned int	port_id;
 	bool		suspended;
 	bool		vbus_attached;
+	bool        vbus_enabled;
 	int		bvalid_irq;
 	int		ls_irq;
 	int		otg_mux_irq;
+	int		id_irq;
 	struct mutex	mutex;
 	struct		delayed_work chg_work;
 	struct		delayed_work otg_sm_work;
 	struct		delayed_work sm_work;
+	struct      regulator *vbus;
 	const struct	rockchip_usb2phy_port_cfg *port_cfg;
 	struct notifier_block	event_nb;
 	enum usb_otg_state	state;
@@ -214,6 +234,7 @@ struct rockchip_usb2phy {
 	struct clk	*clk;
 	struct clk	*clk480m;
 	struct clk_hw	clk480m_hw;
+	bool            edev_self;
 	enum usb_chg_state	chg_state;
 	enum power_supply_type	chg_type;
 	u8			dcd_retries;
@@ -393,6 +414,8 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy)
 			dev_err(rphy->dev, "failed to register extcon device\n");
 			return ret;
 		}
+
+		rphy->edev_self = true;
 	}
 
 	rphy->edev = edev;
@@ -400,6 +423,28 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy)
 	return 0;
 }
 
+static int rockchip_set_vbus_power(struct rockchip_usb2phy_port *rport,bool en)
+{
+	int ret = 0;
+
+	if (!rport->vbus)
+		return 0;
+
+	if (en && !rport->vbus_enabled) {
+		ret = regulator_enable(rport->vbus);
+		if (ret)
+			dev_err(&rport->phy->dev,
+					"Failed to enable VBUS supply\n");
+		} else if (!en && rport->vbus_enabled) {
+			ret = regulator_disable(rport->vbus);
+		}
+
+	if (ret == 0)
+		rport->vbus_enabled = en;
+
+	return ret;
+}
+
 static int rockchip_usb2phy_init(struct phy *phy)
 {
 	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
@@ -407,10 +452,11 @@ static int rockchip_usb2phy_init(struct phy *phy)
 	int ret = 0;
 
 	mutex_lock(&rport->mutex);
-
+printk("busb rport->port_id=%d\n",rport->port_id );
 	if (rport->port_id == USB2PHY_PORT_OTG) {
 		if (rport->mode != USB_DR_MODE_HOST &&
 		    rport->mode != USB_DR_MODE_UNKNOWN) {
+			printk("busb enabled irq\n");
 			/* clear bvalid status and enable bvalid detect irq */
 			ret = property_enable(rphy->grf,
 					      &rport->port_cfg->bvalid_det_clr,
@@ -423,9 +469,34 @@ static int rockchip_usb2phy_init(struct phy *phy)
 					      true);
 			if (ret)
 				goto out;
+		
+			/* clear id status and enable id detect irq */
+			ret = property_enable(rphy->grf,
+					      &rport->port_cfg->idfall_det_clr,
+					      true);
+			if (ret)
+				goto out;
+
+			ret = property_enable(rphy->grf,
+					      &rport->port_cfg->idfall_det_en,
+					      true);
+			if (ret)
+				goto out;
+
+			ret = property_enable(rphy->grf,
+					      &rport->port_cfg->idrise_det_clr,
+					      true);
+			if (ret)
+				goto out;
+
+			ret = property_enable(rphy->grf,
+					      &rport->port_cfg->idrise_det_en,
+					      true);
+			if (ret)
+				goto out;
 
 			schedule_delayed_work(&rport->otg_sm_work,
					      OTG_SCHEDULE_DELAY * 3);
 		} else {
 			/* If OTG works in host only mode, do nothing. */
 			dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode);
@@ -458,7 +529,7 @@ static int rockchip_usb2phy_power_on(struct phy *phy)
 	int ret;
 
 	dev_dbg(&rport->phy->dev, "port power on\n");
-
+printk("busb port power on\n");
 	if (!rport->suspended)
 		return 0;
 
@@ -502,7 +573,7 @@ static int rockchip_usb2phy_power_off(struct phy *phy)
 static int rockchip_usb2phy_exit(struct phy *phy)
 {
 	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
-
+printk("busb rockchip_usb2phy_exit \n");
 	if (rport->port_id == USB2PHY_PORT_OTG &&
 	    rport->mode != USB_DR_MODE_HOST &&
 	    rport->mode != USB_DR_MODE_UNKNOWN) {
@@ -514,11 +585,61 @@ static int rockchip_usb2phy_exit(struct phy *phy)
 	return 0;
 }
 
+static int rockchip_usb2phy_set_mode(struct phy *phy, enum phy_mode mode , int submode)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	bool vbus_det_en;
+	int ret = 0;
+	if (rport->port_id != USB2PHY_PORT_OTG)
+		return ret;
+
+printk("busb rockchip_usb2phy_set_mode mode = %d,submode=%d\n",mode,submode);
+	switch (mode) {
+	case PHY_MODE_USB_OTG:
+		/*
+		 * In case of using vbus to detect connect state by u2phy,
+		 * enable vbus detect on otg mode.
+		 *
+		 * fallthrough
+		 */
+	case PHY_MODE_USB_DEVICE:
+		/* Disable VBUS supply */
+		rockchip_set_vbus_power(rport, false);
+		extcon_set_state_sync(rphy->edev, EXTCON_USB_VBUS_EN, false);
+		vbus_det_en = true;
+		break;
+	case PHY_MODE_USB_HOST:
+		/* Enable VBUS supply */
+		ret = rockchip_set_vbus_power(rport, true);
+		if (ret) {
+			dev_err(&rport->phy->dev,
+				"Failed to set host mode\n");
+			return ret;
+		}
+
+		extcon_set_state_sync(rphy->edev, EXTCON_USB_VBUS_EN, true);
+		/* fallthrough */
+	case PHY_MODE_INVALID:
+		vbus_det_en = false;
+		break;
+	default:
+		dev_info(&rport->phy->dev, "illegal mode\n");
+		printk("busb illegal mode\n");
+		return ret;
+	}
+
+	ret = property_enable(rphy->grf, &rport->port_cfg->vbus_det_en, vbus_det_en);
+
+	return ret;
+}
+
 static const struct phy_ops rockchip_usb2phy_ops = {
 	.init		= rockchip_usb2phy_init,
 	.exit		= rockchip_usb2phy_exit,
 	.power_on	= rockchip_usb2phy_power_on,
 	.power_off	= rockchip_usb2phy_power_off,
+//	.set_mode   = rockchip_usb2phy_set_mode,
 	.owner		= THIS_MODULE,
 };
 
@@ -540,7 +661,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
 	delay = OTG_SCHEDULE_DELAY;
 	dev_dbg(&rport->phy->dev, "%s otg sm work\n",
 		usb_otg_state_string(rport->state));
-
+	printk("busb rockchip_usb2phy_otg_sm_work %s otg sm work %d\n",usb_otg_state_string(rport->state),rport->state);
 	switch (rport->state) {
 	case OTG_STATE_UNDEFINED:
 		rport->state = OTG_STATE_B_IDLE;
@@ -548,13 +669,16 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
 			rockchip_usb2phy_power_off(rport->phy);
 		/* fall through */
 	case OTG_STATE_B_IDLE:
+		printk("busb HOST = %d,VBUS_EN=%d,vbus_attached=%d\n",extcon_get_state(rphy->edev, EXTCON_USB_HOST),extcon_get_state(rphy->edev,EXTCON_USB_VBUS_EN),rport->vbus_attached);
 		if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) {
 			dev_dbg(&rport->phy->dev, "usb otg host connect\n");
+			printk("busb usb otg host connect\n");
 			rport->state = OTG_STATE_A_HOST;
 			rockchip_usb2phy_power_on(rport->phy);
 			return;
 		} else if (vbus_attach) {
 			dev_dbg(&rport->phy->dev, "vbus_attach\n");
+			printk("busb vbus_attach rphy->chg_state = %d\n",rphy->chg_state);
 			switch (rphy->chg_state) {
 			case USB_CHG_STATE_UNDEFINED:
 				schedule_delayed_work(&rport->chg_work, 0);
@@ -689,7 +813,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)
 	struct regmap *base = get_reg_base(rphy);
 	bool is_dcd, tmout, vout;
 	unsigned long delay;
-
+printk("busb chg detection work state = %d\n",rphy->chg_state);
 	dev_dbg(&rport->phy->dev, "chg detection work state = %d\n",
 		rphy->chg_state);
 	switch (rphy->chg_state) {
@@ -923,6 +1047,42 @@ static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t rockchip_usb2phy_id_irq(int irq, void *data)
+{
+	struct rockchip_usb2phy_port *rport = data;
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+	bool cable_vbus_state = false;
+printk("brian rockchip_usb2phy_id_irq \n");
+	if (!property_enabled(rphy->grf, &rport->port_cfg->idfall_det_st) &&
+	    !property_enabled(rphy->grf, &rport->port_cfg->idrise_det_st))
+		return IRQ_NONE;
+
+	mutex_lock(&rport->mutex);
+
+	/* clear id fall or rise detect irq pending status */
+	if (property_enabled(rphy->grf, &rport->port_cfg->idfall_det_st)) {
+		property_enable(rphy->grf, &rport->port_cfg->idfall_det_clr,
+				true);
+		cable_vbus_state = true;
+	} else if (property_enabled(rphy->grf, &rport->port_cfg->idrise_det_st)) {
+		property_enable(rphy->grf, &rport->port_cfg->idrise_det_clr,
+				true);
+		cable_vbus_state = false;
+	}
+
+	extcon_set_state(rphy->edev, EXTCON_USB_HOST, cable_vbus_state);
+	extcon_set_state(rphy->edev, EXTCON_USB_VBUS_EN, cable_vbus_state);
+
+	extcon_sync(rphy->edev, EXTCON_USB_HOST);
+	extcon_sync(rphy->edev, EXTCON_USB_VBUS_EN);
+
+	rockchip_set_vbus_power(rport, cable_vbus_state);
+
+	mutex_unlock(&rport->mutex);
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data)
 {
 	struct rockchip_usb2phy_port *rport = data;
@@ -980,7 +1140,8 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
 					  struct rockchip_usb2phy_port *rport,
 					  struct device_node *child_np)
 {
-	int ret;
+	int ret = 0;
+	int iddig;
 
 	rport->port_id = USB2PHY_PORT_OTG;
 	rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
@@ -994,13 +1155,34 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
 	 */
 	rport->suspended = true;
 	rport->vbus_attached = false;
+	rport->vbus_enabled = false;
 
+	rport->vbus = devm_regulator_get_optional(&rport->phy->dev, "vbus");
+	if (IS_ERR(rport->vbus)) {
+		ret = PTR_ERR(rport->vbus);
+		if (ret == -EPROBE_DEFER)
+			return ret;
+		printk("busb Failed to get VBUS supply regulator\n");
+		dev_warn(&rport->phy->dev, "Failed to get VBUS supply regulator\n");
+		rport->vbus = NULL;
+	}
+	if(rport->vbus != NULL)
+		printk("busb get rport->vbus ok\n");
 	mutex_init(&rport->mutex);
 
 	rport->mode = of_usb_get_dr_mode_by_phy(child_np, -1);
 	if (rport->mode == USB_DR_MODE_HOST ||
 	    rport->mode == USB_DR_MODE_UNKNOWN) {
-		ret = 0;
+		if(rphy->edev_self) {
+			extcon_set_state(rphy->edev, EXTCON_USB, false);
+			extcon_set_state(rphy->edev, EXTCON_USB_HOST, true);
+			extcon_set_state(rphy->edev, EXTCON_USB_VBUS_EN, true);
+			ret = rockchip_set_vbus_power(rport, true);
+			printk("busb rockchip_set_vbus_power ret=%d\n",ret);
+			if(ret)
+				return ret;
+		}	
+		//ret = 0;
 		goto out;
 	}
 
@@ -1044,6 +1226,37 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
 				"failed to request otg-bvalid irq handle\n");
 			goto out;
 		}
+
+		if (rphy->edev_self) {
+		
+			rport->id_irq = of_irq_get_byname(child_np, "otg-id");
+			if (rport->id_irq < 0) {
+				dev_err(rphy->dev, "no otg id irq provided\n");
+				ret = rport->id_irq;
+				goto out;
+			}
+
+			ret = devm_request_threaded_irq(rphy->dev, rport->id_irq, NULL,
+							rockchip_usb2phy_id_irq,
+							IRQF_ONESHOT,
+							"rockchip_usb2phy_id", rport);
+			if (ret) {
+				dev_err(rphy->dev, "failed to request otg-id irq handle\n");
+				return ret;
+			}
+
+			iddig = property_enabled(rphy->grf, &rport->port_cfg->utmi_iddig);
+			if(!iddig) {
+				extcon_set_state(rphy->edev, EXTCON_USB, false);
+				extcon_set_state(rphy->edev, EXTCON_USB_HOST, true);
+				extcon_set_state(rphy->edev, EXTCON_USB_VBUS_EN, true);
+
+				ret = rockchip_set_vbus_power(rport, true);
+				printk("busb rockchip_set_vbus_power ret=%d\n",ret);
+				if (ret)
+					return ret;
+			}
+		}
 	}
 
 	if (!IS_ERR(rphy->edev)) {
@@ -1108,6 +1321,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
 	phy_cfgs = match->data;
 	rphy->chg_state = USB_CHG_STATE_UNDEFINED;
 	rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
+	rphy->edev_self = false;
 	platform_set_drvdata(pdev, rphy);
 
 	ret = rockchip_usb2phy_extcon_register(rphy);
@@ -1329,6 +1543,17 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
 				.bvalid_det_en	= { 0xe3c0, 3, 3, 0, 1 },
 				.bvalid_det_st	= { 0xe3e0, 3, 3, 0, 1 },
 				.bvalid_det_clr	= { 0xe3d0, 3, 3, 0, 1 },
+				.bypass_dm_en	= { 0xe450, 2, 2, 0, 1 },
+				.bypass_sel	= { 0xe450, 3, 3, 0, 1 },
+				.idfall_det_en	= { 0xe3c0, 5, 5, 0, 1 },
+				.idfall_det_st	= { 0xe3e0, 5, 5, 0, 1 },
+				.idfall_det_clr	= { 0xe3d0, 5, 5, 0, 1 },
+				.idrise_det_en	= { 0xe3c0, 4, 4, 0, 1 },
+				.idrise_det_st	= { 0xe3e0, 4, 4, 0, 1 },
+				.idrise_det_clr	= { 0xe3d0, 4, 4, 0, 1 },
+				.ls_det_en	= { 0xe3c0, 2, 2, 0, 1 },
+				.ls_det_st	= { 0xe3e0, 2, 2, 0, 1 },
+				.ls_det_clr	= { 0xe3d0, 2, 2, 0, 1 },
 				.utmi_avalid	= { 0xe2ac, 7, 7, 0, 1 },
 				.utmi_bvalid	= { 0xe2ac, 12, 12, 0, 1 },
 			},
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
index 2bdf643..1c8e971 100644
--- a/include/linux/extcon.h
+++ b/include/linux/extcon.h
@@ -37,6 +37,7 @@
 /* USB external connector */
 #define EXTCON_USB		1
 #define EXTCON_USB_HOST		2
+#define EXTCON_USB_VBUS_EN		3
 
 /*
  * Charging external connector

I worked on mainline 5.4-rc2

I believe its fixed in Armbian. That should be you starting refference.

So this requires to apply the patches to 3 files and recompile the kernel, or I can just recompile the dts file and a driver?

I managed to recompile the kernel (5.6.0-0.4-MANJARO-ARM, with source here), and the patch works if the new generated kernel package is installed by overwriting conflicts; only install the newly compile dtb file will not work, have to recompile and install the new kernel.
Still some issues:

  1. If the hardware host/gadget switch is in host position, if you restart the board, it won’t work by default, you have to toggle the switch (turn it to device position then turn it back), then the host mode will work. The gadget (device) position will work by default even after a restart if the switch stays in device position. I don’t know whether there is way to further fix that by radxa?
  2. When you change the switch position from device to host, then plug in a usb device like a usb mouse, in dmesg log, you find below ethernet interrupt:
[  446.087701] rk_gmac-dwmac fe300000.ethernet eth0: Link is Down
[  450.248113] rk_gmac-dwmac fe300000.ethernet eth0: Link is Up - 1Gbps/Full - flow control off

Not sure whether it is a bug because of the patch?
3. When the port is in device mode, and you connect it to a host pc, in dmesg log, it keeps printing below floods:

[  333.929037] busb rockchip_usb2phy_otg_sm_work b_peripheral otg sm work 3
[  336.008943] busb rockchip_usb2phy_otg_sm_work b_peripheral otg sm work 3
[  338.088918] busb rockchip_usb2phy_otg_sm_work b_peripheral otg sm work 3
[  340.168879] busb rockchip_usb2phy_otg_sm_work b_peripheral otg sm work 3
[  342.248891] busb rockchip_usb2phy_otg_sm_work b_peripheral otg sm work 3
[  344.328856] busb rockchip_usb2phy_otg_sm_work b_peripheral otg sm work 3
[  346.408758] busb rockchip_usb2phy_otg_sm_work b_peripheral otg sm work 3
......

I think this is not a problem and easy to be modified because this is a debug patch, logging prints can be prohibited as official patch.

1.This is the patch’s bug,we will fix it ASAP,maybe you can help us :smile:
2.your log is for gmac,not usb,it’s not the patch’s bug
3.have you tried the armbian like @igorp said?

No, I didn’t try armbian, do you have linked image which is suitable for rockpi4b? Or better I can try that with PXE boot?

you choose one by yourself
https://www.armbian.com/rock-pi-4/#kernels-archive-all

I ported the following u2phy driver to mainline 5.4,and tested ok

Great, does that mean later releases, like mainline 5.6 will automatically inherit the driver?

I’m not sure :smile:

Will this patch/changes be merged into linux mainline kernel? I think this should be submitted by radxa to mainline kernel.

1 Like

You mean 4.4 instead of 5.4 here? Actually I tested Armbian with 5.4 kernel, the port doesn’t work in device mode at all, the hardware switch doesn’t change OTG mode, always the rockpi4b stays in host mode.

Maybe the usb dr_mode is set to host.what’s your application?

Yes, it is. A workaround was applied to set port as host since more people use it that way.

Brian, will your patch be submitted upstream? What should a user do who wants this functionality

Use rockpi4 as a “USB proxy”, backend is iscsi or NFS, so consoles like Nintendo Switch or Playstation 4 can recognize a large USB disk for game storage, while the storage is actually coming from a NAS server.
Reference link: https://gbatemp.net/threads/sxos-loading-xcis-over-the-network-with-a-raspberry-pi.540943/

it’s really good idea.
@aaditya about the usb patch,it’s just a temporary patch,we need some time to test.

1 Like

Hello! where you able to get USB3 device mode working with the 5.4 kernel? if so what patchset did you use? I am using RockPi4b and was able to get 5.4.y branch to compile and boot-up. But I am having trouble getting the USB device mode to work correctly. The USB connection keeps resetting when I plug it into a PC (tried multiple cables/PC’s).

Thank You!