]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e5a94af8 LY |
2 | /* |
3 | * Freescale 83xx USB SOC setup code | |
4 | * | |
5 | * Copyright (C) 2007 Freescale Semiconductor, Inc. | |
6 | * Author: Li Yang | |
e5a94af8 LY |
7 | */ |
8 | ||
9 | ||
10 | #include <linux/stddef.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/errno.h> | |
c026c987 | 13 | #include <linux/of.h> |
e5a94af8 LY |
14 | |
15 | #include <asm/io.h> | |
16 | #include <asm/prom.h> | |
17 | #include <sysdev/fsl_soc.h> | |
18 | ||
19 | #include "mpc83xx.h" | |
20 | ||
21 | ||
b38308ac | 22 | #ifdef CONFIG_PPC_MPC834x |
e5a94af8 LY |
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 | ||
866b6ddd | 41 | np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr"); |
e5a94af8 LY |
42 | if (np) { |
43 | sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ | |
44 | ||
45 | prop = of_get_property(np, "phy_type", NULL); | |
b7d66c88 | 46 | port1_is_dr = 1; |
e5a94af8 LY |
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; | |
b7d66c88 | 51 | port0_is_dr = 1; |
e5a94af8 LY |
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; | |
b7d66c88 | 56 | port0_is_dr = 1; |
e5a94af8 | 57 | } else { |
b7d66c88 | 58 | sicrl |= MPC834X_SICRL_USB1; |
e5a94af8 LY |
59 | } |
60 | } else if (prop && !strcmp(prop, "ulpi")) { | |
b7d66c88 | 61 | sicrl |= MPC834X_SICRL_USB1; |
e5a94af8 LY |
62 | } else { |
63 | printk(KERN_WARNING "834x USB PHY type not supported\n"); | |
64 | } | |
e5a94af8 LY |
65 | of_node_put(np); |
66 | } | |
866b6ddd | 67 | np = of_find_compatible_node(NULL, NULL, "fsl-usb2-mph"); |
e5a94af8 LY |
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"); | |
39db0fd9 | 76 | sicrl &= ~MPC834X_SICRL_USB0; |
e5a94af8 LY |
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"); | |
39db0fd9 | 83 | sicrl &= ~MPC834X_SICRL_USB1; |
e5a94af8 LY |
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 | } | |
b38308ac | 96 | #endif /* CONFIG_PPC_MPC834x */ |
e5a94af8 LY |
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; | |
b74a7e50 | 104 | struct device_node *immr_node = NULL; |
e5a94af8 LY |
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 | ||
866b6ddd | 112 | np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr"); |
e5a94af8 LY |
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 */ | |
b74a7e50 | 125 | immr_node = of_get_parent(np); |
fd066e85 IY |
126 | if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") || |
127 | of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))) | |
b74a7e50 KP |
128 | clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, |
129 | MPC8315_SCCR_USB_MASK, | |
1a9ebc0c | 130 | MPC8315_SCCR_USB_DRCM_01); |
b74a7e50 KP |
131 | else |
132 | clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, | |
133 | MPC83XX_SCCR_USB_MASK, | |
134 | MPC83XX_SCCR_USB_DRCM_11); | |
e5a94af8 LY |
135 | |
136 | /* Configure pin mux for ULPI. There is no pin mux for UTMI */ | |
7ac33417 | 137 | if (prop && !strcmp(prop, "ulpi")) { |
fd066e85 IY |
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")) { | |
c0a20159 AV |
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 | } | |
e5a94af8 LY |
157 | } |
158 | ||
159 | iounmap(immap); | |
160 | ||
8ac6e995 | 161 | of_node_put(immr_node); |
b74a7e50 | 162 | |
e5a94af8 LY |
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 | } | |
28f65c11 | 169 | usb_regs = ioremap(res.start, resource_size(&res)); |
e5a94af8 LY |
170 | |
171 | /* Using on-chip PHY */ | |
7ac33417 CG |
172 | if (prop && (!strcmp(prop, "utmi_wide") || |
173 | !strcmp(prop, "utmi"))) { | |
1a9ebc0c AV |
174 | u32 refsel; |
175 | ||
fd066e85 IY |
176 | if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) |
177 | goto out; | |
178 | ||
1a9ebc0c AV |
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 */ | |
e5a94af8 | 184 | out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, |
1a9ebc0c | 185 | CONTROL_UTMI_PHY_EN | refsel); |
e5a94af8 | 186 | /* Using external UPLI PHY */ |
7ac33417 | 187 | } else if (prop && !strcmp(prop, "ulpi")) { |
e5a94af8 LY |
188 | /* Set PHY_CLK_SEL to ULPI */ |
189 | temp = CONTROL_PHY_CLK_SEL_ULPI; | |
190 | #ifdef CONFIG_USB_OTG | |
191 | /* Set OTG_PORT */ | |
fd066e85 IY |
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 | } | |
e5a94af8 LY |
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 | ||
fd066e85 | 204 | out: |
e5a94af8 LY |
205 | iounmap(usb_regs); |
206 | of_node_put(np); | |
207 | return ret; | |
208 | } | |
209 | #endif /* CONFIG_PPC_MPC831x */ | |
e10241d8 LY |
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 | ||
866b6ddd | 219 | np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr"); |
4df2cb63 JL |
220 | if (!np || !of_device_is_available(np)) { |
221 | of_node_put(np); | |
e10241d8 | 222 | return -ENODEV; |
4df2cb63 | 223 | } |
e10241d8 LY |
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 */ |