diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2008-01-25 00:25:31 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2008-01-26 17:32:18 -0500 |
commit | c8004a28186110657aa3e75135a6b96ebfa3e8f0 (patch) | |
tree | ac199954acf7aa7b9ead9a427eaf51362dde0c23 | |
parent | 94d2dde738a50124d1f1b1b40bd5b9d0ed22e2e2 (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>
-rw-r--r-- | arch/powerpc/platforms/52xx/efika.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/lite5200.c | 10 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc5200_simple.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_common.c | 65 | ||||
-rw-r--r-- | arch/ppc/syslib/mpc52xx_setup.c | 36 | ||||
-rw-r--r-- | include/asm-powerpc/mpc52xx.h | 9 |
6 files changed, 114 insertions, 15 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 | */ |
44 | static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL; | 45 | static spinlock_t mpc52xx_lock = SPIN_LOCK_UNLOCKED; |
46 | static struct mpc52xx_gpt __iomem *mpc52xx_wdt; | ||
47 | static 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 | */ |
125 | static struct of_device_id mpc52xx_gpt_ids[] __initdata = { | 128 | static 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 | }; |
133 | static 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 | */ | ||
131 | void __init | 142 | void __init |
132 | mpc52xx_map_wdt(void) | 143 | mpc52xx_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 | */ | ||
172 | int 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 | */ | ||
149 | void | 206 | void |
150 | mpc52xx_restart(char *cmd) | 207 | mpc52xx_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 | |||
280 | int 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 | } | ||
diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h index 1c48c6d16335..81ef10b6b672 100644 --- a/include/asm-powerpc/mpc52xx.h +++ b/include/asm-powerpc/mpc52xx.h | |||
@@ -248,13 +248,19 @@ struct mpc52xx_cdm { | |||
248 | 248 | ||
249 | #ifndef __ASSEMBLY__ | 249 | #ifndef __ASSEMBLY__ |
250 | 250 | ||
251 | /* mpc52xx_common.c */ | ||
251 | extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node); | 252 | extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node); |
252 | extern void mpc5200_setup_xlb_arbiter(void); | 253 | extern void mpc5200_setup_xlb_arbiter(void); |
253 | extern void mpc52xx_declare_of_platform_devices(void); | 254 | extern void mpc52xx_declare_of_platform_devices(void); |
255 | extern void mpc52xx_map_common_devices(void); | ||
256 | extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv); | ||
257 | extern void mpc52xx_restart(char *cmd); | ||
254 | 258 | ||
259 | /* mpc52xx_pic.c */ | ||
255 | extern void mpc52xx_init_irq(void); | 260 | extern void mpc52xx_init_irq(void); |
256 | extern unsigned int mpc52xx_get_irq(void); | 261 | extern unsigned int mpc52xx_get_irq(void); |
257 | 262 | ||
263 | /* mpc52xx_pci.c */ | ||
258 | #ifdef CONFIG_PCI | 264 | #ifdef CONFIG_PCI |
259 | extern int __init mpc52xx_add_bridge(struct device_node *node); | 265 | extern int __init mpc52xx_add_bridge(struct device_node *node); |
260 | extern void __init mpc52xx_setup_pci(void); | 266 | extern void __init mpc52xx_setup_pci(void); |
@@ -262,9 +268,6 @@ extern void __init mpc52xx_setup_pci(void); | |||
262 | static inline void mpc52xx_setup_pci(void) { } | 268 | static inline void mpc52xx_setup_pci(void) { } |
263 | #endif | 269 | #endif |
264 | 270 | ||
265 | extern void __init mpc52xx_map_wdt(void); | ||
266 | extern void mpc52xx_restart(char *cmd); | ||
267 | |||
268 | #endif /* __ASSEMBLY__ */ | 271 | #endif /* __ASSEMBLY__ */ |
269 | 272 | ||
270 | #ifdef CONFIG_PM | 273 | #ifdef CONFIG_PM |