@@ -146,6 +146,93 @@ int board_usb_init(int index, enum usb_init_type init)
return 0;
}
+/* U-Boot only supports USB high-speed mode on Qualcomm platforms with DWC3
+ * USB controllers. Rather than requiring source level DT changes, we fix up
+ * DT here. This improves compatibility with upstream DT and simplifies the
+ * porting process for new devices.
+ */
+#if CONFIG_IS_ENABLED(OF_LIVE)
+static int fixup_qcom_dwc3(struct device_node *glue_np)
+{
+ struct device_node *dwc3;
+ int ret, len, hsphy_idx = 1;
+ const __be32 *phandles;
+ const char *second_phy_name;
+
+ debug("Fixing up %s\n", glue_np->name);
+
+ /* Tell the glue driver to configure the wrapper for high-speed only operation */
+ ret = of_write_prop(glue_np, "qcom,select-utmi-as-pipe-clk", NULL, 0);
+ if (ret) {
+ log_err("Failed to add property 'qcom,select-utmi-as-pipe-clk': %d\n", ret);
+ return ret;
+ }
+
+ /* Find the DWC3 node itself */
+ dwc3 = of_find_compatible_node(glue_np, NULL, "snps,dwc3");
+ if (!dwc3) {
+ log_err("Failed to find dwc3 node\n");
+ return -ENOENT;
+ }
+
+ phandles = of_get_property(dwc3, "phys", &len);
+ len /= sizeof(*phandles);
+ if (len == 1) {
+ log_debug("Only one phy, not a superspeed controller\n");
+ return 0;
+ }
+
+ /* Figure out if the superspeed phy is present and if so then which phy is it? */
+ ret = of_property_read_string_index(dwc3, "phy-names", 1, &second_phy_name);
+ if (ret == -ENODATA) {
+ log_debug("Only one phy, not a super-speed controller\n");
+ return 0;
+ } else if (ret) {
+ log_err("Failed to read second phy name: %d\n", ret);
+ return ret;
+ }
+
+ if (!strncmp("usb3-phy", second_phy_name, strlen("usb3-phy"))) {
+ log_debug("Second phy isn't superspeed (is '%s') assuming first phy is SS\n",
+ second_phy_name);
+ hsphy_idx = 0;
+ }
+
+ /* Overwrite the "phys" property to only contain the high-speed phy */
+ ret = of_write_prop(dwc3, "phys", sizeof(*phandles), phandles + hsphy_idx);
+ if (ret) {
+ log_err("Failed to overwrite 'phys' property: %d\n", ret);
+ return ret;
+ }
+
+ /* Overwrite "phy-names" to only contain a single entry */
+ ret = of_write_prop(dwc3, "phy-names", strlen("usb2-phy"), "usb2-phy");
+ if (ret) {
+ log_err("Failed to overwrite 'phy-names' property: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void fixup_usb_nodes(void)
+{
+ struct device_node *glue_np = NULL;
+ int ret;
+
+ while ((glue_np = of_find_compatible_node(glue_np, NULL, "qcom,dwc3"))) {
+ ret = fixup_qcom_dwc3(glue_np);
+ if (ret)
+ log_warning("Failed to fixup node %s: %d\n", glue_np->name, ret);
+ }
+}
+#else
+static void fixup_usb_nodes(void)
+{
+ log_debug("Unable to dynamically fixup USB nodes, please enable CONFIG_OF_LIVE\n");
+}
+#endif
+
/*
* Some boards still need board specific init code, they can implement that by
* overriding this function.
@@ -159,6 +246,7 @@ void __weak qcom_board_init(void)
int board_init(void)
{
show_psci_version();
+ fixup_usb_nodes();
qcom_board_init();
return 0;
}
We don't support USB super-speed in U-Boot yet, we lack the SS PHY drivers, however from my testing even with a PHY driver there seem to be other issues when talking to super-speed peripherals. In pursuit of maintaining upstream DT compatibility, and simplifying porting for new devices, let's implement the DT fixups necessary to configure USB in high-speed only mode at runtime. The pattern is identical for all Qualcomm boards that use the Synaptics DWC3 controller: * Add an additional property on the Qualcomm wrapper node * Remove the super-speed phy phandle and phy-name entries. Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org> --- arch/arm/mach-snapdragon/board.c | 88 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+)