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