mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
mach-snapdragon: fixup USB nodes
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. Acked-by: Sumit Garg <sumit.garg@linaro.org> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> Tested-by: Neil Armstrong <neil.armstrong@linaro.org> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
This commit is contained in:
@@ -3,3 +3,4 @@
|
||||
# (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
|
||||
|
||||
obj-y += board.o
|
||||
obj-$(CONFIG_OF_LIVE) += of_fixup.o
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <usb.h>
|
||||
#include <sort.h>
|
||||
|
||||
#include "qcom-priv.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } };
|
||||
@@ -160,6 +162,7 @@ void __weak qcom_board_init(void)
|
||||
int board_init(void)
|
||||
{
|
||||
show_psci_version();
|
||||
qcom_of_fixup_nodes();
|
||||
qcom_board_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
123
arch/arm/mach-snapdragon/of_fixup.c
Normal file
123
arch/arm/mach-snapdragon/of_fixup.c
Normal file
@@ -0,0 +1,123 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* OF_LIVE devicetree fixup.
|
||||
*
|
||||
* This file implements runtime fixups for Qualcomm DT to improve
|
||||
* compatibility with U-Boot. This includes adjusting the USB nodes
|
||||
* to only use USB high-speed, as well as remapping volume buttons
|
||||
* to behave as up/down for navigating U-Boot.
|
||||
*
|
||||
* We use OF_LIVE for this rather than early FDT fixup for a couple
|
||||
* of reasons: it has a much nicer API, is most likely more efficient,
|
||||
* and our changes are only applied to U-Boot. This allows us to use a
|
||||
* DT designed for Linux, run U-Boot with a modified version, and then
|
||||
* boot Linux with the original FDT.
|
||||
*
|
||||
* Copyright (c) 2024 Linaro Ltd.
|
||||
* Author: Caleb Connolly <caleb.connolly@linaro.org>
|
||||
*/
|
||||
|
||||
#include <dt-bindings/input/linux-event-codes.h>
|
||||
#include <dm/of_access.h>
|
||||
#include <dm/of.h>
|
||||
#include <fdt_support.h>
|
||||
#include <linux/errno.h>
|
||||
#include <time.h>
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
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", 0, NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
ret = of_write_prop(dwc3, "maximum-speed", strlen("high-speed"), "high-speed");
|
||||
if (ret) {
|
||||
log_err("Failed to set 'maximum-speed' 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);
|
||||
}
|
||||
}
|
||||
|
||||
#define time_call(func, ...) \
|
||||
do { \
|
||||
u64 start = timer_get_us(); \
|
||||
func(__VA_ARGS__); \
|
||||
debug(#func " took %lluus\n", timer_get_us() - start); \
|
||||
} while (0)
|
||||
|
||||
void qcom_of_fixup_nodes(void)
|
||||
{
|
||||
time_call(fixup_usb_nodes);
|
||||
}
|
||||
20
arch/arm/mach-snapdragon/qcom-priv.h
Normal file
20
arch/arm/mach-snapdragon/qcom-priv.h
Normal file
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#ifndef __QCOM_PRIV_H__
|
||||
#define __QCOM_PRIV_H__
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_LIVE)
|
||||
/**
|
||||
* qcom_of_fixup_nodes() - Fixup Qualcomm DT nodes
|
||||
*
|
||||
* Adjusts nodes in the live tree to improve compatibility with U-Boot.
|
||||
*/
|
||||
void qcom_of_fixup_nodes(void);
|
||||
#else
|
||||
static inline void qcom_of_fixup_nodes(void)
|
||||
{
|
||||
log_debug("Unable to dynamically fixup USB nodes, please enable CONFIG_OF_LIVE\n");
|
||||
}
|
||||
#endif /* OF_LIVE */
|
||||
|
||||
#endif /* __QCOM_PRIV_H__ */
|
||||
Reference in New Issue
Block a user