]> git.ipfire.org Git - thirdparty/u-boot.git/blame - drivers/usb/host/ehci-msm.c
board: dragonboard410c: upstream DT compat
[thirdparty/u-boot.git] / drivers / usb / host / ehci-msm.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
5a822118
MK
2/*
3 * Qualcomm EHCI driver
4 *
5 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
6 *
7 * Based on Linux driver
5a822118
MK
8 */
9
10#include <common.h>
11#include <dm.h>
c744e630 12#include <dm/lists.h>
5a822118 13#include <errno.h>
5a822118
MK
14#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
5a822118
MK
23struct 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 */
0ac0b6eb 27 struct phy phy;
5a822118
MK
28};
29
5a822118
MK
30static 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
0ac0b6eb 35 generic_phy_reset(&p->phy);
5a822118
MK
36
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;
8a8d24bd 51 struct usb_plat *plat = dev_get_plat(dev);
5a822118
MK
52 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
083f8aa9 60 ret = generic_setup_phy(dev, &p->phy, 0);
0ac0b6eb
RF
61 if (ret)
62 return ret;
63
0683b27a 64 ret = board_usb_init(0, plat->init_type);
5a822118
MK
65 if (ret < 0)
66 return ret;
67
0683b27a
RF
68 return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
69 plat->init_type);
5a822118
MK
70}
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
083f8aa9 85 ret = generic_shutdown_phy(&p->phy);
0ac0b6eb
RF
86 if (ret)
87 return ret;
5a822118 88
cd8c3aec 89 ret = board_usb_init(0, USB_INIT_DEVICE); /* Board specific hook */
5a822118
MK
90 if (ret < 0)
91 return ret;
92
93 /* Reset controller */
94 setbits_le32(&ehci->usbcmd, CMD_RESET);
95
96 /* Wait for reset */
48263504 97 if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
5a822118
MK
98 printf("Stuck on USB reset.\n");
99 return -ETIMEDOUT;
100 }
101
102 return 0;
103}
104
d1998a9f 105static int ehci_usb_of_to_plat(struct udevice *dev)
5a822118
MK
106{
107 struct msm_ehci_priv *priv = dev_get_priv(dev);
108
109 priv->ulpi_vp.port_num = 0;
2be1130a 110 priv->ehci = dev_read_addr_ptr(dev);
5a822118
MK
111
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
c744e630
CC
123static 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
24667041
RF
141#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
5a822118 153static const struct udevice_id ehci_usb_ids[] = {
c744e630 154 { .compatible = "qcom,ci-hdrc", },
5a822118
MK
155 { }
156};
157
158U_BOOT_DRIVER(usb_ehci) = {
159 .name = "ehci_msm",
160 .id = UCLASS_USB,
161 .of_match = ehci_usb_ids,
d1998a9f 162 .of_to_plat = ehci_usb_of_to_plat,
c744e630 163 .bind = ehci_usb_of_bind,
5a822118
MK
164 .probe = ehci_usb_probe,
165 .remove = ehci_usb_remove,
166 .ops = &ehci_usb_ops,
41575d8e 167 .priv_auto = sizeof(struct msm_ehci_priv),
8a8d24bd 168 .plat_auto = sizeof(struct usb_plat),
5a822118
MK
169 .flags = DM_FLAG_ALLOC_PRIV_DMA,
170};