]>
git.ipfire.org Git - thirdparty/u-boot.git/blob - arch/arm/mach-snapdragon/of_fixup.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * OF_LIVE devicetree fixup.
5 * This file implements runtime fixups for Qualcomm DT to improve
6 * compatibility with U-Boot. This includes adjusting the USB nodes
7 * to only use USB high-speed, as well as remapping volume buttons
8 * to behave as up/down for navigating U-Boot.
10 * We use OF_LIVE for this rather than early FDT fixup for a couple
11 * of reasons: it has a much nicer API, is most likely more efficient,
12 * and our changes are only applied to U-Boot. This allows us to use a
13 * DT designed for Linux, run U-Boot with a modified version, and then
14 * boot Linux with the original FDT.
16 * Copyright (c) 2024 Linaro Ltd.
17 * Author: Caleb Connolly <caleb.connolly@linaro.org>
20 #include <dt-bindings/input/linux-event-codes.h>
21 #include <dm/of_access.h>
23 #include <fdt_support.h>
24 #include <linux/errno.h>
27 /* U-Boot only supports USB high-speed mode on Qualcomm platforms with DWC3
28 * USB controllers. Rather than requiring source level DT changes, we fix up
29 * DT here. This improves compatibility with upstream DT and simplifies the
30 * porting process for new devices.
32 static int fixup_qcom_dwc3(struct device_node
*glue_np
)
34 struct device_node
*dwc3
;
35 int ret
, len
, hsphy_idx
= 1;
36 const __be32
*phandles
;
37 const char *second_phy_name
;
39 debug("Fixing up %s\n", glue_np
->name
);
41 /* Tell the glue driver to configure the wrapper for high-speed only operation */
42 ret
= of_write_prop(glue_np
, "qcom,select-utmi-as-pipe-clk", 0, NULL
);
44 log_err("Failed to add property 'qcom,select-utmi-as-pipe-clk': %d\n", ret
);
48 /* Find the DWC3 node itself */
49 dwc3
= of_find_compatible_node(glue_np
, NULL
, "snps,dwc3");
51 log_err("Failed to find dwc3 node\n");
55 phandles
= of_get_property(dwc3
, "phys", &len
);
56 len
/= sizeof(*phandles
);
58 log_debug("Only one phy, not a superspeed controller\n");
62 /* Figure out if the superspeed phy is present and if so then which phy is it? */
63 ret
= of_property_read_string_index(dwc3
, "phy-names", 1, &second_phy_name
);
64 if (ret
== -ENODATA
) {
65 log_debug("Only one phy, not a super-speed controller\n");
68 log_err("Failed to read second phy name: %d\n", ret
);
72 if (!strncmp("usb3-phy", second_phy_name
, strlen("usb3-phy"))) {
73 log_debug("Second phy isn't superspeed (is '%s') assuming first phy is SS\n",
78 /* Overwrite the "phys" property to only contain the high-speed phy */
79 ret
= of_write_prop(dwc3
, "phys", sizeof(*phandles
), phandles
+ hsphy_idx
);
81 log_err("Failed to overwrite 'phys' property: %d\n", ret
);
85 /* Overwrite "phy-names" to only contain a single entry */
86 ret
= of_write_prop(dwc3
, "phy-names", strlen("usb2-phy"), "usb2-phy");
88 log_err("Failed to overwrite 'phy-names' property: %d\n", ret
);
92 ret
= of_write_prop(dwc3
, "maximum-speed", strlen("high-speed"), "high-speed");
94 log_err("Failed to set 'maximum-speed' property: %d\n", ret
);
101 static void fixup_usb_nodes(void)
103 struct device_node
*glue_np
= NULL
;
106 while ((glue_np
= of_find_compatible_node(glue_np
, NULL
, "qcom,dwc3"))) {
107 ret
= fixup_qcom_dwc3(glue_np
);
109 log_warning("Failed to fixup node %s: %d\n", glue_np
->name
, ret
);
113 #define time_call(func, ...) \
115 u64 start = timer_get_us(); \
117 debug(#func " took %lluus\n", timer_get_us() - start); \
120 void qcom_of_fixup_nodes(void)
122 time_call(fixup_usb_nodes
);