diff options
Diffstat (limited to 'arch/powerpc/platforms/52xx')
-rw-r--r-- | arch/powerpc/platforms/52xx/Kconfig | 50 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/efika.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/lite5200.c | 46 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/lite5200_pm.c | 13 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc5200_simple.c | 85 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_common.c | 154 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_pci.c | 20 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_pic.c | 22 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_pm.c | 15 |
10 files changed, 307 insertions, 102 deletions
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index 2938d4927b8..515f244c90b 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig @@ -1,38 +1,48 @@ config PPC_MPC52xx - bool + bool "52xx-based boards" + depends on PPC_MULTIPLATFORM && PPC32 select FSL_SOC select PPC_CLOCK - default n - -config PPC_MPC5200 - bool - select PPC_MPC52xx - default n -config PPC_MPC5200_BUGFIX - bool "MPC5200 (L25R) bugfix support" - depends on PPC_MPC5200 - default n +config PPC_MPC5200_SIMPLE + bool "Generic support for simple MPC5200 based boards" + depends on PPC_MPC52xx + select DEFAULT_UIMAGE + select WANT_DEVICE_TREE help - Enable workarounds for original MPC5200 errata. This is not required - for MPC5200B based boards. + This option enables support for a simple MPC52xx based boards which + do not need a custom platform specific setup. Such boards are + supported assuming the following: - It is safe to say 'Y' here + - GPIO pins are configured by the firmware, + - CDM configuration (clocking) is setup correctly by firmware, + - if the 'fsl,has-wdt' property is present in one of the + gpt nodes, then it is safe to use such gpt to reset the board, + - PCI is supported if enabled in the kernel configuration + and if there is a PCI bus node defined in the device tree. + + Boards that are compatible with this generic platform support + are: 'tqc,tqm5200', 'promess,motionpro', 'schindler,cm5200'. config PPC_EFIKA bool "bPlan Efika 5k2. MPC5200B based computer" - depends on PPC_MULTIPLATFORM && PPC32 + depends on PPC_MPC52xx select PPC_RTAS select RTAS_PROC - select PPC_MPC52xx select PPC_NATIVE - default n config PPC_LITE5200 bool "Freescale Lite5200 Eval Board" - depends on PPC_MULTIPLATFORM && PPC32 + depends on PPC_MPC52xx + select DEFAULT_UIMAGE select WANT_DEVICE_TREE - select PPC_MPC5200 - default n +config PPC_MPC5200_BUGFIX + bool "MPC5200 (L25R) bugfix support" + depends on PPC_MPC52xx + help + Enable workarounds for original MPC5200 errata. This is not required + for MPC5200B based boards. + + It is safe to say 'Y' here diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index 307dbc17809..fe1b81bb522 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile @@ -6,6 +6,7 @@ obj-y += mpc52xx_pic.o mpc52xx_common.o obj-$(CONFIG_PCI) += mpc52xx_pci.o endif +obj-$(CONFIG_PPC_MPC5200_SIMPLE) += mpc5200_simple.o obj-$(CONFIG_PPC_EFIKA) += efika.o obj-$(CONFIG_PPC_LITE5200) += lite5200.o diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index a0da70c8b50..a2068faef6e 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) { rtas_initialize(); + /* Map important registers from the internal memory map */ + mpc52xx_map_common_devices(); + efika_pcisetup(); #ifdef CONFIG_PM diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 25d2bfa3d9d..956f459e175 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -32,6 +32,19 @@ * */ +/* mpc5200 device tree match tables */ +static struct of_device_id mpc5200_cdm_ids[] __initdata = { + { .compatible = "fsl,mpc5200-cdm", }, + { .compatible = "mpc5200-cdm", }, + {} +}; + +static struct of_device_id mpc5200_gpio_ids[] __initdata = { + { .compatible = "fsl,mpc5200-gpio", }, + { .compatible = "mpc5200-gpio", }, + {} +}; + /* * Fix clock configuration. * @@ -42,10 +55,12 @@ static void __init lite5200_fix_clock_config(void) { + struct device_node *np; struct mpc52xx_cdm __iomem *cdm; - /* Map zones */ - cdm = mpc52xx_find_and_map("mpc5200-cdm"); + np = of_find_matching_node(NULL, mpc5200_cdm_ids); + cdm = of_iomap(np, 0); + of_node_put(np); if (!cdm) { printk(KERN_ERR "%s() failed; expect abnormal behaviour\n", __FUNCTION__); @@ -74,10 +89,13 @@ lite5200_fix_clock_config(void) static void __init lite5200_fix_port_config(void) { + struct device_node *np; struct mpc52xx_gpio __iomem *gpio; u32 port_config; - gpio = mpc52xx_find_and_map("mpc5200-gpio"); + np = of_find_matching_node(NULL, mpc5200_gpio_ids); + gpio = of_iomap(np, 0); + of_node_put(np); if (!gpio) { printk(KERN_ERR "%s() failed. expect abnormal behavior\n", __FUNCTION__); @@ -131,22 +149,18 @@ static void lite5200_resume_finish(void __iomem *mbar) static void __init lite5200_setup_arch(void) { -#ifdef CONFIG_PCI - struct device_node *np; -#endif - 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; @@ -154,13 +168,7 @@ static void __init lite5200_setup_arch(void) lite5200_pm_init(); #endif -#ifdef CONFIG_PCI - np = of_find_node_by_type(NULL, "pci"); - if (np) { - mpc52xx_add_bridge(np); - of_node_put(np); - } -#endif + mpc52xx_setup_pci(); } /* diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index ffa14aff524..c0f13e8deb0 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -42,6 +42,15 @@ static int lite5200_pm_set_target(suspend_state_t state) static int lite5200_pm_prepare(void) { + struct device_node *np; + const struct of_device_id immr_ids[] = { + { .compatible = "fsl,mpc5200-immr", }, + { .compatible = "fsl,mpc5200b-immr", }, + { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ + { .type = "builtin", .compatible = "mpc5200", }, /* efika */ + {} + }; + /* deep sleep? let mpc52xx code handle that */ if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) return mpc52xx_pm_prepare(); @@ -50,7 +59,9 @@ static int lite5200_pm_prepare(void) return -EINVAL; /* map registers */ - mbar = mpc52xx_find_and_map("mpc5200"); + np = of_find_matching_node(NULL, immr_ids); + mbar = of_iomap(np, 0); + of_node_put(np); if (!mbar) { printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); return -ENOSYS; diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c new file mode 100644 index 00000000000..c48b82bc2aa --- /dev/null +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -0,0 +1,85 @@ +/* + * Support for 'mpc5200-simple-platform' compatible boards. + * + * Written by Marian Balakowicz <m8@semihalf.com> + * Copyright (C) 2007 Semihalf + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Description: + * This code implements support for a simple MPC52xx based boards which + * do not need a custom platform specific setup. Such boards are + * supported assuming the following: + * + * - GPIO pins are configured by the firmware, + * - CDM configuration (clocking) is setup correctly by firmware, + * - if the 'fsl,has-wdt' property is present in one of the + * gpt nodes, then it is safe to use such gpt to reset the board, + * - PCI is supported if enabled in the kernel configuration + * and if there is a PCI bus node defined in the device tree. + * + * Boards that are compatible with this generic platform support + * are listed in a 'board' table. + */ + +#undef DEBUG +#include <asm/time.h> +#include <asm/prom.h> +#include <asm/machdep.h> +#include <asm/mpc52xx.h> + +/* + * Setup the architecture + */ +static void __init mpc5200_simple_setup_arch(void) +{ + if (ppc_md.progress) + 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 */ + mpc5200_setup_xlb_arbiter(); + + mpc52xx_setup_pci(); +} + +/* list of the supported boards */ +static char *board[] __initdata = { + "promess,motionpro", + "schindler,cm5200", + "tqc,tqm5200", + NULL +}; + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc5200_simple_probe(void) +{ + unsigned long node = of_get_flat_dt_root(); + int i = 0; + + while (board[i]) { + if (of_flat_dt_is_compatible(node, board[i])) + break; + i++; + } + + return (board[i] != NULL); +} + +define_machine(mpc5200_simple_platform) { + .name = "mpc5200-simple-platform", + .probe = mpc5200_simple_probe, + .setup_arch = mpc5200_simple_setup_arch, + .init = mpc52xx_declare_of_platform_devices, + .init_IRQ = mpc52xx_init_irq, + .get_irq = mpc52xx_get_irq, + .restart = mpc52xx_restart, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 9850685c542..9aa4425d80b 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -13,57 +13,38 @@ #undef DEBUG #include <linux/kernel.h> +#include <linux/spinlock.h> #include <linux/of_platform.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/mpc52xx.h> +/* MPC5200 device tree match tables */ +static struct of_device_id mpc52xx_xlb_ids[] __initdata = { + { .compatible = "fsl,mpc5200-xlb", }, + { .compatible = "mpc5200-xlb", }, + {} +}; +static struct of_device_id mpc52xx_bus_ids[] __initdata = { + { .compatible = "fsl,mpc5200-immr", }, + { .compatible = "fsl,mpc5200b-immr", }, + { .compatible = "fsl,lpb", }, + + /* depreciated matches; shouldn't be used in new device trees */ + { .type = "builtin", .compatible = "mpc5200", }, /* efika */ + { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ + {} +}; + /* * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart(). * Permanent mapping is required because mpc52xx_restart() can be called * from interrupt context while node mapping (which calls ioremap()) * cannot be used at such point. */ -static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL; - -static void __iomem * -mpc52xx_map_node(struct device_node *ofn) -{ - const u32 *regaddr_p; - u64 regaddr64, size64; - - if (!ofn) - return NULL; - - regaddr_p = of_get_address(ofn, 0, &size64, NULL); - if (!regaddr_p) { - of_node_put(ofn); - return NULL; - } - - regaddr64 = of_translate_address(ofn, regaddr_p); - - of_node_put(ofn); - - return ioremap((u32)regaddr64, (u32)size64); -} - -void __iomem * -mpc52xx_find_and_map(const char *compatible) -{ - return mpc52xx_map_node( - of_find_compatible_node(NULL, NULL, compatible)); -} - -EXPORT_SYMBOL(mpc52xx_find_and_map); - -void __iomem * -mpc52xx_find_and_map_path(const char *path) -{ - return mpc52xx_map_node(of_find_node_by_path(path)); -} - -EXPORT_SYMBOL(mpc52xx_find_and_map_path); +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 @@ -101,9 +82,12 @@ EXPORT_SYMBOL(mpc52xx_find_ipb_freq); void __init mpc5200_setup_xlb_arbiter(void) { + struct device_node *np; struct mpc52xx_xlb __iomem *xlb; - xlb = mpc52xx_find_and_map("mpc5200-xlb"); + np = of_find_matching_node(NULL, mpc52xx_xlb_ids); + xlb = of_iomap(np, 0); + of_node_put(np); if (!xlb) { printk(KERN_ERR __FILE__ ": " "Error mapping XLB in mpc52xx_setup_cpu(). " @@ -124,41 +108,101 @@ mpc5200_setup_xlb_arbiter(void) iounmap(xlb); } +/** + * mpc52xx_declare_of_platform_devices: register internal devices and children + * of the localplus bus to the of_platform + * bus. + */ void __init mpc52xx_declare_of_platform_devices(void) { /* Find every child of the SOC node and add it to of_platform */ - if (of_platform_bus_probe(NULL, NULL, NULL)) + if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL)) printk(KERN_ERR __FILE__ ": " "Error while probing of_platform bus\n"); } +/* + * 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) { - const void *has_wdt; 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. */ - for_each_compatible_node(np, NULL, "fsl,mpc5200-gpt") { - has_wdt = of_get_property(np, "fsl,has-wdt", NULL); - if (has_wdt) { - mpc52xx_wdt = mpc52xx_map_node(np); - return; + for_each_matching_node(np, mpc52xx_gpt_ids) { + if (of_get_property(np, "fsl,has-wdt", NULL) || + of_get_property(np, "has-wdt", NULL)) { + mpc52xx_wdt = of_iomap(np, 0); + of_node_put(np); + break; } } - for_each_compatible_node(np, NULL, "mpc5200-gpt") { - has_wdt = of_get_property(np, "has-wdt", NULL); - if (has_wdt) { - mpc52xx_wdt = mpc52xx_map_node(np); - return; - } + + /* 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) { diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 4c6c82a684b..e3428ddd904 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c @@ -99,6 +99,12 @@ struct mpc52xx_pci { u8 reserved6[4]; /* PCI + 0xFC */ }; +/* MPC5200 device tree match tables */ +const struct of_device_id mpc52xx_pci_ids[] __initdata = { + { .type = "pci", .compatible = "fsl,mpc5200-pci", }, + { .type = "pci", .compatible = "mpc5200-pci", }, + {} +}; /* ======================================================================== */ /* PCI configuration acess */ @@ -363,7 +369,7 @@ mpc52xx_add_bridge(struct device_node *node) pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); - pci_assign_all_buses = 1; + ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; if (of_address_to_resource(node, 0, &rsrc) != 0) { printk(KERN_ERR "Can't get %s resources\n", node->full_name); @@ -406,3 +412,15 @@ mpc52xx_add_bridge(struct device_node *node) return 0; } + +void __init mpc52xx_setup_pci(void) +{ + struct device_node *pci; + + pci = of_find_matching_node(NULL, mpc52xx_pci_ids); + if (!pci) + return; + + mpc52xx_add_bridge(pci); + of_node_put(pci); +} diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 61100f270c6..d0dead8b9a9 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -29,6 +29,18 @@ * */ +/* MPC5200 device tree match tables */ +static struct of_device_id mpc52xx_pic_ids[] __initdata = { + { .compatible = "fsl,mpc5200-pic", }, + { .compatible = "mpc5200-pic", }, + {} +}; +static struct of_device_id mpc52xx_sdma_ids[] __initdata = { + { .compatible = "fsl,mpc5200-bestcomm", }, + { .compatible = "mpc5200-bestcomm", }, + {} +}; + static struct mpc52xx_intr __iomem *intr; static struct mpc52xx_sdma __iomem *sdma; static struct irq_host *mpc52xx_irqhost = NULL; @@ -364,16 +376,18 @@ void __init mpc52xx_init_irq(void) { u32 intr_ctrl; struct device_node *picnode; + struct device_node *np; /* Remap the necessary zones */ - picnode = of_find_compatible_node(NULL, NULL, "mpc5200-pic"); - - intr = mpc52xx_find_and_map("mpc5200-pic"); + picnode = of_find_matching_node(NULL, mpc52xx_pic_ids); + intr = of_iomap(picnode, 0); if (!intr) panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. " "Check node !"); - sdma = mpc52xx_find_and_map("mpc5200-bestcomm"); + np = of_find_matching_node(NULL, mpc52xx_sdma_ids); + sdma = of_iomap(np, 0); + of_node_put(np); if (!sdma) panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " "Check node !"); diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index 7ffa7babf25..c72d3304387 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c @@ -59,10 +59,21 @@ int mpc52xx_set_wakeup_gpio(u8 pin, u8 level) int mpc52xx_pm_prepare(void) { + struct device_node *np; + const struct of_device_id immr_ids[] = { + { .compatible = "fsl,mpc5200-immr", }, + { .compatible = "fsl,mpc5200b-immr", }, + { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ + { .type = "builtin", .compatible = "mpc5200", }, /* efika */ + {} + }; + /* map the whole register space */ - mbar = mpc52xx_find_and_map("mpc5200"); + np = of_find_matching_node(NULL, immr_ids); + mbar = of_iomap(np, 0); + of_node_put(np); if (!mbar) { - printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); + pr_err("mpc52xx_pm_prepare(): could not map registers\n"); return -ENOSYS; } /* these offsets are from mpc5200 users manual */ |