if (ppc_md.progress)
ppc_md.progress("lite5200_setup_arch()", 0);
- /* Fix things that firmware should have done. */
- lite5200_fix_clock_config();
- lite5200_fix_port_config();
+ /* Map important registers from the internal memory map */
+ mpc52xx_map_common_devices();
/* Some mpc5200 & mpc5200b related configuration */
mpc5200_setup_xlb_arbiter();
- /* Map wdt for mpc52xx_restart() */
- mpc52xx_map_wdt();
+ /* Fix things that firmware should have done. */
+ lite5200_fix_clock_config();
+ lite5200_fix_port_config();
#ifdef CONFIG_PM
mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
#undef DEBUG
#include <linux/kernel.h>
+#include <linux/spinlock.h>
#include <linux/of_platform.h>
#include <asm/io.h>
#include <asm/prom.h>
* from interrupt context while node mapping (which calls ioremap())
* 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
}
/*
- * match tables used by mpc52xx_map_wdt()
+ * match tables used by mpc52xx_map_common_devices()
*/
static struct of_device_id mpc52xx_gpt_ids[] __initdata = {
{ .compatible = "fsl,mpc5200-gpt", },
{ .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
-mpc52xx_map_wdt(void)
+mpc52xx_map_common_devices(void)
{
struct device_node *np;
+
/* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
* possibly from a interrupt context. wdt is only implement
* on a gpt0, so check has-wdt property before mapping.
of_get_property(np, "has-wdt", NULL)) {
mpc52xx_wdt = of_iomap(np, 0);
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
mpc52xx_restart(char *cmd)
{
*/
+#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/time.h>
#include <asm/mpc52xx.h>
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;
+}
#ifndef __ASSEMBLY__
+/* mpc52xx_common.c */
extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node);
extern void mpc5200_setup_xlb_arbiter(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 unsigned int mpc52xx_get_irq(void);
+/* mpc52xx_pci.c */
#ifdef CONFIG_PCI
extern int __init mpc52xx_add_bridge(struct device_node *node);
extern void __init mpc52xx_setup_pci(void);
static inline void mpc52xx_setup_pci(void) { }
#endif
-extern void __init mpc52xx_map_wdt(void);
-extern void mpc52xx_restart(char *cmd);
-
#endif /* __ASSEMBLY__ */
#ifdef CONFIG_PM