summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-10-30 08:03:02 -0600
committerTom Rini <[email protected]>2025-10-30 11:06:44 -0600
commit08bf42e1faa4411cd347c2e370da790a0116e318 (patch)
treecc953ba9176fd10d374b250a04c5457c585be6c0 /drivers/usb
parent557606968646a5215b656e0e1e8927e1902f32bf (diff)
parent934647d49c61f9405767bd36da3bba06a40cf346 (diff)
Merge tag 'qcom-for-2026.01-rc2' of https://source.denx.de/u-boot/custodians/u-boot-snapdragon
A variety of Qualcomm features/fixes for this cycle, notably with a few new platforms gaining support: * Initial support for SDM670 (similar to SDM845), SM6350, and SM7150 platforms is added * USB and UART issues on MSM8916 are addressed (improving stability/ reliability) * Firmware loading is implemented for the GENI serial engine, this is used on some platforms to load firmware for i2c/spi/uart to work Some additional patches like binman support for building MBN files still need some additional work. CI: https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/commit/8ef6ac07b35e39a57501554680bbf452e818d3e3/pipelines?ref=qcom-main
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/host/ehci-msm.c146
2 files changed, 69 insertions, 79 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index e845e46e0b7..008f8c99a58 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -60,6 +60,7 @@ config USB_GADGET_VENDOR_NUM
default 0x0955 if ARCH_TEGRA
default 0x1f3a if ARCH_SUNXI
default 0x2207 if ARCH_ROCKCHIP
+ default 0x18d1 if ARCH_QCOM
default 0x0
help
Vendor ID of the USB device emulated, reported to the host device.
@@ -87,6 +88,7 @@ config USB_GADGET_PRODUCT_NUM
default 0x350b if ROCKCHIP_RK3588
default 0x350c if ROCKCHIP_RK3528
default 0x350e if ROCKCHIP_RK3576
+ default 0x4ee0 if ARCH_QCOM
default 0x0
help
Product ID of the USB device emulated, reported to the host device.
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index a759aea9db3..8aeb6a91556 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -24,10 +24,11 @@
struct msm_ehci_priv {
struct ehci_ctrl ctrl; /* Needed by EHCI */
struct usb_ehci *ehci; /* Start of IP core*/
- struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
struct phy phy;
- struct clk iface_clk;
- struct clk core_clk;
+};
+
+struct qcom_ci_hdrc_priv {
+ struct clk_bulk clks;
};
static int msm_init_after_reset(struct ehci_ctrl *dev)
@@ -56,64 +57,31 @@ static int ehci_usb_probe(struct udevice *dev)
struct ehci_hcor *hcor;
int ret;
- ret = clk_get_by_name(dev, "core", &p->core_clk);
- if (ret) {
- dev_err(dev, "Failed to get core clock: %d\n", ret);
- return ret;
- }
-
- ret = clk_get_by_name(dev, "iface", &p->iface_clk);
- if (ret) {
- dev_err(dev, "Failed to get iface clock: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(&p->core_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(&p->iface_clk);
- if (ret)
- goto cleanup_core;
-
hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
ret = generic_setup_phy(dev, &p->phy, 0, PHY_MODE_USB_HOST, 0);
if (ret)
- goto cleanup_iface;
+ return ret;
ret = board_usb_init(0, plat->init_type);
if (ret < 0)
- goto cleanup_iface;
+ return ret;
return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
plat->init_type);
-
-cleanup_iface:
- clk_disable_unprepare(&p->iface_clk);
-cleanup_core:
- clk_disable_unprepare(&p->core_clk);
- return ret;
}
static int ehci_usb_remove(struct udevice *dev)
{
struct msm_ehci_priv *p = dev_get_priv(dev);
- struct usb_ehci *ehci = p->ehci;
int ret;
ret = ehci_deregister(dev);
if (ret)
return ret;
- /* Stop controller. */
- clrbits_le32(&ehci->usbcmd, CMD_RUN);
-
- clk_disable_unprepare(&p->iface_clk);
- clk_disable_unprepare(&p->core_clk);
-
ret = generic_shutdown_phy(&p->phy);
if (ret)
return ret;
@@ -122,15 +90,6 @@ static int ehci_usb_remove(struct udevice *dev)
if (ret < 0)
return ret;
- /* Reset controller */
- setbits_le32(&ehci->usbcmd, CMD_RESET);
-
- /* Wait for reset */
- if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
- printf("Stuck on USB reset.\n");
- return -ETIMEDOUT;
- }
-
return 0;
}
@@ -138,38 +97,14 @@ static int ehci_usb_of_to_plat(struct udevice *dev)
{
struct msm_ehci_priv *priv = dev_get_priv(dev);
- priv->ulpi_vp.port_num = 0;
priv->ehci = dev_read_addr_ptr(dev);
- if (priv->ehci == (void *)FDT_ADDR_T_NONE)
+ if (!priv->ehci)
return -EINVAL;
- /* Warning: this will not work if viewport address is > 64 bit due to
- * ULPI design.
- */
- priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
-
return 0;
}
-static int ehci_usb_of_bind(struct udevice *dev)
-{
- ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
- ofnode phy_node;
-
- if (!ofnode_valid(ulpi_node))
- return 0;
-
- phy_node = ofnode_first_subnode(ulpi_node);
- if (!ofnode_valid(phy_node)) {
- printf("%s: ulpi subnode with no phy\n", __func__);
- return -ENOENT;
- }
-
- return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
- phy_node, NULL);
-}
-
#if defined(CONFIG_CI_UDC)
/* Little quirk that MSM needs with Chipidea controller
* Must reinit phy after reset
@@ -182,17 +117,10 @@ void ci_init_after_reset(struct ehci_ctrl *ctrl)
}
#endif
-static const struct udevice_id ehci_usb_ids[] = {
- { .compatible = "qcom,ci-hdrc", },
- { }
-};
-
U_BOOT_DRIVER(usb_ehci) = {
.name = "ehci_msm",
.id = UCLASS_USB,
- .of_match = ehci_usb_ids,
.of_to_plat = ehci_usb_of_to_plat,
- .bind = ehci_usb_of_bind,
.probe = ehci_usb_probe,
.remove = ehci_usb_remove,
.ops = &ehci_usb_ops,
@@ -200,3 +128,63 @@ U_BOOT_DRIVER(usb_ehci) = {
.plat_auto = sizeof(struct usb_plat),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
+
+static int qcom_ci_hdrc_probe(struct udevice *dev)
+{
+ struct qcom_ci_hdrc_priv *p = dev_get_priv(dev);
+ int ret;
+
+ ret = clk_get_bulk(dev, &p->clks);
+ if (ret && (ret != -ENOSYS && ret != -ENOENT)) {
+ dev_err(dev, "Failed to get clocks: %d\n", ret);
+ return ret;
+ }
+
+ return clk_enable_bulk(&p->clks);
+}
+
+static int qcom_ci_hdrc_remove(struct udevice *dev)
+{
+ struct qcom_ci_hdrc_priv *p = dev_get_priv(dev);
+
+ return clk_release_bulk(&p->clks);
+}
+
+static int qcom_ci_hdrc_bind(struct udevice *dev)
+{
+ ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
+ ofnode phy_node;
+ int ret;
+
+ ret = device_bind_driver_to_node(dev, "ehci_msm", "ehci_msm",
+ dev_ofnode(dev), NULL);
+ if (ret)
+ return ret;
+
+ if (!ofnode_valid(ulpi_node))
+ return 0;
+
+ phy_node = ofnode_first_subnode(ulpi_node);
+ if (!ofnode_valid(phy_node)) {
+ printf("%s: ulpi subnode with no phy\n", __func__);
+ return -ENOENT;
+ }
+
+ return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
+ phy_node, NULL);
+}
+
+static const struct udevice_id qcom_ci_hdrc_ids[] = {
+ { .compatible = "qcom,ci-hdrc", },
+ { }
+};
+
+U_BOOT_DRIVER(qcom_ci_hdrc) = {
+ .name = "qcom_ci_hdrc",
+ .id = UCLASS_NOP,
+ .of_match = qcom_ci_hdrc_ids,
+ .bind = qcom_ci_hdrc_bind,
+ .probe = qcom_ci_hdrc_probe,
+ .remove = qcom_ci_hdrc_remove,
+ .priv_auto = sizeof(struct qcom_ci_hdrc_priv),
+};