Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / arch / powerpc / platforms / 83xx / usb.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Freescale 83xx USB SOC setup code
4  *
5  * Copyright (C) 2007 Freescale Semiconductor, Inc.
6  * Author: Li Yang
7  */
8
9
10 #include <linux/stddef.h>
11 #include <linux/kernel.h>
12 #include <linux/errno.h>
13 #include <linux/of.h>
14
15 #include <asm/io.h>
16 #include <asm/prom.h>
17 #include <sysdev/fsl_soc.h>
18
19 #include "mpc83xx.h"
20
21
22 #ifdef CONFIG_PPC_MPC834x
23 int mpc834x_usb_cfg(void)
24 {
25         unsigned long sccr, sicrl, sicrh;
26         void __iomem *immap;
27         struct device_node *np = NULL;
28         int port0_is_dr = 0, port1_is_dr = 0;
29         const void *prop, *dr_mode;
30
31         immap = ioremap(get_immrbase(), 0x1000);
32         if (!immap)
33                 return -ENOMEM;
34
35         /* Read registers */
36         /* Note: DR and MPH must use the same clock setting in SCCR */
37         sccr = in_be32(immap + MPC83XX_SCCR_OFFS) & ~MPC83XX_SCCR_USB_MASK;
38         sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK;
39         sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI;
40
41         np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
42         if (np) {
43                 sccr |= MPC83XX_SCCR_USB_DRCM_11;  /* 1:3 */
44
45                 prop = of_get_property(np, "phy_type", NULL);
46                 port1_is_dr = 1;
47                 if (prop && (!strcmp(prop, "utmi") ||
48                                         !strcmp(prop, "utmi_wide"))) {
49                         sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
50                         sicrh |= MPC834X_SICRH_USB_UTMI;
51                         port0_is_dr = 1;
52                 } else if (prop && !strcmp(prop, "serial")) {
53                         dr_mode = of_get_property(np, "dr_mode", NULL);
54                         if (dr_mode && !strcmp(dr_mode, "otg")) {
55                                 sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
56                                 port0_is_dr = 1;
57                         } else {
58                                 sicrl |= MPC834X_SICRL_USB1;
59                         }
60                 } else if (prop && !strcmp(prop, "ulpi")) {
61                         sicrl |= MPC834X_SICRL_USB1;
62                 } else {
63                         printk(KERN_WARNING "834x USB PHY type not supported\n");
64                 }
65                 of_node_put(np);
66         }
67         np = of_find_compatible_node(NULL, NULL, "fsl-usb2-mph");
68         if (np) {
69                 sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */
70
71                 prop = of_get_property(np, "port0", NULL);
72                 if (prop) {
73                         if (port0_is_dr)
74                                 printk(KERN_WARNING
75                                         "834x USB port0 can't be used by both DR and MPH!\n");
76                         sicrl &= ~MPC834X_SICRL_USB0;
77                 }
78                 prop = of_get_property(np, "port1", NULL);
79                 if (prop) {
80                         if (port1_is_dr)
81                                 printk(KERN_WARNING
82                                         "834x USB port1 can't be used by both DR and MPH!\n");
83                         sicrl &= ~MPC834X_SICRL_USB1;
84                 }
85                 of_node_put(np);
86         }
87
88         /* Write back */
89         out_be32(immap + MPC83XX_SCCR_OFFS, sccr);
90         out_be32(immap + MPC83XX_SICRL_OFFS, sicrl);
91         out_be32(immap + MPC83XX_SICRH_OFFS, sicrh);
92
93         iounmap(immap);
94         return 0;
95 }
96 #endif /* CONFIG_PPC_MPC834x */
97
98 #ifdef CONFIG_PPC_MPC831x
99 int mpc831x_usb_cfg(void)
100 {
101         u32 temp;
102         void __iomem *immap, *usb_regs;
103         struct device_node *np = NULL;
104         struct device_node *immr_node = NULL;
105         const void *prop;
106         struct resource res;
107         int ret = 0;
108 #ifdef CONFIG_USB_OTG
109         const void *dr_mode;
110 #endif
111
112         np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
113         if (!np)
114                 return -ENODEV;
115         prop = of_get_property(np, "phy_type", NULL);
116
117         /* Map IMMR space for pin and clock settings */
118         immap = ioremap(get_immrbase(), 0x1000);
119         if (!immap) {
120                 of_node_put(np);
121                 return -ENOMEM;
122         }
123
124         /* Configure clock */
125         immr_node = of_get_parent(np);
126         if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") ||
127                         of_device_is_compatible(immr_node, "fsl,mpc8308-immr")))
128                 clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
129                                 MPC8315_SCCR_USB_MASK,
130                                 MPC8315_SCCR_USB_DRCM_01);
131         else
132                 clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
133                                 MPC83XX_SCCR_USB_MASK,
134                                 MPC83XX_SCCR_USB_DRCM_11);
135
136         /* Configure pin mux for ULPI.  There is no pin mux for UTMI */
137         if (prop && !strcmp(prop, "ulpi")) {
138                 if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
139                         clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
140                                         MPC8308_SICRH_USB_MASK,
141                                         MPC8308_SICRH_USB_ULPI);
142                 } else if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
143                         clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
144                                         MPC8315_SICRL_USB_MASK,
145                                         MPC8315_SICRL_USB_ULPI);
146                         clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
147                                         MPC8315_SICRH_USB_MASK,
148                                         MPC8315_SICRH_USB_ULPI);
149                 } else {
150                         clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
151                                         MPC831X_SICRL_USB_MASK,
152                                         MPC831X_SICRL_USB_ULPI);
153                         clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
154                                         MPC831X_SICRH_USB_MASK,
155                                         MPC831X_SICRH_USB_ULPI);
156                 }
157         }
158
159         iounmap(immap);
160
161         of_node_put(immr_node);
162
163         /* Map USB SOC space */
164         ret = of_address_to_resource(np, 0, &res);
165         if (ret) {
166                 of_node_put(np);
167                 return ret;
168         }
169         usb_regs = ioremap(res.start, resource_size(&res));
170
171         /* Using on-chip PHY */
172         if (prop && (!strcmp(prop, "utmi_wide") ||
173                      !strcmp(prop, "utmi"))) {
174                 u32 refsel;
175
176                 if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))
177                         goto out;
178
179                 if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
180                         refsel = CONTROL_REFSEL_24MHZ;
181                 else
182                         refsel = CONTROL_REFSEL_48MHZ;
183                 /* Set UTMI_PHY_EN and REFSEL */
184                 out_be32(usb_regs + FSL_USB2_CONTROL_OFFS,
185                                 CONTROL_UTMI_PHY_EN | refsel);
186         /* Using external UPLI PHY */
187         } else if (prop && !strcmp(prop, "ulpi")) {
188                 /* Set PHY_CLK_SEL to ULPI */
189                 temp = CONTROL_PHY_CLK_SEL_ULPI;
190 #ifdef CONFIG_USB_OTG
191                 /* Set OTG_PORT */
192                 if (!of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
193                         dr_mode = of_get_property(np, "dr_mode", NULL);
194                         if (dr_mode && !strcmp(dr_mode, "otg"))
195                                 temp |= CONTROL_OTG_PORT;
196                 }
197 #endif /* CONFIG_USB_OTG */
198                 out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp);
199         } else {
200                 printk(KERN_WARNING "831x USB PHY type not supported\n");
201                 ret = -EINVAL;
202         }
203
204 out:
205         iounmap(usb_regs);
206         of_node_put(np);
207         return ret;
208 }
209 #endif /* CONFIG_PPC_MPC831x */
210
211 #ifdef CONFIG_PPC_MPC837x
212 int mpc837x_usb_cfg(void)
213 {
214         void __iomem *immap;
215         struct device_node *np = NULL;
216         const void *prop;
217         int ret = 0;
218
219         np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
220         if (!np || !of_device_is_available(np)) {
221                 of_node_put(np);
222                 return -ENODEV;
223         }
224         prop = of_get_property(np, "phy_type", NULL);
225
226         if (!prop || (strcmp(prop, "ulpi") && strcmp(prop, "serial"))) {
227                 printk(KERN_WARNING "837x USB PHY type not supported\n");
228                 of_node_put(np);
229                 return -EINVAL;
230         }
231
232         /* Map IMMR space for pin and clock settings */
233         immap = ioremap(get_immrbase(), 0x1000);
234         if (!immap) {
235                 of_node_put(np);
236                 return -ENOMEM;
237         }
238
239         /* Configure clock */
240         clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, MPC837X_SCCR_USB_DRCM_11,
241                         MPC837X_SCCR_USB_DRCM_11);
242
243         /* Configure pin mux for ULPI/serial */
244         clrsetbits_be32(immap + MPC83XX_SICRL_OFFS, MPC837X_SICRL_USB_MASK,
245                         MPC837X_SICRL_USB_ULPI);
246
247         iounmap(immap);
248         of_node_put(np);
249         return ret;
250 }
251 #endif /* CONFIG_PPC_MPC837x */