This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SK-AM69: Support for USB 3.0 lane swapping in SERDES wrapper

Part Number: SK-AM69
Other Parts Discussed in Thread: AM69, , TUSB321

Tool/software:

According to the AM69 TRM (spruj52), the SERDES wrapper module has the ability to perform USB Type-C lane swapping.

However, according to the AM69 SERDES documentation, SERDES 0 only supports one USB 3 lane (USB3_0):

                  ┌───────────────────┐
                  |                   │
      PCIE1_LANE0/|                   │
  HYPERLINK_LANE0 │                   │   <-> RX0/TX0
──────────────────┤                   ├────────────────
                  │                   │
                  │                   │
      PCIE1_LANE1/|                   │
  HYPERLINK_LANE1 │                   │   <-> RX1/TX1
──────────────────┤                   ├────────────────
                  │                   │
                  │    4L SERDES      │
      PCIE3_LANE0/|                   │
      PCIE1_LANE2/│                   │
  HYPERLINK_LANE2 │                   │   <-> RX2/TX2
──────────────────┤                   ├────────────────
                  │                   │
                  │                   │
      PCIE3_LANE1/|                   │
      PCIE1_LANE3/│                   │
           USB3_0/│                   │
  HYPERLINK_LANE3 │                   │   <-> RX3/TX3
──────────────────┤                   ├────────────────
                  │                   │
                  └───────────────────┘

This differs from other processors. The TDA4VM documentation documents SERDES 0 as having one USB 3 lane (USB3_0) and another lane can be configured for USB 3 lane swapping capabilities (USB3_0_SWAP).

                    ┌───────────────────┐
CPSW0_Q/SGMII_LANE1/│                   │
        PCIE0_LANE0/│                   │
        USB3_0_SWAP │                   │   <-> RX0/TX0
  ──────────────────┤                   ├────────────────
                    │                   │
                    │    2L SERDES      │
CPSW0_Q/SGMII_LANE2/│                   │
        PCIE0_LANE1/│                   │
             USB3_0 │                   │   <-> RX1/TX1
  ──────────────────┤                   ├────────────────
                    │                   │
                    │                   │
                    └───────────────────┘

My main question is: does the AM69 support USB 3 Type-C lane swapping? Or should we add a mux to select which set of SuperSpeed signals are routed to a single SERDES lane?

Our current USB hardware configuration is based upon that of the SK-AM69 evaluation board with the following important differences:

  • USB Type-C is configured to operate with the DRD role.
  • SERDES 0 lane 3: One set of USB_SS_TX/RX signals from the Type-C connector
  • SERDES 0 lane 4: The other set of USB_SS_TX/RX signals from the Type-C connector
  • GPIO0_36: The USBC_DIR signal that is output by TUSB321

After experimenting with various device tree changes, a USB 3 Type-A to Type-C cable between a PC and the AM69 board behaves as follows:

  • In one Type-C connector orientation, the PC can communicate to the board at USB 3 speeds.
  • When the Type-C connector is flipped over, the PC can only communicate to the board at USB 2 speeds.
  • GPIO0_36 changes depending upon the orientation of the Type-C connector.

A USB 3 Type-A to Type-C cable only has one set of SuperSpeed signals, so they will either be connected to lane 3 or lane 4 of SERDES 0 depending upon the orientation of the cable.

In the device tree, we made the following change for SERDES lanes according to the TRM. One notable thing here is that include/dt-bindings/mux/ti-serdes.h defines such as J721E_SERDES0_LANE0_USB3_0_SWAP, but there are no similar USB swap defines for the AM69 (J784S4).

 &serdes_ln_ctrl {
 	idle-states = <J784S4_SERDES0_LANE0_PCIE1_LANE0>, <J784S4_SERDES0_LANE1_PCIE1_LANE1>,
-		      <J784S4_SERDES0_LANE2_PCIE3_LANE0>, <J784S4_SERDES0_LANE3_USB>,
+		      <J784S4_SERDES0_LANE2_IP3_UNUSED>, <J784S4_SERDES0_LANE3_USB>,
 			<J784S4_SERDES1_LANE0_PCIE0_LANE0>, <J784S4_SERDES1_LANE1_PCIE0_LANE1>,
 			<J784S4_SERDES1_LANE2_PCIE0_LANE2>, <J784S4_SERDES1_LANE3_PCIE0_LANE3>;
 };

USB PHY configuration looks like the following.

&serdes0 {
	status = "okay";

	serdes0_usb_link: phy@2 {
		reg = <2>;
		cdns,num-lanes = <2>;
		#phy-cells = <0>;
		cdns,phy-type = <PHY_TYPE_USB3>;
		resets = <&serdes_wiz0 3>, <&serdes_wiz0 4>;
	};
};

Finally, we're attempting to use GPIO0_36 as the USBC_DIR signal for lane swapping.

&serdes_wiz0 {
	status = "okay";
	typec-dir-gpios = <&main_gpio0 36 GPIO_ACTIVE_HIGH>;
	typec-dir-debounce-ms = <700>;
};

One thing that I noticed in drivers/phy/ti/phy-j721e-wiz.c (the SERDES wrapper driver) was that it only supports setting the LN10_SWAP bit depending upon the Type-C direction GPIO bit. We tried modifying this to set the LN23_SWAP bit instead, but did not have any success with getting USB 3 speeds when the Type-C connector was plugged in with either orientation.

static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev,
				  unsigned long id)
{
	struct device *dev = rcdev->dev;
	struct wiz *wiz = dev_get_drvdata(dev);
	int ret;

	if (id == 0) {
		/* if typec-dir gpio was specified, set LN10 SWAP bit based on that */
		if (wiz->gpio_typec_dir) {
			if (wiz->typec_dir_delay)
				msleep_interruptible(wiz->typec_dir_delay);

			if (gpiod_get_value_cansleep(wiz->gpio_typec_dir))
				regmap_field_write(wiz->typec_ln10_swap, 1);
			else
				regmap_field_write(wiz->typec_ln10_swap, 0);
		} else {
...

In some cases, attempting to use the LN23_SWAP bit caused failures during boot time:

[    6.634286] cdns-torrent-phy 5060000.serdes: Timeout waiting for PHY status ready
[    6.641770] phy phy-5060000.serdes.13: phy poweron failed --> -110
[    6.647948] cdns-usb3: probe of 6000000.usb failed with error -110

  • My main question is: does the AM69 support USB 3 Type-C lane swapping? Or should we add a mux to select which set of SuperSpeed signals are routed to a single SERDES lane?

    The AM69 supports type-C lane swapping, however, the implementation is done by external ICs and not automatically supported by the IC.

    You could also refer to the J784S4 EVM for the type-C implementation.

  • Also note that USB3.0 has double muxing where it is connected to SERDES0 and SERDES4. USB_SERDES_MUX needs to select the right SERDES, in this case SERDES0 along with the SERDES0_ln3_ctrl.

  • Our circuit was very similar to the J784S4 EVM's Type-C implementation and we were using the correct SERDES, but I believe that we were running into some signal integrity issues. We were eventually able to get USB SuperSpeed working on different hardware that uses an external mux with only lane 3 of SERDES 0. Thank you, this can be considered to be resolved.