blob: 98fe7bc3bcb169d04a1d0770bbdb7dc8e1153b19 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Mateusz Kulikowskidc381172016-03-31 23:12:26 +02002/*
3 * Qualcomm EHCI driver
4 *
5 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
6 *
7 * Based on Linux driver
Mateusz Kulikowskidc381172016-03-31 23:12:26 +02008 */
9
10#include <common.h>
11#include <dm.h>
Caleb Connolly154ed1d2024-02-26 17:26:21 +000012#include <dm/lists.h>
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020013#include <errno.h>
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020014#include <usb.h>
15#include <usb/ehci-ci.h>
16#include <usb/ulpi.h>
17#include <wait_bit.h>
18#include <asm/gpio.h>
19#include <asm/io.h>
20#include <linux/compat.h>
21#include "ehci.h"
22
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020023struct msm_ehci_priv {
24 struct ehci_ctrl ctrl; /* Needed by EHCI */
25 struct usb_ehci *ehci; /* Start of IP core*/
26 struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
Ramon Fried7e365962018-09-21 13:35:50 +030027 struct phy phy;
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020028};
29
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020030static int msm_init_after_reset(struct ehci_ctrl *dev)
31{
32 struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl);
33 struct usb_ehci *ehci = p->ehci;
34
Ramon Fried7e365962018-09-21 13:35:50 +030035 generic_phy_reset(&p->phy);
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020036
37 /* set mode to host controller */
38 writel(CM_HOST, &ehci->usbmode);
39
40 return 0;
41}
42
43static const struct ehci_ops msm_ehci_ops = {
44 .init_after_reset = msm_init_after_reset
45};
46
47static int ehci_usb_probe(struct udevice *dev)
48{
49 struct msm_ehci_priv *p = dev_get_priv(dev);
50 struct usb_ehci *ehci = p->ehci;
Simon Glassb75b15b2020-12-03 16:55:23 -070051 struct usb_plat *plat = dev_get_plat(dev);
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020052 struct ehci_hccr *hccr;
53 struct ehci_hcor *hcor;
54 int ret;
55
56 hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
57 hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
58 HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
59
Patrice Chotard343ff752022-09-06 08:15:28 +020060 ret = generic_setup_phy(dev, &p->phy, 0);
Ramon Fried7e365962018-09-21 13:35:50 +030061 if (ret)
62 return ret;
63
Ramon Fried7b0334f2018-09-21 13:35:51 +030064 ret = board_usb_init(0, plat->init_type);
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020065 if (ret < 0)
66 return ret;
67
Ramon Fried7b0334f2018-09-21 13:35:51 +030068 return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
69 plat->init_type);
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020070}
71
72static int ehci_usb_remove(struct udevice *dev)
73{
74 struct msm_ehci_priv *p = dev_get_priv(dev);
75 struct usb_ehci *ehci = p->ehci;
76 int ret;
77
78 ret = ehci_deregister(dev);
79 if (ret)
80 return ret;
81
82 /* Stop controller. */
83 clrbits_le32(&ehci->usbcmd, CMD_RUN);
84
Patrice Chotard343ff752022-09-06 08:15:28 +020085 ret = generic_shutdown_phy(&p->phy);
Ramon Fried7e365962018-09-21 13:35:50 +030086 if (ret)
87 return ret;
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020088
Ramon Friedbc866cc82018-09-21 13:35:43 +030089 ret = board_usb_init(0, USB_INIT_DEVICE); /* Board specific hook */
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020090 if (ret < 0)
91 return ret;
92
93 /* Reset controller */
94 setbits_le32(&ehci->usbcmd, CMD_RESET);
95
96 /* Wait for reset */
Álvaro Fernández Rojas918de032018-01-23 17:14:55 +010097 if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
Mateusz Kulikowskidc381172016-03-31 23:12:26 +020098 printf("Stuck on USB reset.\n");
99 return -ETIMEDOUT;
100 }
101
102 return 0;
103}
104
Simon Glassaad29ae2020-12-03 16:55:21 -0700105static int ehci_usb_of_to_plat(struct udevice *dev)
Mateusz Kulikowskidc381172016-03-31 23:12:26 +0200106{
107 struct msm_ehci_priv *priv = dev_get_priv(dev);
108
109 priv->ulpi_vp.port_num = 0;
Kever Yangd24b1542020-03-04 08:59:49 +0800110 priv->ehci = dev_read_addr_ptr(dev);
Mateusz Kulikowskidc381172016-03-31 23:12:26 +0200111
112 if (priv->ehci == (void *)FDT_ADDR_T_NONE)
113 return -EINVAL;
114
115 /* Warning: this will not work if viewport address is > 64 bit due to
116 * ULPI design.
117 */
118 priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
119
120 return 0;
121}
122
Caleb Connolly154ed1d2024-02-26 17:26:21 +0000123static int ehci_usb_of_bind(struct udevice *dev)
124{
125 ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
126 ofnode phy_node;
127
128 if (!ofnode_valid(ulpi_node))
129 return 0;
130
131 phy_node = ofnode_first_subnode(ulpi_node);
132 if (!ofnode_valid(phy_node)) {
133 printf("%s: ulpi subnode with no phy\n", __func__);
134 return -ENOENT;
135 }
136
137 return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
138 phy_node, NULL);
139}
140
Ramon Friedcbee9082018-09-21 13:35:53 +0300141#if defined(CONFIG_CI_UDC)
142/* Little quirk that MSM needs with Chipidea controller
143 * Must reinit phy after reset
144 */
145void ci_init_after_reset(struct ehci_ctrl *ctrl)
146{
147 struct msm_ehci_priv *p = ctrl->priv;
148
149 generic_phy_reset(&p->phy);
150}
151#endif
152
Mateusz Kulikowskidc381172016-03-31 23:12:26 +0200153static const struct udevice_id ehci_usb_ids[] = {
Caleb Connolly154ed1d2024-02-26 17:26:21 +0000154 { .compatible = "qcom,ci-hdrc", },
Mateusz Kulikowskidc381172016-03-31 23:12:26 +0200155 { }
156};
157
158U_BOOT_DRIVER(usb_ehci) = {
159 .name = "ehci_msm",
160 .id = UCLASS_USB,
161 .of_match = ehci_usb_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700162 .of_to_plat = ehci_usb_of_to_plat,
Caleb Connolly154ed1d2024-02-26 17:26:21 +0000163 .bind = ehci_usb_of_bind,
Mateusz Kulikowskidc381172016-03-31 23:12:26 +0200164 .probe = ehci_usb_probe,
165 .remove = ehci_usb_remove,
166 .ops = &ehci_usb_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700167 .priv_auto = sizeof(struct msm_ehci_priv),
Simon Glassb75b15b2020-12-03 16:55:23 -0700168 .plat_auto = sizeof(struct usb_plat),
Mateusz Kulikowskidc381172016-03-31 23:12:26 +0200169 .flags = DM_FLAG_ALLOC_PRIV_DMA,
170};