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