Jump to content

NanoPC T4: how to make DisplayPort & Type-C working in 5.* kernels


Oleksii

Recommended Posts

Hello, nanopc t4 folks,

 

Some, not so long time ago, I worked on fusb302.ko driver and device tree improvements in order to make USB Type-C port working properly in the mainline 5.* kernel. I managed to get DisplayPort over type-C + some general type-c handling improved before my board simply died. Unfortunately, I was not able to finish all the planned work and cannot continue further :( However, I guess, working DP is already fairly good achievement that might be interesting for many of us. Hereby, I want to publish some patches to the mainline!!! driver and device tree that add missing functionality, so one can get DP+type-C working on NanoPC T4 (and all RK3399 based boards with Fairchild FUSB302 chip for PD with relatively small DT adjustments). I would be very happy if results of my work can be helpful to others and extremely happy if there any volunteers, who are willing to continue work on this subject. My primary goal was to contribute to Armbian, first of all, with a potential mainline repo contribution. What was added:

  • Extcon notifications support (type-c related cables) in the stock fusb302 driver (developed by Google folks, but also used by Intel :) if I understand correctly)
  • DisplayPort altmode is registered automatically, if device tree has proper modelling for that
  • DisplayPort altmode is entered as soon as DP cable connection is detected (both DP+USB3.0 and DP only pin assignments are supported) 
  • DisplayPort altmode is handled by the unified DP altmode driver rather than custom out-of-tree PD chip driver
  • "connector" node modelling in the device tree according to the mainline kernel docs and modern requirements
  • fusb node phandle is still specified as extcon source for Rockchip's proprietary drivers, however, last can be easily adjusted to resolve extcon directly from connector node link (as soon as extcon property is declared as deprecated for all new development).
  • fusb302 driver is now correctly linked to dwc3 driver which provides role_switch functionality (+1 step to correct "Dual Role" mode handling based on the cable detection). This also eliminates annoying error message in the boot log: "OF: graph: no port node found in /i2c@ff3d0000/typec-portc@22"

 

Please, also notice that type-c mode is forced to Host as in the most of rk3399 based SBC dtbs presently. This is rather a workaround for such boards, than a permanent solution, until all necessary bits are developed for correct role switching in the drivers. I kindly ask some NanoPC T4 owners to build mainline kernel with my patches and test whether expected functionality also works for you. Those patches apply to linux kernel since 5.6 when I started to work, but should also apply to way earlier versions according to my brief analysis of kernel commits history.

 

fusb302-add-extcon.patch rk3399-nanopc-t4-type-c-modeling.patch

Link to comment
Share on other sites

I downloaded and compiled current. There was a couple errors

I will try again using "dev" since that is post 5.6


arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts:167.35-169.5: ERROR (phandle_references): /usb@fe800000/usb@fe800000/port/endpoint: Reference to non-existent node or label "fusb0_role_sw"

arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts:146.29-148.5: ERROR (phandle_references): /syscon@ff770000/usb2-phy@e450/otg-port/port/endpoint: Reference to non-existent node or label "usbc_hs"

arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts:124.29-126.5: ERROR (phandle_references): /phy@ff7c0000/dp-port/port/endpoint: Reference to non-existent node or label "usbc_dp"

arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts:136.29-138.5: ERROR (phandle_references): /phy@ff7c0000/usb3-port/port/endpoint: Reference to non-existent node or label "usbc_ss"

ERROR: Input tree has errors, aborting (use -f to force output)
make[2]: *** [scripts/Makefile.lib:291: arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dtb] Error 2
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [scripts/Makefile.build:500: arch/arm64/boot/dts/rockchip] Error 2
make: *** [Makefile:1246: dtbs] Error 2

 

 

Thanks. I am interested in learning this. The changes are a bit extreme. But I learn tons as I go.

I dont have a DisplayPort but I have a few Anker Type-C hubs and power strips.

To be frank, I bought the Metal Case and Heat-sink Fan. This has improved things.

I run 4.4.213 and Ubuntu Focal Desktop. I am pretty happy now and I have

decided on new programming directions. I run VSCode on my NanoPC-T4.

I am excited by the Gnome3 and moving to TypeScript and Node.

