Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion arch/arm/dts/qcs6490-rb3gen2-u-boot.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
};

&usb_1 {
dr_mode = "host";
dr_mode = "peripheral";
};

// RAM Entry 0 : Base 0x0080000000 Size 0x003A800000
Expand Down
160 changes: 148 additions & 12 deletions arch/arm/mach-snapdragon/of_fixup.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* 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.
* to only use USB high-speed if SSPHY driver is not available.
*
* 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,
Expand All @@ -21,20 +21,109 @@
#include <dt-bindings/input/linux-event-codes.h>
#include <dm/of_access.h>
#include <dm/of.h>
#include <dm/device.h>
#include <dm/lists.h>
#include <event.h>
#include <fdt_support.h>
#include <linux/errno.h>
#include <linker_lists.h>
#include <stdlib.h>
#include <tee/optee.h>
#include <time.h>

/**
* find_ssphy_node() - Find the super-speed PHY node referenced by DWC3
* @dwc3: DWC3 device node
*
* Returns: Pointer to SS-PHY node if found, NULL otherwise
*/
static struct device_node *find_ssphy_node(struct device_node *dwc3)
{
const __be32 *phandles;
const char *phy_name;
int len, i, ret;

phandles = of_get_property(dwc3, "phys", &len);
if (!phandles)
return NULL;

len /= sizeof(*phandles);

/* Iterate through PHY phandles to find the SS-PHY */
for (i = 0; i < len; i++) {
ret = of_property_read_string_index(dwc3, "phy-names", i, &phy_name);
if (ret)
continue;

/* Check if this is the super-speed PHY */
if (!strncmp("usb3-phy", phy_name, strlen("usb3-phy")) ||
!strncmp("usb3_phy", phy_name, strlen("usb3_phy"))) {
return of_find_node_by_phandle(NULL, be32_to_cpu(phandles[i]));
}
}

return NULL;
}

/**
* has_driver_for_node() - Check if any PHY driver can bind to this node
* @np: Device node to check
*
* Returns: true if a PHY driver with matching compatible string exists, false otherwise
*/
static bool has_driver_for_node(struct device_node *np)
{
struct driver *driver = ll_entry_start(struct driver, driver);
const int n_ents = ll_entry_count(struct driver, driver);
const char *compat_list, *compat;
int compat_length, i;
struct driver *entry;

if (!np)
return false;

/* Get compatible strings from the node */
compat_list = of_get_property(np, "compatible", &compat_length);
if (!compat_list)
return false;

/* Check each compatible string against PHY drivers only */
for (i = 0; i < compat_length; i += strlen(compat) + 1) {
compat = compat_list + i;

/* Iterate through all registered drivers */
for (entry = driver; entry != driver + n_ents; entry++) {
const struct udevice_id *of_match = entry->of_match;

/* Skip non-PHY drivers to improve performance */
if (entry->id != UCLASS_PHY)
continue;

if (!of_match)
continue;

while (of_match->compatible) {
if (!strcmp(of_match->compatible, compat)) {
debug("Found PHY driver '%s' for SS-PHY compatible '%s'\n",
entry->name, compat);
return true;
}
of_match++;
}
}
}

return false;
}

/* 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 *root, struct device_node *glue_np, bool flat)
{
struct device_node *dwc3;
struct device_node *dwc3, *ssphy_np;
int ret, len, hsphy_idx = 1;
const __be32 *phandles;
const char *second_phy_name;
Expand All @@ -54,30 +143,43 @@ static int fixup_qcom_dwc3(struct device_node *root, struct device_node *glue_np
}
}

/* 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;
}
debug("Checking USB configuration for %s\n", glue_np->name);

phandles = of_get_property(dwc3, "phys", &len);
len /= sizeof(*phandles);
if (len == 1) {
log_debug("Only one phy, not a superspeed controller\n");
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? */
/* Figure out if the superspeed phy is present */
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");
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;
}

