Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
[pandora-kernel.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/spinlock.h>
17 #include <linux/of_platform.h>
18 #include <asm/io.h>
19 #include <asm/prom.h>
20 #include <asm/mpc52xx.h>
21
22 /* MPC5200 device tree match tables */
23 static struct of_device_id mpc52xx_xlb_ids[] __initdata = {
24         { .compatible = "fsl,mpc5200-xlb", },
25         { .compatible = "mpc5200-xlb", },
26         {}
27 };
28 static struct of_device_id mpc52xx_bus_ids[] __initdata = {
29         { .compatible = "fsl,mpc5200-immr", },
30         { .compatible = "fsl,mpc5200b-immr", },
31         { .compatible = "simple-bus", },
32
33         /* depreciated matches; shouldn't be used in new device trees */
34         { .compatible = "fsl,lpb", },
35         { .type = "builtin", .compatible = "mpc5200", }, /* efika */
36         { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */
37         {}
38 };
39
40 /*
41  * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart().
42  * Permanent mapping is required because mpc52xx_restart() can be called
43  * from interrupt context while node mapping (which calls ioremap())
44  * cannot be used at such point.
45  */
46 static DEFINE_SPINLOCK(mpc52xx_lock);
47 static struct mpc52xx_gpt __iomem *mpc52xx_wdt;
48 static struct mpc52xx_cdm __iomem *mpc52xx_cdm;
49
50 /*
51  * Configure the XLB arbiter settings to match what Linux expects.
52  */
53 void __init
54 mpc5200_setup_xlb_arbiter(void)
55 {
56         struct device_node *np;
57         struct mpc52xx_xlb  __iomem *xlb;
58
59         np = of_find_matching_node(NULL, mpc52xx_xlb_ids);
60         xlb = of_iomap(np, 0);
61         of_node_put(np);
62         if (!xlb) {
63                 printk(KERN_ERR __FILE__ ": "
64                         "Error mapping XLB in mpc52xx_setup_cpu(). "
65                         "Expect some abnormal behavior\n");
66                 return;
67         }
68
69         /* Configure the XLB Arbiter priorities */
70         out_be32(&xlb->master_pri_enable, 0xff);
71         out_be32(&xlb->master_priority, 0x11111111);
72
73         /*
74          * Disable XLB pipelining
75          * (cfr errate 292. We could do this only just before ATA PIO
76          *  transaction and re-enable it afterwards ...)
77          * Not needed on MPC5200B.
78          */
79         if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)
80                 out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS);
81
82         iounmap(xlb);
83 }
84
85 /**
86  * mpc52xx_declare_of_platform_devices: register internal devices and children
87  *                                      of the localplus bus to the of_platform
88  *                                      bus.
89  */
90 void __init
91 mpc52xx_declare_of_platform_devices(void)
92 {
93         /* Find every child of the SOC node and add it to of_platform */
94         if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL))
95                 printk(KERN_ERR __FILE__ ": "
96                         "Error while probing of_platform bus\n");
97 }
98
99 /*
100  * match tables used by mpc52xx_map_common_devices()
101  */
102 static struct of_device_id mpc52xx_gpt_ids[] __initdata = {
103         { .compatible = "fsl,mpc5200-gpt", },
104         { .compatible = "mpc5200-gpt", }, /* old */
105         {}
106 };
107 static struct of_device_id mpc52xx_cdm_ids[] __initdata = {
108         { .compatible = "fsl,mpc5200-cdm", },
109         { .compatible = "mpc5200-cdm", }, /* old */
110         {}
111 };
112
113 /**
114  * mpc52xx_map_common_devices: iomap devices required by common code
115  */
116 void __init
117 mpc52xx_map_common_devices(void)
118 {
119         struct device_node *np;
120
121         /* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
122          * possibly from a interrupt context. wdt is only implement
123          * on a gpt0, so check has-wdt property before mapping.
124          */
125         for_each_matching_node(np, mpc52xx_gpt_ids) {
126                 if (of_get_property(np, "fsl,has-wdt", NULL) ||
127                     of_get_property(np, "has-wdt", NULL)) {
128                         mpc52xx_wdt = of_iomap(np, 0);
129                         of_node_put(np);
130                         break;
131                 }
132         }
133
134         /* Clock Distribution Module, used by PSC clock setting function */
135         np = of_find_matching_node(NULL, mpc52xx_cdm_ids);
136         mpc52xx_cdm = of_iomap(np, 0);
137         of_node_put(np);
138 }
139
140 /**
141  * mpc52xx_set_psc_clkdiv: Set clock divider in the CDM for PSC ports
142  *
143  * @psc_id: id of psc port; must be 1,2,3 or 6
144  * @clkdiv: clock divider value to put into CDM PSC register.
145  */
146 int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv)
147 {
148         unsigned long flags;
149         u16 __iomem *reg;
150         u32 val;
151         u32 mask;
152         u32 mclken_div;
153
154         if (!mpc52xx_cdm)
155                 return -ENODEV;
156
157         mclken_div = 0x8000 | (clkdiv & 0x1FF);
158         switch (psc_id) {
159         case 1: reg = &mpc52xx_cdm->mclken_div_psc1; mask = 0x20; break;
160         case 2: reg = &mpc52xx_cdm->mclken_div_psc2; mask = 0x40; break;
161         case 3: reg = &mpc52xx_cdm->mclken_div_psc3; mask = 0x80; break;
162         case 6: reg = &mpc52xx_cdm->mclken_div_psc6; mask = 0x10; break;
163         default:
164                 return -ENODEV;
165         }
166
167         /* Set the rate and enable the clock */
168         spin_lock_irqsave(&mpc52xx_lock, flags);
169         out_be16(reg, mclken_div);
170         val = in_be32(&mpc52xx_cdm->clk_enables);
171         out_be32(&mpc52xx_cdm->clk_enables, val | mask);
172         spin_unlock_irqrestore(&mpc52xx_lock, flags);
173
174         return 0;
175 }
176 EXPORT_SYMBOL(mpc52xx_set_psc_clkdiv);
177
178 /**
179  * mpc52xx_get_xtal_freq - Get SYS_XTAL_IN frequency for a device
180  *
181  * @node: device node
182  *
183  * Returns the frequency of the external oscillator clock connected
184  * to the SYS_XTAL_IN pin, or 0 if it cannot be determined.
185  */
186 unsigned int mpc52xx_get_xtal_freq(struct device_node *node)
187 {
188         u32 val;
189         unsigned int freq;
190
191         if (!mpc52xx_cdm)
192                 return 0;
193
194         freq = mpc5xxx_get_bus_frequency(node);
195         if (!freq)
196                 return 0;
197
198         if (in_8(&mpc52xx_cdm->ipb_clk_sel) & 0x1)
199                 freq *= 2;
200
201         val  = in_be32(&mpc52xx_cdm->rstcfg);
202         if (val & (1 << 5))
203                 freq *= 8;
204         else
205                 freq *= 4;
206         if (val & (1 << 6))
207                 freq /= 12;
208         else
209                 freq /= 16;
210
211         return freq;
212 }
213 EXPORT_SYMBOL(mpc52xx_get_xtal_freq);
214
215 /**
216  * mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer
217  */
218 void
219 mpc52xx_restart(char *cmd)
220 {
221         local_irq_disable();
222
223         /* Turn on the watchdog and wait for it to expire.
224          * It effectively does a reset. */
225         if (mpc52xx_wdt) {
226                 out_be32(&mpc52xx_wdt->mode, 0x00000000);
227                 out_be32(&mpc52xx_wdt->count, 0x000000ff);
228                 out_be32(&mpc52xx_wdt->mode, 0x00009004);
229         } else
230                 printk(KERN_ERR __FILE__ ": "
231                         "mpc52xx_restart: Can't access wdt. "
232                         "Restart impossible, system halted.\n");
233
234         while (1);
235 }