I mostly run Sage Math and Python Science software. This box compiles and runs some advanced

software. Nonetheless I am learning ARM architecture and will keep at the RK3399 and Synopsis

SoC architecture.  I am going to see if the new 5.x kernel can just connect my Anker Type-C hub.

 

I do want to thank everyone for their work on the NanoPC.

 

NOTE: the Ubuntu NetworkManager Setting has a bug and crashes when updating.

I just dont use the GUI. I am not saying running Ubuntu Gnome3 Desktop is ready to go.

It is actually amazingly good though. anyhow...but it will be better under new Panfrost and friends.

Link to comment
Share on other sites

Hi Oleksii

At first I downloaed your patches and put it in armbian's build tool, it report errors with fusb302 patch

Then I downloaded your rk3399-nanopc-t4-type-c-modeling.patch only and add two lines

extcon-cables = <1 2 5 6 9 10 12 44>;
typec-altmodes = <0xff01 1 0x001c0000 1>;

based on Helios64 commit on armbian's git (ea5bf1afd56423c069dd3267e9effc2c62d6706c), then I connect type-c monitor to my nanopct4 board and get these dmesg info:

root@nanopct4:~# dmesg |grep dp
[    5.720996] systemd[1]: Created slice system-modprobe.slice.
[    5.813967] systemd[1]: Starting Coldplug All udev Devices...
[    6.497528] systemd[1]: Finished Coldplug All udev Devices.
[    6.915278] rockchip-drm display-subsystem: bound fec00000.dp (ops cdn_dp_component_ops [rockchipdrm])
[    6.919926] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Not connected. Disabling cdn
[    7.222288] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Not connected. Disabling cdn
root@nanopct4:~# dmesg |grep typec
[    1.413642] vbus_typec: supplied by vcc5v0_sys
[    7.797465] typec_displayport port0-partner.0: No compatible pin configuration found:0000 -> 0014, 001c <- 0000

Do you have any ideas on how to fix it?

Thanks a lot!

Link to comment
Share on other sites

4 hours ago, charliealex73 said:

Hi Oleksii

At first I downloaed your patches and put it in armbian's build tool, it report errors with fusb302 patch

Then I downloaded your rk3399-nanopc-t4-type-c-modeling.patch only and add two lines


extcon-cables = <1 2 5 6 9 10 12 44>;
typec-altmodes = <0xff01 1 0x001c0000 1>;

based on Helios64 commit on armbian's git (ea5bf1afd56423c069dd3267e9effc2c62d6706c), then I connect type-c monitor to my nanopct4 board and get these dmesg info:

 

1. My work is based on mainline fusb302 driver sources, Armbian replaces it with some proprietary one. Patches shouldn't apply on top of armbian's version.

2. DTB patch makes absolutely no sense unless driver has proper support for altmode negotiation and extcon notifications. There is no magic in DTB itself, it is just a configuration parameters "provider"!

3.  extcon-cables and typec-altmodes -  where did you get those from? I can only guess, however, those "unofficial" bindings have no relation to the current driver in mainline.

Link to comment
Share on other sites

My Orange Pi 4B has got FUSB302B too.

USB Type-C gives power but my keyboard or mouse can't work...

 

Other 2 USB type A works ok.

 

I try Armbian_21.05.1_Orangepi4_focal_current, Armbian_20.05.3_Orangepi4_bionic_current. Thay doesn't work.

 

But USB Type-C works on https://github.com/orangepi-xunlong/orangepi-build Looks like USB Type-C wants old kernel...

 

How I use can @Oleksiipath with Orange Pi 4B ?

Link to comment
Share on other sites

I tried your patches to get displayport over usb-c working on nanopct4.

Compiled an armbian image with mainline kernel (5.17.14)

 

./compile.sh docker BOARD=nanopct4 BRANCH=current RELEASE=jammy BUILD_MINIMAL=no BUILD_DESKTOP=yes KERNEL_ONLY=no
KERNEL_CONFIGURE=yes DESKTOP_ENVIRONMENT=xfce DESKTOP_ENVIRONMENT_CONFIG_NAME=config_base COMPRESS_OUTPUTIMAGE=sha,gpg,img

 

rk3399-nanopc-t4-type-c-modeling.patch did apply just fine, but fusb302-add-extcon.patch I had to slightly modify your patches because of changes in mainline since 5.6.x

