Merge branch 'bug-fixes' of git://farnsworth.org/dale/linux-2.6-mv643xx_eth into...
[linux-2.6] / arch / powerpc / platforms / 52xx / mpc52xx_common.c
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/kernel.h>
16 #include <linux/of_platform.h>
17 #include <asm/io.h>
18 #include <asm/prom.h>
19 #include <asm/mpc52xx.h>
20
21 /*
22  * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart().
23  * Permanent mapping is required because mpc52xx_restart() can be called
24  * from interrupt context while node mapping (which calls ioremap())
25  * cannot be used at such point.
26  */
27 static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL;
28
29 static void __iomem *
30 mpc52xx_map_node(struct device_node *ofn)
31 {
32         const u32 *regaddr_p;
33         u64 regaddr64, size64;
34
35         if (!ofn)
36                 return NULL;
37
38         regaddr_p = of_get_address(ofn, 0, &size64, NULL);
39         if (!regaddr_p) {
40                 of_node_put(ofn);
41                 return NULL;
42         }
43
44         regaddr64 = of_translate_address(ofn, regaddr_p);
45
46         of_node_put(ofn);
47
48         return ioremap((u32)regaddr64, (u32)size64);
49 }
50
51 void __iomem *
52 mpc52xx_find_and_map(const char *compatible)
53 {
54         return mpc52xx_map_node(
55                 of_find_compatible_node(NULL, NULL, compatible));
56 }
57
58 EXPORT_SYMBOL(mpc52xx_find_and_map);
59
60 void __iomem *
61 mpc52xx_find_and_map_path(const char *path)
62 {
63         return mpc52xx_map_node(of_find_node_by_path(path));
64 }
65
66 EXPORT_SYMBOL(mpc52xx_find_and_map_path);
67
68 /**
69  *      mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device
70  *      @node:  device node
71  *
72  *      Returns IPB bus frequency, or 0 if the bus frequency cannot be found.
73  */
74 unsigned int
75 mpc52xx_find_ipb_freq(struct device_node *node)
76 {
77         struct device_node *np;
78         const unsigned int *p_ipb_freq = NULL;
79
80         of_node_get(node);
81         while (node) {
82                 p_ipb_freq = of_get_property(node, "bus-frequency", NULL);
83                 if (p_ipb_freq)
84                         break;
85
86                 np = of_get_parent(node);
87                 of_node_put(node);
88                 node = np;
89         }
90         if (node)
91                 of_node_put(node);
92
93         return p_ipb_freq ? *p_ipb_freq : 0;
94 }
95 EXPORT_SYMBOL(mpc52xx_find_ipb_freq);
96
97
98 /*
99  * Configure the XLB arbiter settings to match what Linux expects.
100  */
101 void __init
102 mpc5200_setup_xlb_arbiter(void)
103 {
104         struct mpc52xx_xlb  __iomem *xlb;
105
106         xlb = mpc52xx_find_and_map("mpc5200-xlb");
107         if (!xlb) {
108                 printk(KERN_ERR __FILE__ ": "
109                         "Error mapping XLB in mpc52xx_setup_cpu().  "
110                         "Expect some abnormal behavior\n");
111                 return;
112         }
113
114         /* Configure the XLB Arbiter priorities */
115         out_be32(&xlb->master_pri_enable, 0xff);
116         out_be32(&xlb->master_priority, 0x11111111);
117
118         /* Disable XLB pipelining
119          * (cfr errate 292. We could do this only just before ATA PIO
120          *  transaction and re-enable it afterwards ...)
121          */
122         out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS);
123
124         iounmap(xlb);
125 }
126
127 void __init
128 mpc52xx_declare_of_platform_devices(void)
129 {
130         /* Find every child of the SOC node and add it to of_platform */
131         if (of_platform_bus_probe(NULL, NULL, NULL))
132                 printk(KERN_ERR __FILE__ ": "
133                         "Error while probing of_platform bus\n");
134 }
135
136 void __init
137 mpc52xx_map_wdt(void)
138 {
139         const void *has_wdt;
140         struct device_node *np;
141
142         /* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
143          * possibly from a interrupt context. wdt is only implement
144          * on a gpt0, so check has-wdt property before mapping.
145          */
146         for_each_compatible_node(np, NULL, "fsl,mpc5200-gpt") {
147                 has_wdt = of_get_property(np, "fsl,has-wdt", NULL);
148                 if (has_wdt) {
149                         mpc52xx_wdt = mpc52xx_map_node(np);
150                         return;
151                 }
152         }
153         for_each_compatible_node(np, NULL, "mpc5200-gpt") {
154                 has_wdt = of_get_property(np, "has-wdt", NULL);
155                 if (has_wdt) {
156                         mpc52xx_wdt = mpc52xx_map_node(np);
157                         return;
158                 }
159         }
160 }
161
162 void
163 mpc52xx_restart(char *cmd)
164 {
165         local_irq_disable();
166
167         /* Turn on the watchdog and wait for it to expire.
168          * It effectively does a reset. */
169         if (mpc52xx_wdt) {
170                 out_be32(&mpc52xx_wdt->mode, 0x00000000);
171                 out_be32(&mpc52xx_wdt->count, 0x000000ff);
172                 out_be32(&mpc52xx_wdt->mode, 0x00009004);
173         } else
174                 printk("mpc52xx_restart: Can't access wdt. "
175                         "Restart impossible, system halted.\n");
176
177         while (1);
178 }