1 | /* |
2 | * |
3 | * Utility functions for the Freescale MPC52xx. |
4 | * |
5 | * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com> |
6 | * |
7 | * This file is licensed under the terms of the GNU General Public License |
8 | * version 2. This program is licensed "as is" without any warranty of any |
9 | * kind, whether express or implied. |
10 | * |
11 | */ |
12 | |
13 | #undef DEBUG |
14 | |
15 | #include <linux/gpio.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/spinlock.h> |
18 | #include <linux/of_address.h> |
19 | #include <linux/of_platform.h> |
20 | #include <linux/of_gpio.h> |
21 | #include <linux/export.h> |
22 | #include <asm/io.h> |
23 | #include <asm/mpc52xx.h> |
24 | |
25 | /* MPC5200 device tree match tables */ |
26 | static const struct of_device_id mpc52xx_xlb_ids[] __initconst = { |
27 | { .compatible = "fsl,mpc5200-xlb" , }, |
28 | { .compatible = "mpc5200-xlb" , }, |
29 | {} |
30 | }; |
31 | static const struct of_device_id mpc52xx_bus_ids[] __initconst = { |
32 | { .compatible = "fsl,mpc5200-immr" , }, |
33 | { .compatible = "fsl,mpc5200b-immr" , }, |
34 | { .compatible = "simple-bus" , }, |
35 | |
36 | /* depreciated matches; shouldn't be used in new device trees */ |
37 | { .compatible = "fsl,lpb" , }, |
38 | { .type = "builtin" , .compatible = "mpc5200" , }, /* efika */ |
39 | { .type = "soc" , .compatible = "mpc5200" , }, /* lite5200 */ |
40 | {} |
41 | }; |
42 | |
43 | /* |
44 | * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart(). |
45 | * Permanent mapping is required because mpc52xx_restart() can be called |
46 | * from interrupt context while node mapping (which calls ioremap()) |
47 | * cannot be used at such point. |
48 | */ |
49 | static DEFINE_SPINLOCK(mpc52xx_lock); |
50 | static struct mpc52xx_gpt __iomem *mpc52xx_wdt; |
51 | static struct mpc52xx_cdm __iomem *mpc52xx_cdm; |
52 | |
53 | /* |
54 | * Configure the XLB arbiter settings to match what Linux expects. |
55 | */ |
56 | void __init |
57 | mpc5200_setup_xlb_arbiter(void) |
58 | { |
59 | struct device_node *np; |
60 | struct mpc52xx_xlb __iomem *xlb; |
61 | |
62 | np = of_find_matching_node(NULL, matches: mpc52xx_xlb_ids); |
63 | xlb = of_iomap(node: np, index: 0); |
64 | of_node_put(node: np); |
65 | if (!xlb) { |
66 | printk(KERN_ERR __FILE__ ": " |
67 | "Error mapping XLB in mpc52xx_setup_cpu(). " |
68 | "Expect some abnormal behavior\n" ); |
69 | return; |
70 | } |
71 | |
72 | /* Configure the XLB Arbiter priorities */ |
73 | out_be32(&xlb->master_pri_enable, 0xff); |
74 | out_be32(&xlb->master_priority, 0x11111111); |
75 | |
76 | /* |
77 | * Disable XLB pipelining |
78 | * (cfr errate 292. We could do this only just before ATA PIO |
79 | * transaction and re-enable it afterwards ...) |
80 | * Not needed on MPC5200B. |
81 | */ |
82 | if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) |
83 | out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS); |
84 | |
85 | iounmap(addr: xlb); |
86 | } |
87 | |
88 | /* |
89 | * This variable is mapped in mpc52xx_map_common_devices and |
90 | * used in mpc5200_psc_ac97_gpio_reset(). |
91 | */ |
92 | static DEFINE_SPINLOCK(gpio_lock); |
93 | struct mpc52xx_gpio __iomem *simple_gpio; |
94 | struct mpc52xx_gpio_wkup __iomem *wkup_gpio; |
95 | |
96 | /** |
97 | * mpc52xx_declare_of_platform_devices: register internal devices and children |
98 | * of the localplus bus to the of_platform |
99 | * bus. |
100 | */ |
101 | void __init mpc52xx_declare_of_platform_devices(void) |
102 | { |
103 | /* Find all the 'platform' devices and register them. */ |
104 | if (of_platform_populate(NULL, matches: mpc52xx_bus_ids, NULL, NULL)) |
105 | pr_err(__FILE__ ": Error while populating devices from DT\n" ); |
106 | } |
107 | |
108 | /* |
109 | * match tables used by mpc52xx_map_common_devices() |
110 | */ |
111 | static const struct of_device_id mpc52xx_gpt_ids[] __initconst = { |
112 | { .compatible = "fsl,mpc5200-gpt" , }, |
113 | { .compatible = "mpc5200-gpt" , }, /* old */ |
114 | {} |
115 | }; |
116 | static const struct of_device_id mpc52xx_cdm_ids[] __initconst = { |
117 | { .compatible = "fsl,mpc5200-cdm" , }, |
118 | { .compatible = "mpc5200-cdm" , }, /* old */ |
119 | {} |
120 | }; |
121 | static const struct of_device_id mpc52xx_gpio_simple[] __initconst = { |
122 | { .compatible = "fsl,mpc5200-gpio" , }, |
123 | {} |
124 | }; |
125 | static const struct of_device_id mpc52xx_gpio_wkup[] __initconst = { |
126 | { .compatible = "fsl,mpc5200-gpio-wkup" , }, |
127 | {} |
128 | }; |
129 | |
130 | |
131 | /** |
132 | * mpc52xx_map_common_devices: iomap devices required by common code |
133 | */ |
134 | void __init |
135 | mpc52xx_map_common_devices(void) |
136 | { |
137 | struct device_node *np; |
138 | |
139 | /* mpc52xx_wdt is mapped here and used in mpc52xx_restart, |
140 | * possibly from a interrupt context. wdt is only implement |
141 | * on a gpt0, so check has-wdt property before mapping. |
142 | */ |
143 | for_each_matching_node(np, mpc52xx_gpt_ids) { |
144 | if (of_property_read_bool(np, propname: "fsl,has-wdt" ) || |
145 | of_property_read_bool(np, propname: "has-wdt" )) { |
146 | mpc52xx_wdt = of_iomap(node: np, index: 0); |
147 | of_node_put(node: np); |
148 | break; |
149 | } |
150 | } |
151 | |
152 | /* Clock Distribution Module, used by PSC clock setting function */ |
153 | np = of_find_matching_node(NULL, matches: mpc52xx_cdm_ids); |
154 | mpc52xx_cdm = of_iomap(node: np, index: 0); |
155 | of_node_put(node: np); |
156 | |
157 | /* simple_gpio registers */ |
158 | np = of_find_matching_node(NULL, matches: mpc52xx_gpio_simple); |
159 | simple_gpio = of_iomap(node: np, index: 0); |
160 | of_node_put(node: np); |
161 | |
162 | /* wkup_gpio registers */ |
163 | np = of_find_matching_node(NULL, matches: mpc52xx_gpio_wkup); |
164 | wkup_gpio = of_iomap(node: np, index: 0); |
165 | of_node_put(node: np); |
166 | } |
167 | |
168 | /** |
169 | * mpc52xx_set_psc_clkdiv: Set clock divider in the CDM for PSC ports |
170 | * |
171 | * @psc_id: id of psc port; must be 1,2,3 or 6 |
172 | * @clkdiv: clock divider value to put into CDM PSC register. |
173 | */ |
174 | int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv) |
175 | { |
176 | unsigned long flags; |
177 | u16 __iomem *reg; |
178 | u32 val; |
179 | u32 mask; |
180 | u32 mclken_div; |
181 | |
182 | if (!mpc52xx_cdm) |
183 | return -ENODEV; |
184 | |
185 | mclken_div = 0x8000 | (clkdiv & 0x1FF); |
186 | switch (psc_id) { |
187 | case 1: reg = &mpc52xx_cdm->mclken_div_psc1; mask = 0x20; break; |
188 | case 2: reg = &mpc52xx_cdm->mclken_div_psc2; mask = 0x40; break; |
189 | case 3: reg = &mpc52xx_cdm->mclken_div_psc3; mask = 0x80; break; |
190 | case 6: reg = &mpc52xx_cdm->mclken_div_psc6; mask = 0x10; break; |
191 | default: |
192 | return -ENODEV; |
193 | } |
194 | |
195 | /* Set the rate and enable the clock */ |
196 | spin_lock_irqsave(&mpc52xx_lock, flags); |
197 | out_be16(reg, mclken_div); |
198 | val = in_be32(&mpc52xx_cdm->clk_enables); |
199 | out_be32(&mpc52xx_cdm->clk_enables, val | mask); |
200 | spin_unlock_irqrestore(lock: &mpc52xx_lock, flags); |
201 | |
202 | return 0; |
203 | } |
204 | EXPORT_SYMBOL(mpc52xx_set_psc_clkdiv); |
205 | |
206 | /** |
207 | * mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer |
208 | */ |
209 | void __noreturn mpc52xx_restart(char *cmd) |
210 | { |
211 | local_irq_disable(); |
212 | |
213 | /* Turn on the watchdog and wait for it to expire. |
214 | * It effectively does a reset. */ |
215 | if (mpc52xx_wdt) { |
216 | out_be32(&mpc52xx_wdt->mode, 0x00000000); |
217 | out_be32(&mpc52xx_wdt->count, 0x000000ff); |
218 | out_be32(&mpc52xx_wdt->mode, 0x00009004); |
219 | } else |
220 | printk(KERN_ERR __FILE__ ": " |
221 | "mpc52xx_restart: Can't access wdt. " |
222 | "Restart impossible, system halted.\n" ); |
223 | |
224 | while (1); |
225 | } |
226 | |
227 | #define PSC1_RESET 0x1 |
228 | #define PSC1_SYNC 0x4 |
229 | #define PSC1_SDATA_OUT 0x1 |
230 | #define PSC2_RESET 0x2 |
231 | #define PSC2_SYNC (0x4<<4) |
232 | #define PSC2_SDATA_OUT (0x1<<4) |
233 | #define MPC52xx_GPIO_PSC1_MASK 0x7 |
234 | #define MPC52xx_GPIO_PSC2_MASK (0x7<<4) |
235 | |
236 | /** |
237 | * mpc5200_psc_ac97_gpio_reset: Use gpio pins to reset the ac97 bus |
238 | * |
239 | * @psc: psc number to reset (only psc 1 and 2 support ac97) |
240 | */ |
241 | int mpc5200_psc_ac97_gpio_reset(int psc_number) |
242 | { |
243 | unsigned long flags; |
244 | u32 gpio; |
245 | u32 mux; |
246 | int out; |
247 | int reset; |
248 | int sync; |
249 | |
250 | if ((!simple_gpio) || (!wkup_gpio)) |
251 | return -ENODEV; |
252 | |
253 | switch (psc_number) { |
254 | case 0: |
255 | reset = PSC1_RESET; /* AC97_1_RES */ |
256 | sync = PSC1_SYNC; /* AC97_1_SYNC */ |
257 | out = PSC1_SDATA_OUT; /* AC97_1_SDATA_OUT */ |
258 | gpio = MPC52xx_GPIO_PSC1_MASK; |
259 | break; |
260 | case 1: |
261 | reset = PSC2_RESET; /* AC97_2_RES */ |
262 | sync = PSC2_SYNC; /* AC97_2_SYNC */ |
263 | out = PSC2_SDATA_OUT; /* AC97_2_SDATA_OUT */ |
264 | gpio = MPC52xx_GPIO_PSC2_MASK; |
265 | break; |
266 | default: |
267 | pr_err(__FILE__ ": Unable to determine PSC, no ac97 " |
268 | "cold-reset will be performed\n" ); |
269 | return -ENODEV; |
270 | } |
271 | |
272 | spin_lock_irqsave(&gpio_lock, flags); |
273 | |
274 | /* Reconfigure pin-muxing to gpio */ |
275 | mux = in_be32(&simple_gpio->port_config); |
276 | out_be32(&simple_gpio->port_config, mux & (~gpio)); |
277 | |
278 | /* enable gpio pins for output */ |
279 | setbits8(&wkup_gpio->wkup_gpioe, reset); |
280 | setbits32(&simple_gpio->simple_gpioe, sync | out); |
281 | |
282 | setbits8(&wkup_gpio->wkup_ddr, reset); |
283 | setbits32(&simple_gpio->simple_ddr, sync | out); |
284 | |
285 | /* Assert cold reset */ |
286 | clrbits32(&simple_gpio->simple_dvo, sync | out); |
287 | clrbits8(&wkup_gpio->wkup_dvo, reset); |
288 | |
289 | /* wait for 1 us */ |
290 | udelay(1); |
291 | |
292 | /* Deassert reset */ |
293 | setbits8(&wkup_gpio->wkup_dvo, reset); |
294 | |
295 | /* wait at least 200ns */ |
296 | /* 7 ~= (200ns * timebase) / ns2sec */ |
297 | __delay(7); |
298 | |
299 | /* Restore pin-muxing */ |
300 | out_be32(&simple_gpio->port_config, mux); |
301 | |
302 | spin_unlock_irqrestore(lock: &gpio_lock, flags); |
303 | |
304 | return 0; |
305 | } |
306 | EXPORT_SYMBOL(mpc5200_psc_ac97_gpio_reset); |
307 | |