/* Find the super-speed PHY node and check if a driver is available */
ssphy_np = find_ssphy_node(dwc3);
if (ssphy_np && has_driver_for_node(ssphy_np)) {
debug("Skipping USB fixup for %s (SS-PHY driver available)\n",
glue_np->name);
return 0;
}

/* No driver available - apply the fixup */
debug("Applying USB high-speed fixup to %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;
}

/*
* Determine which phy is the superspeed phy by checking the name of the second phy
* since it is typically the superspeed one.
Expand Down Expand Up @@ -164,11 +266,42 @@ static void fixup_power_domains(struct device_node *root)
}
}

static void add_optee_node(struct device_node *root)
{
struct device_node *fw = NULL, *optee = NULL;
int ret;

fw = of_find_node_by_path("/firmware");
if (!fw) {
log_err("Failed to find /firmware node\n");
return;
}

ret = of_add_subnode(fw, "optee", strlen("optee") + 1, &optee);
if (ret) {
log_err("Failed to add 'optee' subnode: %d\n", ret);
return;
}

ret = of_write_prop(optee, "compatible", strlen("linaro,optee-tz") + 1,
"linaro,optee-tz");
if (ret) {
log_err("Failed to add optee 'compatible' property: %d\n", ret);
return;
}

ret = of_write_prop(optee, "method", strlen("smc") + 1, "smc");
if (ret) {
log_err("Failed to add optee 'method' property: %d\n", ret);
return;
}
}

#define time_call(func, ...) \
do { \
u64 start = timer_get_us(); \
func(__VA_ARGS__); \
debug(#func " took %lluus\n", timer_get_us() - start); \
printf(#func " took %lluus\n", timer_get_us() - start); \
} while (0)

static int qcom_of_fixup_nodes(void * __maybe_unused ctx, struct event *event)
Expand All @@ -178,6 +311,9 @@ static int qcom_of_fixup_nodes(void * __maybe_unused ctx, struct event *event)
time_call(fixup_usb_nodes, root);
time_call(fixup_power_domains, root);

if (IS_ENABLED(CONFIG_OPTEE) && is_optee_smc_api())
time_call(add_optee_node, root);

return 0;
}

Expand Down
4 changes: 4 additions & 0 deletions board/qualcomm/tfa-optee.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Enables support for TF-A based OP-TEE as the open
# source TrustZone stack on Qcom platforms
CONFIG_TEE=y
CONFIG_OPTEE=y
2 changes: 2 additions & 0 deletions configs/qcm6490_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ CONFIG_REMAKE_ELF=y
CONFIG_DEFAULT_DEVICE_TREE="qcom/qcs6490-rb3gen2"

CONFIG_FASTBOOT_BUF_ADDR=0xd8800000

CONFIG_PHY_QCOM_QMP_COMBO=y
1 change: 1 addition & 0 deletions drivers/clk/qcom/clock-sc7280.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ static const struct gate_clk sc7280_clks[] = {
GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0xf01c, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0xf054, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0xf058, 1),
GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0xf05c, 1),
GATE_CLK(GCC_CFG_NOC_USB3_SEC_AXI_CLK, 0x9e07c, 1),
GATE_CLK(GCC_USB30_SEC_MASTER_CLK, 0x9e010, 1),
GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x9e080, 1),
Expand Down
8 changes: 8 additions & 0 deletions drivers/phy/qcom/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ config PHY_QCOM_IPQ4019_USB
help
Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s.

config PHY_QCOM_QMP_COMBO
bool "Qualcomm QMP USB3-DP Combo PHY driver"
depends on PHY && ARCH_SNAPDRAGON
help
Enable this to support the USB3-DP Combo QMP PHY on various Qualcomm
chipsets. This driver supports the USB3 PHY functionality of the combo
PHY (USB3 + DisplayPort). Currently only USB3 mode is supported.

config PHY_QCOM_QMP_PCIE
tristate "Qualcomm QMP PCIe PHY driver"
depends on PHY && ARCH_SNAPDRAGON
Expand Down
1 change: 1 addition & 0 deletions drivers/phy/qcom/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o
obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o
obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o
obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o
obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
Expand Down
Loading