Dual DP output on custom board

I am trying to get two DP-connected displays on a custom board hosting a TX2 (4GB). The one associated with sor0 seems to work fine. The one associated with sor1 (which I have configured the same way) does not.

Here is what (I think) are the relevant lines in tegra186-quill-p3489-0888-a00-00-base.dts:

                sor {
                        status = "okay";  /* from disabled */
                        nvidia,active-panel = <&sor0_dp_display>;
                        dp-display {
                                status = "okay";   /* from disabled */
                        };
                        hdmi-display {
                                status = "disabled";
                        };
                };

                dpaux@155c0000 {
                        status = "okay";  /* from disabled */
                };

                sor1 {
                        status = "okay";
                        nvidia,active-panel = <&sor1_dp_display>;
                        dp-display {
                                status = "okay";
                        };
                        hdmi-display {
                                status = "disabled";
                        };
                };

                dpaux@15040000 {
                        status = "okay";  /* from disabled */
                };


                nvdisplay@15200000 {
                        status = "okay";  /* from disabled */
                        nvidia,dc-or-node = "/host1x/sor1"; /* v2 */
                        nvidia,dc-connector = <&sor1>;     /* v2 */
                        win-mask = <0x3>;    /* v3 */

                };

                nvdisplay@15210000 {
                        status = "okay";
                        nvidia,dc-or-node = "/host1x/sor";
                        nvidia,dc-connector = <&sor0>;
                        win-mask = <0xC>;    /* v3 */
                };

Just grep’ing dmesg for the respective nvdisplays, I get:

for “15210000” (main going to sor0), which works:

[    0.480246] iommu: Adding device 15210000.nvdisplay to group 35
[    2.869060] tegradc 15210000.nvdisplay: disp1 connected to head1->/host1x/sor
[    2.869200] tegradc 15210000.nvdisplay: DT parsed successfully
[    2.869222] tegradc 15210000.nvdisplay: Display dc.ffffff800b4c0000 registered with id=1
[    2.869476] tegradc 15210000.nvdisplay: vblank syncpt # 11 for dc 1
[    2.869482] tegradc 15210000.nvdisplay: vpulse3 syncpt # 12 for dc 1
[    2.870269] tegradc 15210000.nvdisplay: dc_dp_out_hotplug_init: couldn't get regulator vdd_hdmi_5v0
[    2.879145] tegradc 15210000.nvdisplay: probed
[    2.879394] tegradc 15210000.nvdisplay: fb registered
[    2.907777] tegradc 15210000.nvdisplay: dp: couldn't get regulator vdd-dp-pwr
[    2.907791] tegradc 15210000.nvdisplay: dp: couldn't get regulator avdd-dp-pll
[    2.907804] tegradc 15210000.nvdisplay: dp: couldn't get regulator vdd-edp-sec-mode
[    2.907816] tegradc 15210000.nvdisplay: dp: couldn't get regulator vdd-dp-pad
[    2.912545] tegradc 15210000.nvdisplay: dp: aux read defer (0x10020000) -- 6
[    2.916602] tegradc 15210000.nvdisplay: dp: aux read defer (0x10020000) -- 6
[    2.918286] tegradc 15210000.nvdisplay: dp: aux read defer (0x10020000) -- 6
[    2.920693] tegradc 15210000.nvdisplay: dp: aux read defer (0x10020000) -- 6
[    2.921939] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x600000 did not specify bpp
[    2.930175] tegradc 15210000.nvdisplay: dp: aux write defer (0x10020000) -- 6
[    2.932007] tegradc 15210000.nvdisplay: dp: aux write defer (0x10020000) -- 6
[    2.933683] tegradc 15210000.nvdisplay: dp: aux read defer (0x10020000) -- 6
[    2.935819] tegradc 15210000.nvdisplay: dp: aux read defer (0x10020000) -- 6
[    2.941179] tegradc 15210000.nvdisplay: dp: aux write defer (0x10020000) -- 6
[    2.942951] tegradc 15210000.nvdisplay: dp: aux write defer (0x10020000) -- 6
[    2.944630] tegradc 15210000.nvdisplay: dp: aux write defer (0x10020000) -- 6
[    2.970497] tegradc 15210000.nvdisplay: dp: aux write defer (0x10020000) -- 6
[    2.998812] tegradc 15210000.nvdisplay: dp: aux write defer (0x10020000) -- 6
[    3.026484] tegradc 15210000.nvdisplay: dp: aux write defer (0x10020000) -- 6
[    3.205029] tegradc 15210000.nvdisplay: dp: aux read defer (0x10020000) -- 6
[    3.207628] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x600000 did not specify bpp
[    3.228508] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x600000 did not specify bpp
[    3.228515] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x400000 did not specify bpp
[    3.228521] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x0 did not specify bpp
[    3.228528] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x0 did not specify bpp
[    3.228534] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x400000 did not specify bpp
[    3.228545] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x400000 did not specify bpp
[    3.228551] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x600000 did not specify bpp
[    3.228556] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x400000 did not specify bpp
[    3.228567] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x400000 did not specify bpp
[    3.228573] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x400000 did not specify bpp
[    3.228586] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x400000 did not specify bpp
[    3.228593] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x420000 did not specify bpp
[    3.228599] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x420000 did not specify bpp
[    3.228604] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x420000 did not specify bpp
[    3.228610] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x420000 did not specify bpp
[    3.228614] tegradc 15210000.nvdisplay: blank - powerdown
[    3.311410] tegradc 15210000.nvdisplay: tegra_dp_get_bpp: vmode=0x600000 did not specify bpp
[    3.311485] tegradc 15210000.nvdisplay: unblank
... AND ON FOR A WHILE ...