The last hunk I just updated so it would apply since there where some changes in the same lines.

And the function fwnode_graph_get_remote_node was removed in this commit (https://github.com/torvalds/linux/commit/c49eea6ffec626c059ace085fce1bf501b05dbc7) so I applied the same workaround as in the commit to now use fwnode_graph_get_endpoint_by_id

Spoiler

--- a/drivers/usb/typec/tcpm/fusb302.c    2022-06-11 15:07:10.000000000 +0200
+++ b/drivers/usb/typec/tcpm/fusb302.c    2022-06-11 17:50:31.241860256 +0200
@@ -1916,7 +1916,7 @@
     struct fusb302_chip *chip;
     struct i2c_adapter *adapter = client->adapter;
     struct device *dev = &client->dev;
-    struct fwnode_handle *usb_ss_fwnode;
+    struct fwnode_handle *usb_ss_fwnode, *ep;
     struct fwnode_handle *dp_fwnode;
     const char *name;
     int ret = 0;
@@ -1989,11 +1989,25 @@
         goto destroy_workqueue;
     }
 
-    usb_ss_fwnode = fwnode_graph_get_remote_node(chip->tcpc_dev.fwnode , 1, 0);
+    ep = fwnode_graph_get_endpoint_by_id(chip->tcpc_dev.fwnode , 1, 0, 0);
+    if (ep){
+        usb_ss_fwnode = fwnode_graph_get_remote_port_parent(ep);
+        fwnode_handle_put(ep);
+    }
+    else {
+        usb_ss_fwnode = NULL;
+    }
     chip->usb_ss_present = usb_ss_fwnode != NULL;
     fwnode_handle_put(usb_ss_fwnode);
 
-    dp_fwnode = fwnode_graph_get_remote_node(chip->tcpc_dev.fwnode , 2, 0);
+    ep = fwnode_graph_get_endpoint_by_id(chip->tcpc_dev.fwnode , 2, 0, 0);
+    if (ep){
+        dp_fwnode = fwnode_graph_get_remote_port_parent(ep);
+        fwnode_handle_put(ep);
+    }
+    else {
+        dp_fwnode = NULL;
+    }
     chip->dp_present = dp_fwnode != NULL;
     fwnode_handle_put(dp_fwnode);
 
 

 

Once everything is booted up I get:

dmesg | grep typec
[    9.123527] typec_fusb302 4-0022: DisplayPort altmode registered
[    9.191412] rockchip-typec-phy ff7c0000.phy: get polarity property failed

 

DisplayPort altmode registered looks to me that it at least did something. Once I plugin the type-c cable however I just get this:

cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Not connected. Disabling cdn

 

The screen I test with is: MB16AMT

This is a touchscreen as well, so it will try to use combined displayport+usb mode to get it all working on a single cable (confirmed working on win10 laptop). Is this mode not covered by you patches?

 

Tried also a "normal" just displayport display with an typec to displayport cable. Then I got this:

[   73.642298] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Not connected. Disabling cdn
[   73.933028] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Not connected. Disabling cdn
[   73.940772] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Connected, not enabled. Enabling cdn
[   74.114884] rockchip-typec-phy ff7c0000.phy: get superspeed property failed
[   74.114898] phy phy-ff7c0000.phy.8: phy poweron failed --> -1
[   74.114913] cdn-dp fec00000.dp: [drm:cdn_dp_enable [rockchipdrm]] *ERROR* phy power on failed: -1
[   74.114982] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] *ERROR* Enable dp failed -1

 

Flipping the type-c connector around also did not change anything (on either display).

I guess something is still wrong here. I also did one test where I build the image without the add-fusb30x-driver.patch, so the armbian fuse302 driver could not have interfered here. And in both tests the behavior was the same.

Any tips where I could start to dig?

Link to comment
Share on other sites

In the end the fix seemed to be fairly simple.

The function fusb302_extcon_register that was added by this patch was just called to early and was checking for usb_ss_present and dp_present to advertise the capabilities, but at that point those values where not initialized yet. So the extcon device did not have any capabilities resulting in -EPERM / "get superspeed property failed".

The following patch moves the initialization until after the values are initialized.

Spoiler

