diff options
Diffstat (limited to 'arch/powerpc/platforms/83xx/usb.c')
-rw-r--r-- | arch/powerpc/platforms/83xx/usb.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c new file mode 100644 index 000000000000..e7fdf013cd39 --- /dev/null +++ b/arch/powerpc/platforms/83xx/usb.c | |||
@@ -0,0 +1,181 @@ | |||
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> | ||
17 | |||
18 | #include <asm/io.h> | ||
19 | #include <asm/prom.h> | ||
20 | #include <sysdev/fsl_soc.h> | ||
21 | |||
22 | #include "mpc83xx.h" | ||
23 | |||
24 | |||
25 | #ifdef CONFIG_MPC834x | ||
26 | int mpc834x_usb_cfg(void) | ||
27 | { | ||
28 | unsigned long sccr, sicrl, sicrh; | ||
29 | void __iomem *immap; | ||
30 | struct device_node *np = NULL; | ||
31 | int port0_is_dr = 0, port1_is_dr = 0; | ||
32 | const void *prop, *dr_mode; | ||
33 | |||
34 | immap = ioremap(get_immrbase(), 0x1000); | ||
35 | if (!immap) | ||
36 | return -ENOMEM; | ||
37 | |||
38 | /* Read registers */ | ||
39 | /* Note: DR and MPH must use the same clock setting in SCCR */ | ||
40 | sccr = in_be32(immap + MPC83XX_SCCR_OFFS) & ~MPC83XX_SCCR_USB_MASK; | ||
41 | sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK; | ||
42 | sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI; | ||
43 | |||
44 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); | ||
45 | if (np) { | ||
46 | sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ | ||
47 | |||
48 | prop = of_get_property(np, "phy_type", NULL); | ||
49 | if (prop && (!strcmp(prop, "utmi") || | ||
50 | !strcmp(prop, "utmi_wide"))) { | ||
51 | sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1; | ||
52 | sicrh |= MPC834X_SICRH_USB_UTMI; | ||
53 | port1_is_dr = 1; | ||
54 | } else if (prop && !strcmp(prop, "serial")) { | ||
55 | dr_mode = of_get_property(np, "dr_mode", NULL); | ||
56 | if (dr_mode && !strcmp(dr_mode, "otg")) { | ||
57 | sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1; | ||
58 | port1_is_dr = 1; | ||
59 | } else { | ||
60 | sicrl |= MPC834X_SICRL_USB0; | ||
61 | } | ||
62 | } else if (prop && !strcmp(prop, "ulpi")) { | ||
63 | sicrl |= MPC834X_SICRL_USB0; | ||
64 | } else { | ||
65 | printk(KERN_WARNING "834x USB PHY type not supported\n"); | ||
66 | } | ||
67 | port0_is_dr = 1; | ||
68 | of_node_put(np); | ||
69 | } | ||
70 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph"); | ||
71 | if (np) { | ||
72 | sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ | ||
73 | |||
74 | prop = of_get_property(np, "port0", NULL); | ||
75 | if (prop) { | ||
76 | if (port0_is_dr) | ||
77 | printk(KERN_WARNING | ||
78 | "834x USB port0 can't be used by both DR and MPH!\n"); | ||
79 | sicrl |= MPC834X_SICRL_USB0; | ||
80 | } | ||
81 | prop = of_get_property(np, "port1", NULL); | ||
82 | if (prop) { | ||
83 | if (port1_is_dr) | ||
84 | printk(KERN_WARNING | ||
85 | "834x USB port1 can't be used by both DR and MPH!\n"); | ||
86 | sicrl |= MPC834X_SICRL_USB1; | ||
87 | } | ||
88 | of_node_put(np); | ||
89 | } | ||
90 | |||
91 | /* Write back */ | ||
92 | out_be32(immap + MPC83XX_SCCR_OFFS, sccr); | ||
93 | out_be32(immap + MPC83XX_SICRL_OFFS, sicrl); | ||
94 | out_be32(immap + MPC83XX_SICRH_OFFS, sicrh); | ||
95 | |||
96 | iounmap(immap); | ||
97 | return 0; | ||
98 | } | ||
99 | #endif /* CONFIG_MPC834x */ | ||
100 | |||
101 | #ifdef CONFIG_PPC_MPC831x | ||
102 | int mpc831x_usb_cfg(void) | ||
103 | { | ||
104 | u32 temp; | ||
105 | void __iomem *immap, *usb_regs; | ||
106 | struct device_node *np = NULL; | ||
107 | const void *prop; | ||
108 | struct resource res; | ||
109 | int ret = 0; | ||
110 | #ifdef CONFIG_USB_OTG | ||
111 | const void *dr_mode; | ||
112 | #endif | ||
113 | |||
114 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); | ||
115 | if (!np) | ||
116 | return -ENODEV; | ||
117 | prop = of_get_property(np, "phy_type", NULL); | ||
118 | |||
119 | /* Map IMMR space for pin and clock settings */ | ||
120 | immap = ioremap(get_immrbase(), 0x1000); | ||
121 | if (!immap) { | ||
122 | of_node_put(np); | ||
123 | return -ENOMEM; | ||
124 | } | ||
125 | |||
126 | /* Configure clock */ | ||
127 | temp = in_be32(immap + MPC83XX_SCCR_OFFS); | ||
128 | temp &= ~MPC83XX_SCCR_USB_MASK; | ||
129 | temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ | ||
130 | out_be32(immap + MPC83XX_SCCR_OFFS, temp); | ||
131 | |||
132 | /* Configure pin mux for ULPI. There is no pin mux for UTMI */ | ||
133 | if (!strcmp(prop, "ulpi")) { | ||
134 | temp = in_be32(immap + MPC83XX_SICRL_OFFS); | ||
135 | temp &= ~MPC831X_SICRL_USB_MASK; | ||
136 | temp |= MPC831X_SICRL_USB_ULPI; | ||
137 | out_be32(immap + MPC83XX_SICRL_OFFS, temp); | ||
138 | |||
139 | temp = in_be32(immap + MPC83XX_SICRH_OFFS); | ||
140 | temp &= ~MPC831X_SICRH_USB_MASK; | ||
141 | temp |= MPC831X_SICRH_USB_ULPI; | ||
142 | out_be32(immap + MPC83XX_SICRH_OFFS, temp); | ||
143 | } | ||
144 | |||
145 | iounmap(immap); | ||
146 | |||
147 | /* Map USB SOC space */ | ||
148 | ret = of_address_to_resource(np, 0, &res); | ||
149 | if (ret) { | ||
150 | of_node_put(np); | ||
151 | return ret; | ||
152 | } | ||
153 | usb_regs = ioremap(res.start, res.end - res.start + 1); | ||
154 | |||
155 | /* Using on-chip PHY */ | ||
156 | if (!strcmp(prop, "utmi_wide") || | ||
157 | !strcmp(prop, "utmi")) { | ||
158 | /* Set UTMI_PHY_EN, REFSEL to 48MHZ */ | ||
159 | out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, | ||
160 | CONTROL_UTMI_PHY_EN | CONTROL_REFSEL_48MHZ); | ||
161 | /* Using external UPLI PHY */ | ||
162 | } else if (!strcmp(prop, "ulpi")) { | ||
163 | /* Set PHY_CLK_SEL to ULPI */ | ||
164 | temp = CONTROL_PHY_CLK_SEL_ULPI; | ||
165 | #ifdef CONFIG_USB_OTG | ||
166 | /* Set OTG_PORT */ | ||
167 | dr_mode = of_get_property(np, "dr_mode", NULL); | ||
168 | if (dr_mode && !strcmp(dr_mode, "otg")) | ||
169 | temp |= CONTROL_OTG_PORT; | ||
170 | #endif /* CONFIG_USB_OTG */ | ||
171 | out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp); | ||
172 | } else { | ||
173 | printk(KERN_WARNING "831x USB PHY type not supported\n"); | ||
174 | ret = -EINVAL; | ||
175 | } | ||
176 | |||
177 | iounmap(usb_regs); | ||
178 | of_node_put(np); | ||
179 | return ret; | ||
180 | } | ||
181 | #endif /* CONFIG_PPC_MPC831x */ | ||