for 15200000 (on sor1) which doesn’t work:

[    0.479266] iommu: Adding device 15200000.dc_common to group 33
[    0.479872] iommu: Adding device 15200000.nvdisplay to group 34
[    2.823203] tegradccommon 15200000.dc_common: host1x channel mapped
[    2.823211] tegradccommon 15200000.dc_common: dc_common syncpt # 1 allocated
[    2.823238] tegradccommon 15200000.dc_common: dma mapping done
[    2.823882] tegradc 15200000.nvdisplay: disp0 connected to head0->/host1x/sor1
[    2.824124] tegradc 15200000.nvdisplay: DT parsed successfully
[    2.824151] tegradc 15200000.nvdisplay: Display dc.ffffff800b4a0000 registered with id=0
[    2.830825] tegradc 15200000.nvdisplay: vblank syncpt # 8 for dc 0
[    2.830830] tegradc 15200000.nvdisplay: vpulse3 syncpt # 9 for dc 0
[    2.831767] tegradc 15200000.nvdisplay: dc_dp_out_hotplug_init: couldn't get regulator vdd_hdmi_5v0
[    2.860053] tegradc 15200000.nvdisplay: probed
[    2.862860] tegradc 15200000.nvdisplay: fb registered
[    2.868084] tegradc 15200000.nvdisplay: blank - powerdown
[    9.349333] tegradc 15200000.nvdisplay: blank - powerdown
[   11.178996] tegradc 15200000.nvdisplay: blank - powerdown

Any thoughts/help that anyone can offer is much appreciated!

Just de-compress your dtb back to dts with dtc tool.

And compare below nodes

  1. nvdisplay

  2. sorX

  3. dpaux.

Make sure the one that can work fine shares the same configuration with another one.

Thank you for the suggestion, @WayneWWW. I produced diffs of the three different sections (included below). The differences, for the most part, are things I would expect to be different.

For example, here is the dpaux diff, which is where I would think the problem is (note, all of these diff’s are in the direction of ‘diff working non-working’):

