aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2008-01-25 00:25:31 -0500
committerGrant Likely <grant.likely@secretlab.ca>2008-01-26 17:32:18 -0500
commitc8004a28186110657aa3e75135a6b96ebfa3e8f0 (patch)
treeac199954acf7aa7b9ead9a427eaf51362dde0c23 /arch
parent94d2dde738a50124d1f1b1b40bd5b9d0ed22e2e2 (diff)
[POWERPC] Add common clock setting routine mpc52xx_psc_set_clkdiv()
PSC drivers should not access the CDM registers directly. Instead provide a common routine for setting the PSC clock parameters with the required locking. Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/52xx/efika.c3
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c10
-rw-r--r--arch/powerpc/platforms/52xx/mpc5200_simple.c6
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c65
-rw-r--r--arch/ppc/syslib/mpc52xx_setup.c36
5 files changed, 108 insertions, 12 deletions
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c
index a0da70c8b502..a2068faef6ea 100644
--- a/arch/powerpc/platforms/52xx/efika.c
+++ b/arch/powerpc/platforms/52xx/efika.c
@@ -180,6 +180,9 @@ static void __init efika_setup_arch(void)
180{ 180{
181 rtas_initialize(); 181 rtas_initialize();
182 182
183 /* Map important registers from the internal memory map */
184 mpc52xx_map_common_devices();
185
183 efika_pcisetup(); 186 efika_pcisetup();
184 187
185#ifdef CONFIG_PM 188#ifdef CONFIG_PM
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index fb35b285a146..956f459e175c 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -152,15 +152,15 @@ static void __init lite5200_setup_arch(void)
152 if (ppc_md.progress) 152 if (ppc_md.progress)
153 ppc_md.progress("lite5200_setup_arch()", 0); 153 ppc_md.progress("lite5200_setup_arch()", 0);
154 154
155 /* Fix things that firmware should have done. */ 155 /* Map important registers from the internal memory map */
156 lite5200_fix_clock_config(); 156 mpc52xx_map_common_devices();
157 lite5200_fix_port_config();
158 157
159 /* Some mpc5200 & mpc5200b related configuration */ 158 /* Some mpc5200 & mpc5200b related configuration */
160 mpc5200_setup_xlb_arbiter(); 159 mpc5200_setup_xlb_arbiter();
161 160
162 /* Map wdt for mpc52xx_restart() */ 161 /* Fix things that firmware should have done. */
163 mpc52xx_map_wdt(); 162 lite5200_fix_clock_config();
163 lite5200_fix_port_config();
164 164
165#ifdef CONFIG_PM 165#ifdef CONFIG_PM
166 mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; 166 mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c
index 754aa932f595..c48b82bc2aad 100644
--- a/arch/powerpc/platforms/52xx/mpc5200_simple.c
+++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c
@@ -39,12 +39,12 @@ static void __init mpc5200_simple_setup_arch(void)
39 if (ppc_md.progress) 39 if (ppc_md.progress)
40 ppc_md.progress("mpc5200_simple_setup_arch()", 0); 40 ppc_md.progress("mpc5200_simple_setup_arch()", 0);
41 41
42 /* Map important registers from the internal memory map */
43 mpc52xx_map_common_devices();
44
42 /* Some mpc5200 & mpc5200b related configuration */ 45 /* Some mpc5200 & mpc5200b related configuration */
43 mpc5200_setup_xlb_arbiter(); 46 mpc5200_setup_xlb_arbiter();
44 47
45 /* Map wdt for mpc52xx_restart() */
46 mpc52xx_map_wdt();
47
48 mpc52xx_setup_pci(); 48 mpc52xx_setup_pci();
49} 49}
50 50
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index 744eb3a34ec9..9aa4425d80b2 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -13,6 +13,7 @@
13#undef DEBUG 13#undef DEBUG
14 14
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/spinlock.h>
16#include <linux/of_platform.h> 17#include <linux/of_platform.h>
17#include <asm/io.h> 18#include <asm/io.h>
18#include <asm/prom.h> 19#include <asm/prom.h>
@@ -41,7 +42,9 @@ static struct of_device_id mpc52xx_bus_ids[] __initdata = {
41 * from interrupt context while node mapping (which calls ioremap()) 42 * from interrupt context while node mapping (which calls ioremap())
42 * cannot be used at such point. 43 * cannot be used at such point.
43 */ 44 */
44static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL; 45static spinlock_t mpc52xx_lock = SPIN_LOCK_UNLOCKED;
46static struct mpc52xx_gpt __iomem *mpc52xx_wdt;
47static struct mpc52xx_cdm __iomem *mpc52xx_cdm;
45 48
46/** 49/**
47 * mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device 50 * mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device
@@ -120,18 +123,27 @@ mpc52xx_declare_of_platform_devices(void)
120} 123}
121 124
122/* 125/*
123 * match tables used by mpc52xx_map_wdt() 126 * match tables used by mpc52xx_map_common_devices()
124 */ 127 */
125static struct of_device_id mpc52xx_gpt_ids[] __initdata = { 128static struct of_device_id mpc52xx_gpt_ids[] __initdata = {
126 { .compatible = "fsl,mpc5200-gpt", }, 129 { .compatible = "fsl,mpc5200-gpt", },
127 { .compatible = "mpc5200-gpt", }, /* old */ 130 { .compatible = "mpc5200-gpt", }, /* old */
128 {} 131 {}
129}; 132};
133static struct of_device_id mpc52xx_cdm_ids[] __initdata = {
134 { .compatible = "fsl,mpc5200-cdm", },
135 { .compatible = "mpc5200-cdm", }, /* old */
136 {}
137};
130 138
139/**
140 * mpc52xx_map_common_devices: iomap devices required by common code
141 */
131void __init 142void __init
132mpc52xx_map_wdt(void) 143mpc52xx_map_common_devices(void)
133{ 144{
134 struct device_node *np; 145 struct device_node *np;
146
135 /* mpc52xx_wdt is mapped here and used in mpc52xx_restart, 147 /* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
136 * possibly from a interrupt context. wdt is only implement 148 * possibly from a interrupt context. wdt is only implement
137 * on a gpt0, so check has-wdt property before mapping. 149 * on a gpt0, so check has-wdt property before mapping.
@@ -141,11 +153,56 @@ mpc52xx_map_wdt(void)
141 of_get_property(np, "has-wdt", NULL)) { 153 of_get_property(np, "has-wdt", NULL)) {
142 mpc52xx_wdt = of_iomap(np, 0); 154 mpc52xx_wdt = of_iomap(np, 0);
143 of_node_put(np); 155 of_node_put(np);
144 return; 156 break;
145 } 157 }
146 } 158 }
159
160 /* Clock Distribution Module, used by PSC clock setting function */
161 np = of_find_matching_node(NULL, mpc52xx_cdm_ids);
162 mpc52xx_cdm = of_iomap(np, 0);
163 of_node_put(np);
147} 164}
148 165
166/**
167 * mpc52xx_set_psc_clkdiv: Set clock divider in the CDM for PSC ports
168 *
169 * @psc_id: id of psc port; must be 1,2,3 or 6
170 * @clkdiv: clock divider value to put into CDM PSC register.
171 */
172int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv)
173{
174 unsigned long flags;
175 u16 __iomem *reg;
176 u32 val;
177 u32 mask;
178 u32 mclken_div;
179
180 if (!mpc52xx_cdm)
181 return -ENODEV;
182
183 mclken_div = 0x8000 | (clkdiv & 0x1FF);
184 switch (psc_id) {
185 case 1: reg = &mpc52xx_cdm->mclken_div_psc1; mask = 0x20; break;
186 case 2: reg = &mpc52xx_cdm->mclken_div_psc2; mask = 0x40; break;
187 case 3: reg = &mpc52xx_cdm->mclken_div_psc3; mask = 0x80; break;
188 case 6: reg = &mpc52xx_cdm->mclken_div_psc6; mask = 0x10; break;
189 default:
190 return -ENODEV;
191 }
192
193 /* Set the rate and enable the clock */
194 spin_lock_irqsave(&mpc52xx_lock, flags);
195 out_be16(reg, mclken_div);
196 val = in_be32(&mpc52xx_cdm->clk_enables);
197 out_be32(&mpc52xx_cdm->clk_enables, val | mask);
198 spin_unlock_irqrestore(&mpc52xx_lock, flags);
199
200 return 0;
201}
202
203/**
204 * mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer
205 */
149void 206void
150mpc52xx_restart(char *cmd) 207mpc52xx_restart(char *cmd)
151{ 208{
diff --git a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c
index ecfa2c0f8ba3..9f504fc7693e 100644
--- a/arch/ppc/syslib/mpc52xx_setup.c
+++ b/arch/ppc/syslib/mpc52xx_setup.c
@@ -16,6 +16,7 @@
16 */ 16 */
17 17
18 18
19#include <linux/spinlock.h>
19#include <asm/io.h> 20#include <asm/io.h>
20#include <asm/time.h> 21#include <asm/time.h>
21#include <asm/mpc52xx.h> 22#include <asm/mpc52xx.h>
@@ -275,3 +276,38 @@ int mpc52xx_match_psc_function(int psc_idx, const char *func)
275 276
276 return 0; 277 return 0;
277} 278}
279
280int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv)
281{
282 static spinlock_t lock = SPIN_LOCK_UNLOCKED;
283 struct mpc52xx_cdm __iomem *cdm;
284 unsigned long flags;
285 u16 mclken_div;
286 u16 __iomem *reg;
287 u32 mask;
288
289 cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
290 if (!cdm) {
291 printk(KERN_ERR __FILE__ ": Error mapping CDM\n");
292 return -ENODEV;
293 }
294
295 mclken_div = 0x8000 | (clkdiv & 0x1FF);
296 switch (psc_id) {
297 case 1: reg = &cdm->mclken_div_psc1; mask = 0x20; break;
298 case 2: reg = &cdm->mclken_div_psc2; mask = 0x40; break;
299 case 3: reg = &cdm->mclken_div_psc3; mask = 0x80; break;
300 case 6: reg = &cdm->mclken_div_psc6; mask = 0x10; break;
301 default:
302 return -ENODEV;
303 }
304
305 /* Set the rate and enable the clock */
306 spin_lock_irqsave(&lock, flags);
307 out_be16(reg, mclken_div);
308 out_be32(&cdm->clk_enables, in_be32(&cdm->clk_enables) | mask);
309 spin_unlock_irqrestore(&lock, flags);
310
311 iounmap(cdm);
312 return 0;
313}