--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1933,34 +1933,7 @@
     chip->i2c_client = client;
     chip->dev = &client->dev;
     mutex_init(&chip->lock);
-
-    /*
-     * Devicetree platforms should get extcon via phandle (not yet
-     * supported). On ACPI platforms, we get the name from a device prop.
-     * This device prop is for kernel internal use only and is expected
-     * to be set by the platform code which also registers the i2c client
-     * for the fusb302.
-     */
-    if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
-        chip->extcon = extcon_get_extcon_dev(name);
-        if (IS_ERR(chip->extcon))
-            return PTR_ERR(chip->extcon);
-    } else if (device_property_read_bool(dev, "extcon")) {
-        chip->extcon = extcon_get_edev_by_phandle(dev, 0);
-        if (IS_ERR(chip->extcon)) {
-            if (PTR_ERR(chip->extcon) != -EPROBE_DEFER)
-                dev_err(dev,
-                    "Invalid or missing extcon device\n");
-            return PTR_ERR(chip->extcon);
-        }
-    } else {
-        chip->extcon = fusb302_extcon_register(chip);
-        if (IS_ERR(chip->extcon)) {
-            dev_err(dev, "Cannot create extcon, ret=%d\n", ret);
-            return PTR_ERR(chip->extcon);
-        }
-    }
 
     chip->vbus = devm_regulator_get(chip->dev, "vbus");
     if (IS_ERR(chip->vbus))
         return PTR_ERR(chip->vbus);
@@ -2029,6 +1996,33 @@
             dev_info(dev, "DisplayPort altmode registered");
     }
 
+    /*
+     * Devicetree platforms should get extcon via phandle (not yet
+     * supported). On ACPI platforms, we get the name from a device prop.
+     * This device prop is for kernel internal use only and is expected
+     * to be set by the platform code which also registers the i2c client
+     * for the fusb302.
+     */
+    if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
+        chip->extcon = extcon_get_extcon_dev(name);
+        if (IS_ERR(chip->extcon))
+            return PTR_ERR(chip->extcon);
+    } else if (device_property_read_bool(dev, "extcon")) {
+        chip->extcon = extcon_get_edev_by_phandle(dev, 0);
+        if (IS_ERR(chip->extcon)) {
+            if (PTR_ERR(chip->extcon) != -EPROBE_DEFER)
+                dev_err(dev,
+                    "Invalid or missing extcon device\n");
+            return PTR_ERR(chip->extcon);
+        }
+    } else {
+        chip->extcon = fusb302_extcon_register(chip);
+        if (IS_ERR(chip->extcon)) {
+            dev_err(dev, "Cannot create extcon, ret=%d\n", ret);
+            return PTR_ERR(chip->extcon);
+        }
+    }
+
     ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn,
               IRQF_ONESHOT | IRQF_TRIGGER_LOW,
               "fsc_interrupt_int_n", chip);
 

 

This now successfully works with a usb-c to DisplayPort cable. Although it seems to work only with some monitors. My Dell U2414H did not work, while it worked with LG 27GL850.

The Dell would cause this:

Zitat

[  722.088218] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Connected without sink. Assert hpd
[  722.088364] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Not connected. Disabling cdn
[  727.096289] cdn-dp fec00000.dp: [drm:cdn_dp_check_sink_connection [rockchipdrm]] *ERROR* Get sink capability timed out
[  727.096346] cdn-dp fec00000.dp: [drm:cdn_dp_pd_event_work [rockchipdrm]] Connected without sink. Assert hpd

However that sounds like its now a displayport problem, no longer a usb alt mode problem.

 

Getting my type-c monitor with touch interface to work took some more work. This monitor prefers to connect in a usb+DP mode. And the code in drivers/usb/typec/altmodes/displayport.c could not get a matching pin configuration between port and device.

The display returned a vdo of 0xC0045 for the displayport alt mode. According to this 3rd party description https://www.st.com/resource/en/technical_article/ta0356-usb-typec-and-power-delivery-displayport-alternate-mode-stmicroelectronics.pdf this essentially means:

Type-C receptacle with pin modes C and D supported as a UFP_D device.

The port was registered with a vdo of 0x1C1C46

Type-C receptacle with pin modes C, D and E supported as a DFP_D device.

 