--- dpaux-0.dts 2021-11-23 13:00:35.597505966 -0500
+++ dpaux-1.dts 2021-11-23 13:00:50.761302004 -0500
@@ -1,16 +1,16 @@
-               dpaux@155c0000 {
-                       compatible = "nvidia,tegra186-dpaux";
-                       reg = <0x0 0x155c0000 0x0 0x40000>;
-                       interrupts = <0x0 0x9f 0x4>;
-                       nvidia,dpaux-ctrlnum = <0x0>;
-                       clocks = <0x10 0x60>;
-                       clock-names = "dpaux";
-                       resets = <0x10 0x5>;
-                       reset-names = "dpaux";
+               dpaux@15040000 {
+                       compatible = "nvidia,tegra186-dpaux1";
+                       reg = <0x0 0x15040000 0x0 0x40000>;
+                       interrupts = <0x0 0xa0 0x4>;
+                       nvidia,dpaux-ctrlnum = <0x1>;
+                       clocks = <0x10 0x5f>;
+                       clock-names = "dpaux1";
+                       resets = <0x10 0x7c>;
+                       reset-names = "dpaux1";
                        power-domains = <0x96>;
                        status = "okay";
-                       linux,phandle = <0x92>;
-                       phandle = <0x92>;
+                       linux,phandle = <0x94>;
+                       phandle = <0x94>;

                        prod-settings {
                                #prod-cells = <0x3>;

Here is the sor diff:

--- sor-0.dts   2021-11-23 12:59:44.010193785 -0500
+++ sor-1.dts   2021-11-23 13:00:12.609813634 -0500
@@ -1,32 +1,32 @@
-               sor {
-                       compatible = "nvidia,tegra186-sor";
-                       reg = <0x0 0x15540000 0x0 0x40000>;
-                       nvidia,sor-ctrlnum = <0x0>;
-                       nvidia,dpaux = <0x92>;
+               sor1 {
+                       compatible = "nvidia,tegra186-sor1";
+                       reg = <0x0 0x15580000 0x0 0x40000>;
+                       nvidia,sor-ctrlnum = <0x1>;
+                       nvidia,dpaux = <0x94>;
                        nvidia,xbar-ctrl = <0x0 0x1 0x2 0x3 0x4>;
-                       clocks = <0x10 0x61 0x10 0x27 0x10 0x267 0x10 0x128 0x10 0x20b 0x10 0x10d 0x10 0x88 0x10 0x66 0x10 0x58 0x10 0x62>;
-                       clock-names = "sor0_ref", "sor_safe", "sor0_pad_clkout", "sor0", "pll_dp", "pllp_out0", "maud", "hda", "hda2codec_2x", "hda2hdmi";
-                       resets = <0x10 0x27 0x10 0xf 0x10 0x10 0x10 0x11>;
-                       reset-names = "sor0", "hda_rst", "hda2codec_2x_rst", "hda2hdmi_rst";
+                       clocks = <0x10 0x5d 0x10 0x27 0x10 0x268 0x10 0x129 0x10 0x20b 0x10 0x10d 0x10 0x88 0x10 0x66 0x10 0x58 0x10 0x62>;
+                       clock-names = "sor1_ref", "sor_safe", "sor1_pad_clkout", "sor1", "pll_dp", "pllp_out0", "maud", "hda", "hda2codec_2x", "hda2hdmi";
+                       resets = <0x10 0x6c 0x10 0xf 0x10 0x10 0x10 0x11>;
+                       reset-names = "sor1", "hda_rst", "hda2codec_2x_rst", "hda2hdmi_rst";
                        status = "okay";
-                       nvidia,active-panel = <0x93>;
-                       nvidia,hpd-gpio = <0x1b 0x78 0x1>;
-                       linux,phandle = <0x88>;
-                       phandle = <0x88>;
+                       nvidia,active-panel = <0x95>;
+                       nvidia,hpd-gpio = <0x1b 0x79 0x1>;
+                       linux,phandle = <0x90>;
+                       phandle = <0x90>;

                        hdmi-display {
                                compatible = "hdmi,display";
                                status = "disabled";
-                               linux,phandle = <0x1c5>;
-                               phandle = <0x1c5>;
+                               linux,phandle = <0x1c7>;
+                               phandle = <0x1c7>;
                        };

                        dp-display {
                                compatible = "dp, display";
                                status = "okay";
                                nvidia,is_ext_dp_panel = <0x1>;
-                               linux,phandle = <0x93>;
-                               phandle = <0x93>;
+                               linux,phandle = <0x95>;
+                               phandle = <0x95>;

                                disp-default-out {
                                        nvidia,out-type = <0x3>;
@@ -34,7 +34,7 @@
                                        nvidia,out-order = <0x0>;
                                        nvidia,out-flags = <0x0>;
                                        nvidia,out-pins = <0x1 0x0 0x2 0x0 0x3 0x0 0x0 0x1>;
-                                       nvidia,out-parent-clk = "plld3";
+                                       nvidia,out-parent-clk = "plld2";
                                        nvidia,out-xres = <0x1000>;
                                        nvidia,out-yres = <0x870>;
                                };
@@ -163,9 +163,8 @@
                                status = "disabled";
                                compatible = "s-edp,uhdtv-15-6";
                                nvidia,tx-pu-disable = <0x1>;
-                               nvidia,panel-bl-pwm-gpio = <0x28 0xd 0x0>;
-                               linux,phandle = <0x1c6>;
-                               phandle = <0x1c6>;
+                               linux,phandle = <0x1c8>;
+                               phandle = <0x1c8>;

                                disp-default-out {
                                        nvidia,out-type = <0x3>;

The only thing I can see here that I don’t know whether it makes sense is that they two have different parent clocks (plld3 for the one that works, plld2 for the one that doesn’t). But it seems to me these should be different.

And here is the nvdisplay diff. A quick note on this one: Just to make sure none of the nvdisplay-specific properties are causing the issue, I swapped which display goes to which sor. All of the differences (except the attached sor) follow the nvdisplay. The problem follows the sor (sor0 works, sor1 does not):

--- nvdisplay-0.dts     2021-11-23 12:59:10.570634328 -0500
+++ nvdisplay-1.dts     2021-11-23 12:59:27.418412914 -0500
@@ -1,16 +1,16 @@
-               nvdisplay@15200000 {
+               nvdisplay@15210000 {
                        compatible = "nvidia,tegra186-dc";
-                       reg = <0x0 0x15200000 0x0 0x10000>;
-                       interrupts = <0x0 0x99 0x4>;
-                       win-mask = <0x3>;
+                       reg = <0x0 0x15210000 0x0 0x10000>;
+                       interrupts = <0x0 0x9a 0x4>;
+                       win-mask = <0xc>;
                        iommus = <0x11 0x9>;
                        iommu-group-id = <0x1>;
-                       nvidia,dc-ctrlnum = <0x0>;
+                       nvidia,dc-ctrlnum = <0x1>;
                        nvidia,cmu-enable = <0x1>;
                        clocks = <0x10 0x9c 0x10 0x9e 0x10 0x9b 0x10 0x9f 0x10 0xa0 0x10 0x9d 0x10 0x206 0x10 0x207 0x10 0x210 0x10 0x10d 0x10 0x10b 0x10 0x3a>;
-                       clock-names = "nvdisplay_disp", "nvdisplayhub", "nvdisplay_p0", "nvdisplay_p1", "nvdisplay_p2", "nvdisp_dsc", "pll_d", "plld2", "plld3", "pllp_display", "pll_d_out1", "disp1_emc";
-                       resets = <0x10 0x5c 0x10 0x5d 0x10 0x5e 0x10 0x5f 0x10 0x60 0x10 0x61 0x10 0x62 0x10 0x59>;
-                       reset-names = "misc", "wgrp0", "wgrp1", "wgrp2", "wgrp3", "wgrp4", "wgrp5", "head0";
+                       clock-names = "nvdisplay_disp", "nvdisplayhub", "nvdisplay_p0", "nvdisplay_p1", "nvdisplay_p2", "nvdisp_dsc", "pll_d", "plld2", "plld3", "pllp_display", "pll_d_out1", "disp2_emc";
+                       resets = <0x10 0x5c 0x10 0x5d 0x10 0x5e 0x10 0x5f 0x10 0x60 0x10 0x61 0x10 0x62 0x10 0x5a>;
+                       reset-names = "misc", "wgrp0", "wgrp1", "wgrp2", "wgrp3", "wgrp4", "wgrp5", "head1";
                        pinctrl-names = "dsi-dpd-disable", "dsi-dpd-enable", "dsib-dpd-disable", "dsib-dpd-enable", "dsic-dpd-disable", "dsic-dpd-enable", "dsid-dpd-disable", "dsid-dpd-enable", "hdmi-dp0-dpd-disable", "hdmi-dp0-dpd-enable", "hdmi-dp1-dpd-disable", "hdmi-dp1-dpd-enable";
                        pinctrl-0 = <0x7c>;
                        pinctrl-1 = <0x7d>;
@@ -25,24 +25,17 @@
                        pinctrl-10 = <0x86>;
                        pinctrl-11 = <0x87>;
                        status = "okay";
-                       fb_reserved = <0x79>;
+                       fb_reserved = <0x7a>;
                        nvidia,dc-flags = <0x1>;
-                       nvidia,emc-rate = <0x11e1a300>;
+                       nvidia,emc-clk-rate = <0x11e1a300>;
                        nvidia,fb-bpp = <0x20>;
                        nvidia,fb-flags = <0x1>;
-                       nvidia,fb-win = <0x0>;
-                       nvidia,dc-or-node = "/host1x/sor0";
-                       nvidia,dc-connector = <0x88>;
-                       avdd_lcd-supply = <0x89>;
-                       dvdd_lcd-supply = <0x8a>;
-                       avdd_dsi_csi-supply = <0x3c>;
-                       outp-supply = <0x8b>;
-                       outn-supply = <0x8c>;
-                       vdd_lcd_bl-supply = <0x26>;
-                       vdd_lcd_bl_en-supply = <0x8d>;
+                       nvidia,fb-win = <0x3>;
+                       nvidia,dc-or-node = "/host1x/sor1";
+                       nvidia,dc-connector = <0x90>;
                        avdd_hdmi-supply = <0x8e>;
                        avdd_hdmi_pll-supply = <0x12>;
                        vdd_hdmi_5v0-supply = <0x8f>;
-                       linux,phandle = <0x1c1>;
-                       phandle = <0x1c1>;
+                       linux,phandle = <0x1c2>;
+                       phandle = <0x1c2>;
                };

I’m going to HW-probe the HPD line on the second display and make sure that’s not “broken.” Is there anything obvious in what I’ve presented, that I’m missing?

A bit of additional information: I recently discovered that neither of the HPD signals (as viewed via “cat /sys/kernel/debug/tegra_dp[0,1]/hotplug”) appears to register. Cat’ing either one indicates the state is “0” regardless of whether I have that particular monitor plugged in.

I probed both HPD lines with a scope to make sure they are transitioning.

Some debug tips

  1. Disable the head that can work fine and only leave that problematic head, boot up and dump dmesg. Otherwise the log from both heads will be mixed up and hard to debug from the log.

  2. You don’t need to worry about the clk, resets, interrupted. They are not related. For example, just make sure you enable the correct dpaux. What is written inside it could be ignored.
    What you should check is something that was not there on the head. For example, regulators, win-mask setting.

Also, make sure the pinmux setting for this hpd pin is set to SFIO instead of GPIO. If that head was by default enabled as GPIO in jetpack, then you need to update it.

Update: What seemed to eventually work is this:

  1. Download the latest pinmux configuration template spreadsheet for the TX2.

  2. Change the DP0_HPD and DP1_HPD pins to remove the indications of pull-up resistors (both of these are driven directly by signal buffers driven by the hotplug output of the USB controller). I left everything else the same.

  3. Generate the dtsi files. (I just accepted the provided board name - I don’t know if that matters.)

  4. Then I included the pinmux file at this point in the tegra186-quill-p3489-0888-a00-00-base.dts:

...
#include <t18x-common-platforms/tegra186-quill-common-p3489-1000-a00.dtsi>
#include <t18x-common-platforms/tegra186-quill-power-tree-p3489-1000-a00-00.dtsi>
#include <t18x-common-platforms/tegra186-quill-camera-modules.dtsi>
#include <t18x-common-modules/tegra186-display-e3320-1000-a00.dtsi>

/**** include new pinmux file here ****/
#include "tegra18x-jetson-tx2-config-template-pinmux.dtsi"

/* comms dtsi file should be included after gpio dtsi file */
#include <t18x-common-plugin-manager/tegra186-quill-p3489-1000-a00-plugin-manager.dtsi>
#include <t18x-common-modules/tegra186-super-module-e2614-p2597-1000-a00.dtsi>
#include <t18x-common-plugin-manager/tegra186-quill-display-plugin-manager.dtsi>
#include <t18x-common-prod/tegra186-priv-quill-p3489-1000-a00-prod.dtsi>
#include <t18x-common-plugin-manager/tegra186-quill-camera-plugin-manager.dtsi>
...

This build resulted in a bunch of stuff not working. Apparently the default pinmux settings in that spreadsheet don’t generally work for the board I’m bringing up, but the default ones in the public sources do. So:

  1. I removed all the pinmux settings from that new config file except for the two related to the HPD signals on the display ports.

That seems to have done the trick. The hotplug events are now recognized and handled, and both displays work.

Thanks for your help, @WayneWWW!

Quick follow-on: The /sys/kernel/debug/tegradc.0/hotplug and /sys/kernel/debug/tegra_dp0/hotplug are apparently red herrings. Neither one of those seems to change state as the monitors are plugged in/out. Perhaps they just reflect the value of a register bit controlling the hpd, and not the actual hpd itself.