]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/powerpc/platforms/52xx/mpc52xx_common.c
744eb3a34ec989508d727167e17c16f7b183aeea
[linux-2.6-omap-h63xx.git] / 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 /* MPC5200 device tree match tables */
22 static struct of_device_id mpc52xx_xlb_ids[] __initdata = {
23         { .compatible = "fsl,mpc5200-xlb", },
24         { .compatible = "mpc5200-xlb", },
25         {}
26 };
27 static struct of_device_id mpc52xx_bus_ids[] __initdata = {
28         { .compatible = "fsl,mpc5200-immr", },
29         { .compatible = "fsl,mpc5200b-immr", },
30         { .compatible = "fsl,lpb", },
31
32         /* depreciated matches; shouldn't be used in new device trees */
33         { .type = "builtin", .compatible = "mpc5200", }, /* efika */
34         { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */
35         {}
36 };
37
38 /*
39  * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart().
40  * Permanent mapping is required because mpc52xx_restart() can be called
41  * from interrupt context while node mapping (which calls ioremap())
42  * cannot be used at such point.
43  */
44 static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL;
45
46 /**
47  *      mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device
48  *      @node:  device node
49  *
50  *      Returns IPB bus frequency, or 0 if the bus frequency cannot be found.
51  */
52 unsigned int
53 mpc52xx_find_ipb_freq(struct device_node *node)
54 {
55         struct device_node *np;
56         const unsigned int *p_ipb_freq = NULL;
57
58         of_node_get(node);
59         while (node) {
60                 p_ipb_freq = of_get_property(node, "bus-frequency", NULL);
61                 if (p_ipb_freq)
62                         break;
63
64                 np = of_get_parent(node);
65                 of_node_put(node);
66                 node = np;
67         }
68         if (node)
69                 of_node_put(node);
70
71         return p_ipb_freq ? *p_ipb_freq : 0;
72 }
73 EXPORT_SYMBOL(mpc52xx_find_ipb_freq);
74
75
76 /*
77  * Configure the XLB arbiter settings to match what Linux expects.
78  */
79 void __init
80 mpc5200_setup_xlb_arbiter(void)
81 {
82         struct device_node *np;
83         struct mpc52xx_xlb  __iomem *xlb;
84
85         np = of_find_matching_node(NULL, mpc52xx_xlb_ids);
86         xlb = of_iomap(np, 0);
87         of_node_put(np);
88         if (!xlb) {
89                 printk(KERN_ERR __FILE__ ": "
90                         "Error mapping XLB in mpc52xx_setup_cpu().  "
91                         "Expect some abnormal behavior\n");
92                 return;
93         }
94
95         /* Configure the XLB Arbiter priorities */
96         out_be32(&xlb->master_pri_enable, 0xff);
97         out_be32(&xlb->master_priority, 0x11111111);
98
99         /* Disable XLB pipelining
100          * (cfr errate 292. We could do this only just before ATA PIO
101          *  transaction and re-enable it afterwards ...)
102          */
103         out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS);
104
105         iounmap(xlb);
106 }
107
108 /**
109  * mpc52xx_declare_of_platform_devices: register internal devices and children
110  *                                      of the localplus bus to the of_platform
111  *                                      bus.
112  */
113 void __init
114 mpc52xx_declare_of_platform_devices(void)
115 {
116         /* Find every child of the SOC node and add it to of_platform */
117         if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL))
118                 printk(KERN_ERR __FILE__ ": "
119                         "Error while probing of_platform bus\n");
120 }
121
122 /*
123  * match tables used by mpc52xx_map_wdt()
124  */
125 static struct of_device_id mpc52xx_gpt_ids[] __initdata = {
126         { .compatible = "fsl,mpc5200-gpt", },
127         { .compatible = "mpc5200-gpt", }, /* old */
128         {}
129 };
130
131 void __init
132 mpc52xx_map_wdt(void)
133 {
134         struct device_node *np;
135         /* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
136          * possibly from a interrupt context. wdt is only implement
137          * on a gpt0, so check has-wdt property before mapping.
138          */
139         for_each_matching_node(np, mpc52xx_gpt_ids) {
140                 if (of_get_property(np, "fsl,has-wdt", NULL) ||
141                     of_get_property(np, "has-wdt", NULL)) {
142                         mpc52xx_wdt = of_iomap(np, 0);
143                         of_node_put(np);
144                         return;
145                 }
146         }
147 }
148
149 void
150 mpc52xx_restart(char *cmd)
151 {
152         local_irq_disable();
153
154         /* Turn on the watchdog and wait for it to expire.
155          * It effectively does a reset. */
156         if (mpc52xx_wdt) {
157                 out_be32(&mpc52xx_wdt->mode, 0x00000000);
158                 out_be32(&mpc52xx_wdt->count, 0x000000ff);
159                 out_be32(&mpc52xx_wdt->mode, 0x00009004);
160         } else
161                 printk("mpc52xx_restart: Can't access wdt. "
162                         "Restart impossible, system halted.\n");
163
164         while (1);
165 }