[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>
This commit is contained in:
parent
94d2dde738
commit
c8004a2818
|
@ -180,6 +180,9 @@ static void __init efika_setup_arch(void)
|
||||||
{
|
{
|
||||||
rtas_initialize();
|
rtas_initialize();
|
||||||
|
|
||||||
|
/* Map important registers from the internal memory map */
|
||||||
|
mpc52xx_map_common_devices();
|
||||||
|
|
||||||
efika_pcisetup();
|
efika_pcisetup();
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
|
@ -152,15 +152,15 @@ static void __init lite5200_setup_arch(void)
|
||||||
if (ppc_md.progress)
|
if (ppc_md.progress)
|
||||||
ppc_md.progress("lite5200_setup_arch()", 0);
|
ppc_md.progress("lite5200_setup_arch()", 0);
|
||||||
|
|
||||||
/* Fix things that firmware should have done. */
|
/* Map important registers from the internal memory map */
|
||||||
lite5200_fix_clock_config();
|
mpc52xx_map_common_devices();
|
||||||
lite5200_fix_port_config();
|
|
||||||
|
|
||||||
/* Some mpc5200 & mpc5200b related configuration */
|
/* Some mpc5200 & mpc5200b related configuration */
|
||||||
mpc5200_setup_xlb_arbiter();
|
mpc5200_setup_xlb_arbiter();
|
||||||
|
|
||||||
/* Map wdt for mpc52xx_restart() */
|
/* Fix things that firmware should have done. */
|
||||||
mpc52xx_map_wdt();
|
lite5200_fix_clock_config();
|
||||||
|
lite5200_fix_port_config();
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
|
mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
|
||||||
|
|
|
@ -39,12 +39,12 @@ static void __init mpc5200_simple_setup_arch(void)
|
||||||
if (ppc_md.progress)
|
if (ppc_md.progress)
|
||||||
ppc_md.progress("mpc5200_simple_setup_arch()", 0);
|
ppc_md.progress("mpc5200_simple_setup_arch()", 0);
|
||||||
|
|
||||||
|
/* Map important registers from the internal memory map */
|
||||||
|
mpc52xx_map_common_devices();
|
||||||
|
|
||||||
/* Some mpc5200 & mpc5200b related configuration */
|
/* Some mpc5200 & mpc5200b related configuration */
|
||||||
mpc5200_setup_xlb_arbiter();
|
mpc5200_setup_xlb_arbiter();
|
||||||
|
|
||||||
/* Map wdt for mpc52xx_restart() */
|
|
||||||
mpc52xx_map_wdt();
|
|
||||||
|
|
||||||
mpc52xx_setup_pci();
|
mpc52xx_setup_pci();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
|
@ -41,7 +42,9 @@ static struct of_device_id mpc52xx_bus_ids[] __initdata = {
|
||||||
* from interrupt context while node mapping (which calls ioremap())
|
* from interrupt context while node mapping (which calls ioremap())
|
||||||
* cannot be used at such point.
|
* cannot be used at such point.
|
||||||
*/
|
*/
|
||||||
static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL;
|
static spinlock_t mpc52xx_lock = SPIN_LOCK_UNLOCKED;
|
||||||
|
static struct mpc52xx_gpt __iomem *mpc52xx_wdt;
|
||||||
|
static struct mpc52xx_cdm __iomem *mpc52xx_cdm;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device
|
* mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device
|
||||||
|
@ -120,18 +123,27 @@ mpc52xx_declare_of_platform_devices(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* match tables used by mpc52xx_map_wdt()
|
* match tables used by mpc52xx_map_common_devices()
|
||||||
*/
|
*/
|
||||||
static struct of_device_id mpc52xx_gpt_ids[] __initdata = {
|
static struct of_device_id mpc52xx_gpt_ids[] __initdata = {
|
||||||
{ .compatible = "fsl,mpc5200-gpt", },
|
{ .compatible = "fsl,mpc5200-gpt", },
|
||||||
{ .compatible = "mpc5200-gpt", }, /* old */
|
{ .compatible = "mpc5200-gpt", }, /* old */
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
static struct of_device_id mpc52xx_cdm_ids[] __initdata = {
|
||||||
|
{ .compatible = "fsl,mpc5200-cdm", },
|
||||||
|
{ .compatible = "mpc5200-cdm", }, /* old */
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpc52xx_map_common_devices: iomap devices required by common code
|
||||||
|
*/
|
||||||
void __init
|
void __init
|
||||||
mpc52xx_map_wdt(void)
|
mpc52xx_map_common_devices(void)
|
||||||
{
|
{
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
|
|
||||||
/* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
|
/* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
|
||||||
* possibly from a interrupt context. wdt is only implement
|
* possibly from a interrupt context. wdt is only implement
|
||||||
* on a gpt0, so check has-wdt property before mapping.
|
* on a gpt0, so check has-wdt property before mapping.
|
||||||
|
@ -141,11 +153,56 @@ mpc52xx_map_wdt(void)
|
||||||
of_get_property(np, "has-wdt", NULL)) {
|
of_get_property(np, "has-wdt", NULL)) {
|
||||||
mpc52xx_wdt = of_iomap(np, 0);
|
mpc52xx_wdt = of_iomap(np, 0);
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clock Distribution Module, used by PSC clock setting function */
|
||||||
|
np = of_find_matching_node(NULL, mpc52xx_cdm_ids);
|
||||||
|
mpc52xx_cdm = of_iomap(np, 0);
|
||||||
|
of_node_put(np);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpc52xx_set_psc_clkdiv: Set clock divider in the CDM for PSC ports
|
||||||
|
*
|
||||||
|
* @psc_id: id of psc port; must be 1,2,3 or 6
|
||||||
|
* @clkdiv: clock divider value to put into CDM PSC register.
|
||||||
|
*/
|
||||||
|
int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
u16 __iomem *reg;
|
||||||
|
u32 val;
|
||||||
|
u32 mask;
|
||||||
|
u32 mclken_div;
|
||||||
|
|
||||||
|
if (!mpc52xx_cdm)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
mclken_div = 0x8000 | (clkdiv & 0x1FF);
|
||||||
|
switch (psc_id) {
|
||||||
|
case 1: reg = &mpc52xx_cdm->mclken_div_psc1; mask = 0x20; break;
|
||||||
|
case 2: reg = &mpc52xx_cdm->mclken_div_psc2; mask = 0x40; break;
|
||||||
|
case 3: reg = &mpc52xx_cdm->mclken_div_psc3; mask = 0x80; break;
|
||||||
|
case 6: reg = &mpc52xx_cdm->mclken_div_psc6; mask = 0x10; break;
|
||||||
|
default:
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the rate and enable the clock */
|
||||||
|
spin_lock_irqsave(&mpc52xx_lock, flags);
|
||||||
|
out_be16(reg, mclken_div);
|
||||||
|
val = in_be32(&mpc52xx_cdm->clk_enables);
|
||||||
|
out_be32(&mpc52xx_cdm->clk_enables, val | mask);
|
||||||
|
spin_unlock_irqrestore(&mpc52xx_lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
mpc52xx_restart(char *cmd)
|
mpc52xx_restart(char *cmd)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <linux/spinlock.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/time.h>
|
#include <asm/time.h>
|
||||||
#include <asm/mpc52xx.h>
|
#include <asm/mpc52xx.h>
|
||||||
|
@ -275,3 +276,38 @@ int mpc52xx_match_psc_function(int psc_idx, const char *func)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv)
|
||||||
|
{
|
||||||
|
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
|
||||||
|
struct mpc52xx_cdm __iomem *cdm;
|
||||||
|
unsigned long flags;
|
||||||
|
u16 mclken_div;
|
||||||
|
u16 __iomem *reg;
|
||||||
|
u32 mask;
|
||||||
|
|
||||||
|
cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
|
||||||
|
if (!cdm) {
|
||||||
|
printk(KERN_ERR __FILE__ ": Error mapping CDM\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
mclken_div = 0x8000 | (clkdiv & 0x1FF);
|
||||||
|
switch (psc_id) {
|
||||||
|
case 1: reg = &cdm->mclken_div_psc1; mask = 0x20; break;
|
||||||
|
case 2: reg = &cdm->mclken_div_psc2; mask = 0x40; break;
|
||||||
|
case 3: reg = &cdm->mclken_div_psc3; mask = 0x80; break;
|
||||||
|
case 6: reg = &cdm->mclken_div_psc6; mask = 0x10; break;
|
||||||
|
default:
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the rate and enable the clock */
|
||||||
|
spin_lock_irqsave(&lock, flags);
|
||||||
|
out_be16(reg, mclken_div);
|
||||||
|
out_be32(&cdm->clk_enables, in_be32(&cdm->clk_enables) | mask);
|
||||||
|
spin_unlock_irqrestore(&lock, flags);
|
||||||
|
|
||||||
|
iounmap(cdm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -248,13 +248,19 @@ struct mpc52xx_cdm {
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
/* mpc52xx_common.c */
|
||||||
extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node);
|
extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node);
|
||||||
extern void mpc5200_setup_xlb_arbiter(void);
|
extern void mpc5200_setup_xlb_arbiter(void);
|
||||||
extern void mpc52xx_declare_of_platform_devices(void);
|
extern void mpc52xx_declare_of_platform_devices(void);
|
||||||
|
extern void mpc52xx_map_common_devices(void);
|
||||||
|
extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv);
|
||||||
|
extern void mpc52xx_restart(char *cmd);
|
||||||
|
|
||||||
|
/* mpc52xx_pic.c */
|
||||||
extern void mpc52xx_init_irq(void);
|
extern void mpc52xx_init_irq(void);
|
||||||
extern unsigned int mpc52xx_get_irq(void);
|
extern unsigned int mpc52xx_get_irq(void);
|
||||||
|
|
||||||
|
/* mpc52xx_pci.c */
|
||||||
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
||||||
extern int __init mpc52xx_add_bridge(struct device_node *node);
|
extern int __init mpc52xx_add_bridge(struct device_node *node);
|
||||||
extern void __init mpc52xx_setup_pci(void);
|
extern void __init mpc52xx_setup_pci(void);
|
||||||
|
@ -262,9 +268,6 @@ extern void __init mpc52xx_setup_pci(void);
|
||||||
static inline void mpc52xx_setup_pci(void) { }
|
static inline void mpc52xx_setup_pci(void) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void __init mpc52xx_map_wdt(void);
|
|
||||||
extern void mpc52xx_restart(char *cmd);
|
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
Loading…
Reference in a new issue