The current code of displayport.c was not able to make a match between these even though they are compatible.

It seemed to not correctly interpret the DFP_D and UFP_D bitmasks and ignoring the bit indicating receptacle or plug, which flips the meaning of those masks.

With the following patch the MB16AMT monitor does now correctly get a pinmode of D (2 lanes USB + 2 lanes DP) since it also has the DP_STATUS_PREFER_MULTI_FUNC set.

The USB3 interface shows up as a hub and seems to provide a DisplayLink usb device, as backup to DP I guess...

The touch HID device is connected through the USB2 connection.

Spoiler

--- a/include/linux/usb/typec_dp.h
+++ a/include/linux/usb/typec_dp.h
@@ -71,8 +71,8 @@
 #define DP_CAP_GEN2            BIT(3) /* Reserved after v1.0b */
 #define DP_CAP_RECEPTACLE        BIT(6)
 #define DP_CAP_USB            BIT(7)
-#define DP_CAP_DFP_D_PIN_ASSIGN(_cap_)    (((_cap_) & GENMASK(15, 8)) >> 😎
-#define DP_CAP_UFP_D_PIN_ASSIGN(_cap_)    (((_cap_) & GENMASK(23, 16)) >> 16)
+#define DP_CAP_DFP_D_PIN_ASSIGN(_cap_)    (((_cap_) & DP_CAP_RECEPTACLE) ? (((_cap_) & GENMASK(15,  8)) >>  😎 : (((_cap_) & GENMASK(23, 16)) >> 16))
+#define DP_CAP_UFP_D_PIN_ASSIGN(_cap_)    (((_cap_) & DP_CAP_RECEPTACLE) ? (((_cap_) & GENMASK(23, 16)) >> 16) : (((_cap_) & GENMASK(15,  8)) >>  8))
 
 /* DisplayPort Status Update VDO bits */
 #define DP_STATUS_CONNECTION(_status_)    ((_status_) & 3)
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -82,20 +82,20 @@
         return 0;
     case DP_STATUS_CON_DFP_D:
         conf |= DP_CONF_UFP_U_AS_DFP_D;
-        pin_assign = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo) &
-                 DP_CAP_DFP_D_PIN_ASSIGN(dp->port->vdo);
+        pin_assign = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo) &
+                 DP_CAP_UFP_D_PIN_ASSIGN(dp->port->vdo);
         break;
     case DP_STATUS_CON_UFP_D:
     case DP_STATUS_CON_BOTH: /* NOTE: First acting as DP source */
         conf |= DP_CONF_UFP_U_AS_UFP_D;
-        pin_assign = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo) &
-                 DP_CAP_UFP_D_PIN_ASSIGN(dp->port->vdo);
+        pin_assign = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo) &
+                 DP_CAP_DFP_D_PIN_ASSIGN(dp->port->vdo);
         break;
     default:
         break;
 

 

With the fix from above, patches (like this one) that check the reverse mapping and or like this fuse302-add-extcon.patch does, registering a port with identical pinmaps for UFP_D and DFP_D even though only one mode is actually supported (~line 292 fuse302-add-extcon.patch), are no longer necessary?

 

Anyway, so far everything seems to work now regarding the alt mode switching . Just some weirdness with DP and specific monitors.

Link to comment
Share on other sites

On 6/14/2022 at 3:23 AM, warloxx said:

rk3399-nanopc-t4-type-c-modeling.patch did apply just fine

sudo dmesg | grep "typec"        
[    0.845532] typec_fusb302 4-0022: error -EINVAL: cannot register tcpm port
[    0.846545] typec_fusb302: probe of 4-0022 failed with error -22


Doesn't seem to be working, I was hoping to use the OTG mode of the USB-C port.

I made some modifications to rk3399-nanopc-t4-type-c-modeling.patch.

 

32 lines

+        data-role = "otg";

129 lines

+    dr_mode = "otg";
Link to comment
Share on other sites

I used offical rom linux-kernel-rk3399-5.15.78-6fc4621-20230309, the typec is also not avaiable on linux 5.x;

warloxx's solution works ok

 

 

by the way , we need select fusb302 in the kernel menu and recompile it

Edited by yongwn
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...

Important Information

Terms of Use - Privacy Policy - Guidelines